diff --git a/0010-re-write-.gitignore.patch b/0010-re-write-.gitignore.patch index 3e0b46c..b6fa0be 100644 --- a/0010-re-write-.gitignore.patch +++ b/0010-re-write-.gitignore.patch @@ -4,14 +4,14 @@ Date: Mon, 8 Jul 2019 12:55:29 +0200 Subject: [PATCH] re-write .gitignore --- - .gitignore | 152 ++++++++++++++++++++++++++++++++++++++ + .gitignore | 150 ++++++++++++++++++++++++++++++++++++++ docs/.gitignore | 5 ++ grub-core/.gitignore | 16 ++++ grub-core/lib/.gitignore | 1 + include/grub/gcrypt/.gitignore | 2 + po/.gitignore | 5 ++ util/bash-completion.d/.gitignore | 2 + - 7 files changed, 183 insertions(+) + 7 files changed, 181 insertions(+) create mode 100644 docs/.gitignore create mode 100644 grub-core/.gitignore create mode 100644 grub-core/lib/.gitignore @@ -20,10 +20,10 @@ Subject: [PATCH] re-write .gitignore create mode 100644 util/bash-completion.d/.gitignore diff --git a/.gitignore b/.gitignore -index f6a1bd0517..594d0134d3 100644 +index f6a1bd0517..208d1d2325 100644 --- a/.gitignore +++ b/.gitignore -@@ -275,3 +275,155 @@ widthspec.bin +@@ -275,3 +275,153 @@ widthspec.bin /xfs_test /xzcompress_test /zfs_test @@ -152,8 +152,6 @@ index f6a1bd0517..594d0134d3 100644 +/grub*-reboot.8 +/grub*-render-label +/grub*-render-label.1 -+/grub*-rpm-sort -+/grub*-rpm-sort.8 +/grub*-script-check +/grub*-script-check.1 +/grub*-set-bootflag diff --git a/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch b/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch new file mode 100644 index 0000000..db101c0 --- /dev/null +++ b/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 28 Apr 2015 11:15:03 -0400 +Subject: [PATCH] Make grub2-mkconfig construct titles that look like the ones + we want elsewhere. + +Resolves: rhbz#1215839 + +Signed-off-by: Peter Jones +--- + util/grub.d/10_linux.in | 34 +++++++++++++++++++++++++++------- + 1 file changed, 27 insertions(+), 7 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 5f6d3c8d52..786dbabb4a 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -78,6 +78,32 @@ case x"$GRUB_FS" in + ;; + esac + ++mktitle () ++{ ++ local title_type ++ local version ++ local OS_NAME ++ local OS_VERS ++ ++ title_type=$1 && shift ++ version=$1 && shift ++ ++ OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})" ++ OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})" ++ ++ case $title_type in ++ recovery) ++ title=$(printf '%s (%s) %s (recovery mode)' \ ++ "${OS_NAME}" "${version}" "${OS_VERS}") ++ ;; ++ *) ++ title=$(printf '%s (%s) %s' \ ++ "${OS_NAME}" "${version}" "${OS_VERS}") ++ ;; ++ esac ++ echo -n ${title} ++} ++ + title_correction_code= + + linux_entry () +@@ -91,17 +117,11 @@ linux_entry () + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + if [ x$type != xsimple ] ; then +- case $type in +- recovery) +- title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;; +- *) +- title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; +- esac ++ title=$(mktitle "$type" "$version") + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" +- grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" + fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else diff --git a/0032-Use-rpm-s-sort-for-grub2-mkconfig.patch b/0032-Use-rpm-s-sort-for-grub2-mkconfig.patch deleted file mode 100644 index 9463ef8..0000000 --- a/0032-Use-rpm-s-sort-for-grub2-mkconfig.patch +++ /dev/null @@ -1,457 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robert Marshall -Date: Mon, 16 Mar 2015 14:14:19 -0400 -Subject: [PATCH] Use rpm's sort for grub2-mkconfig - -Add an option for rpm-based systems to use the rpm-sort library to sort -kernels. This avoids problems due to discrepancies between `sort -V` -and rpm. - -Signed-off-by: Robert Marshall -[pjones: fix --enable-rpm-sort configure option] -Signed-off-by: Peter Jones -[thierry.vignaud: fix build with rpm-4.16] -Signed-off-by: Thierry Vignaud -[tim: fix disabling grub-rpm-sort by ./configure] -Signed-off-by: Tim Landscheidt -[javierm: don't check for rpmvercmp in librpm] -Signed-off-by: Javier Martinez Canillas -[rharwood: commit message, migrate to h2m] -Signed-off-by: Robbie Harwood ---- - configure.ac | 36 ++++++ - Makefile.util.def | 17 +++ - util/grub-rpm-sort.c | 281 +++++++++++++++++++++++++++++++++++++++++++++ - docs/man/grub-rpm-sort.h2m | 2 + - util/grub-mkconfig_lib.in | 11 +- - 5 files changed, 346 insertions(+), 1 deletion(-) - create mode 100644 util/grub-rpm-sort.c - create mode 100644 docs/man/grub-rpm-sort.h2m - -diff --git a/configure.ac b/configure.ac -index 8331f95b64..87c8f17393 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath]) - grub_TRANSFORM([grub-mkrescue]) - grub_TRANSFORM([grub-probe]) - grub_TRANSFORM([grub-reboot]) -+grub_TRANSFORM([grub-rpm-sort]) - grub_TRANSFORM([grub-script-check]) - grub_TRANSFORM([grub-set-default]) - grub_TRANSFORM([grub-sparc64-setup]) -@@ -1837,6 +1838,35 @@ fi - - AC_SUBST([LIBDEVMAPPER]) - -+AC_ARG_ENABLE([rpm-sort], -+ [AS_HELP_STRING([--enable-rpm-sort], -+ [enable native rpm sorting of kernels in grub (default=guessed)])]) -+if test x"$enable_rpm_sort" = xno ; then -+ rpm_sort_excuse="explicitly disabled" -+else -+ enable_rpm_sort=yes -+fi -+ -+if test x"$rpm_sort_excuse" = x ; then -+ # Check for rpmlib header. -+ AC_CHECK_HEADER([rpm/rpmlib.h], [], -+ [rpm_sort_excuse="need rpm/rpmlib header"]) -+fi -+ -+if test x"$rpm_sort_excuse" = x ; then -+ # Check for rpmio library. -+ AC_CHECK_LIB([rpmio], [rpmvercmp], [], -+ [rpm_sort_excuse="rpmio missing rpmvercmp"]) -+fi -+ -+if test x"$rpm_sort_excuse" = x ; then -+ LIBRPM="-lrpmio"; -+ AC_DEFINE([HAVE_RPMIO], [1], -+ [Define to 1 if you have the rpmio library.]) -+fi -+ -+AC_SUBST([LIBRPM]) -+ - LIBGEOM= - if test x$host_kernel = xkfreebsd; then - AC_CHECK_LIB([geom], [geom_gettree], [], -@@ -2024,6 +2054,7 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes]) - AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes]) - AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes]) - AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes]) -+AM_CONDITIONAL([COND_GRUB_RPM_SORT], [test x$enable_rpm_sort = xyes]) - AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x]) - if test x$FONT_SOURCE != x ; then - HAVE_FONT_SOURCE=1 -@@ -2145,6 +2176,11 @@ echo grub-mount: Yes - else - echo grub-mount: No "($grub_mount_excuse)" - fi -+if [ x"$rpm_sort_excuse" = x ]; then -+echo grub-rpm-sort: Yes -+else -+echo grub-rpm-sort: No "($rpm_sort_excuse)" -+fi - if [ x"$starfield_excuse" = x ]; then - echo starfield theme: Yes - echo With DejaVuSans font from $DJVU_FONT_SOURCE -diff --git a/Makefile.util.def b/Makefile.util.def -index 2c9b283a23..bc10cc7972 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -703,6 +703,23 @@ program = { - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; - }; - -+program = { -+ name = grub-rpm-sort; -+ mansection = 8; -+ installdir = sbin; -+ -+ common = grub-core/kern/emu/misc.c; -+ common = grub-core/kern/emu/argp_common.c; -+ common = grub-core/osdep/init.c; -+ common = util/misc.c; -+ common = util/grub-rpm-sort.c; -+ -+ ldadd = libgrubkern.a; -+ ldadd = grub-core/lib/gnulib/libgnu.a; -+ ldadd = '$(LIBDEVMAPPER) $(LIBRPM)'; -+ condition = COND_GRUB_RPM_SORT; -+}; -+ - script = { - name = grub-mkconfig; - common = util/grub-mkconfig.in; -diff --git a/util/grub-rpm-sort.c b/util/grub-rpm-sort.c -new file mode 100644 -index 0000000000..f33bd1ed56 ---- /dev/null -+++ b/util/grub-rpm-sort.c -@@ -0,0 +1,281 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static size_t -+read_file (const char *input, char **ret) -+{ -+ FILE *in; -+ size_t s; -+ size_t sz = 2048; -+ size_t offset = 0; -+ char *text; -+ -+ if (!strcmp(input, "-")) -+ in = stdin; -+ else -+ in = grub_util_fopen(input, "r"); -+ -+ text = xmalloc (sz); -+ -+ if (!in) -+ grub_util_error (_("cannot open `%s': %s"), input, strerror (errno)); -+ -+ while ((s = fread (text + offset, 1, sz - offset, in)) != 0) -+ { -+ offset += s; -+ if (sz - offset == 0) -+ { -+ sz += 2048; -+ text = xrealloc (text, sz); -+ } -+ } -+ -+ text[offset] = '\0'; -+ *ret = text; -+ -+ if (in != stdin) -+ fclose(in); -+ -+ return offset + 1; -+} -+ -+/* returns name/version/release */ -+/* NULL string pointer returned if nothing found */ -+static void -+split_package_string (char *package_string, char **name, -+ char **version, char **release) -+{ -+ char *package_version, *package_release; -+ -+ /* Release */ -+ package_release = strrchr (package_string, '-'); -+ -+ if (package_release != NULL) -+ *package_release++ = '\0'; -+ -+ *release = package_release; -+ -+ /* Version */ -+ package_version = strrchr(package_string, '-'); -+ -+ if (package_version != NULL) -+ *package_version++ = '\0'; -+ -+ *version = package_version; -+ /* Name */ -+ *name = package_string; -+ -+ /* Bubble up non-null values from release to name */ -+ if (*name == NULL) -+ { -+ *name = (*version == NULL ? *release : *version); -+ *version = *release; -+ *release = NULL; -+ } -+ if (*version == NULL) -+ { -+ *version = *release; -+ *release = NULL; -+ } -+} -+ -+/* -+ * package name-version-release comparator for qsort -+ * expects p, q which are pointers to character strings (char *) -+ * which will not be altered in this function -+ */ -+static int -+package_version_compare (const void *p, const void *q) -+{ -+ char *local_p, *local_q; -+ char *lhs_name, *lhs_version, *lhs_release; -+ char *rhs_name, *rhs_version, *rhs_release; -+ int vercmpflag = 0; -+ -+ local_p = alloca (strlen (*(char * const *)p) + 1); -+ local_q = alloca (strlen (*(char * const *)q) + 1); -+ -+ /* make sure these allocated */ -+ assert (local_p); -+ assert (local_q); -+ -+ strcpy (local_p, *(char * const *)p); -+ strcpy (local_q, *(char * const *)q); -+ -+ split_package_string (local_p, &lhs_name, &lhs_version, &lhs_release); -+ split_package_string (local_q, &rhs_name, &rhs_version, &rhs_release); -+ -+ /* Check Name and return if unequal */ -+ vercmpflag = rpmvercmp ((lhs_name == NULL ? "" : lhs_name), -+ (rhs_name == NULL ? "" : rhs_name)); -+ if (vercmpflag != 0) -+ return vercmpflag; -+ -+ /* Check version and return if unequal */ -+ vercmpflag = rpmvercmp ((lhs_version == NULL ? "" : lhs_version), -+ (rhs_version == NULL ? "" : rhs_version)); -+ if (vercmpflag != 0) -+ return vercmpflag; -+ -+ /* Check release and return the version compare value */ -+ vercmpflag = rpmvercmp ((lhs_release == NULL ? "" : lhs_release), -+ (rhs_release == NULL ? "" : rhs_release)); -+ -+ return vercmpflag; -+} -+ -+static void -+add_input (const char *filename, char ***package_names, size_t *n_package_names) -+{ -+ char *orig_input_buffer = NULL; -+ char *input_buffer; -+ char *position_of_newline; -+ char **names = *package_names; -+ char **new_names = NULL; -+ size_t n_names = *n_package_names; -+ -+ if (!*package_names) -+ new_names = names = xmalloc (sizeof (char *) * 2); -+ -+ if (read_file (filename, &orig_input_buffer) < 2) -+ { -+ if (new_names) -+ free (new_names); -+ if (orig_input_buffer) -+ free (orig_input_buffer); -+ return; -+ } -+ -+ input_buffer = orig_input_buffer; -+ while (input_buffer && *input_buffer && -+ (position_of_newline = strchrnul (input_buffer, '\n'))) -+ { -+ size_t sz = position_of_newline - input_buffer; -+ char *new; -+ -+ if (sz == 0) -+ { -+ input_buffer = position_of_newline + 1; -+ continue; -+ } -+ -+ new = xmalloc (sz+1); -+ strncpy (new, input_buffer, sz); -+ new[sz] = '\0'; -+ -+ names = xrealloc (names, sizeof (char *) * (n_names + 1)); -+ names[n_names] = new; -+ n_names++; -+ -+ /* move buffer ahead to next line */ -+ input_buffer = position_of_newline + 1; -+ if (*position_of_newline == '\0') -+ input_buffer = NULL; -+ } -+ -+ free (orig_input_buffer); -+ -+ *package_names = names; -+ *n_package_names = n_names; -+} -+ -+static char * -+help_filter (int key, const char *text, void *input __attribute__ ((unused))) -+{ -+ return (char *)text; -+} -+ -+static struct argp_option options[] = { -+ { 0, } -+}; -+ -+struct arguments -+{ -+ size_t ninputs; -+ size_t input_max; -+ char **inputs; -+}; -+ -+static error_t -+argp_parser (int key, char *arg, struct argp_state *state) -+{ -+ struct arguments *arguments = state->input; -+ switch (key) -+ { -+ case ARGP_KEY_ARG: -+ assert (arguments->ninputs < arguments->input_max); -+ arguments->inputs[arguments->ninputs++] = xstrdup (arg); -+ break; -+ default: -+ return ARGP_ERR_UNKNOWN; -+ } -+ return 0; -+} -+ -+static struct argp argp = { -+ options, argp_parser, N_("[INPUT_FILES]"), -+ N_("Sort a list of strings in RPM version sort order."), -+ NULL, help_filter, NULL -+}; -+ -+int -+main (int argc, char *argv[]) -+{ -+ struct arguments arguments; -+ char **package_names = NULL; -+ size_t n_package_names = 0; -+ int i; -+ -+ grub_util_host_init (&argc, &argv); -+ -+ memset (&arguments, 0, sizeof (struct arguments)); -+ arguments.input_max = argc+1; -+ arguments.inputs = xmalloc ((arguments.input_max + 1) -+ * sizeof (arguments.inputs[0])); -+ memset (arguments.inputs, 0, (arguments.input_max + 1) -+ * sizeof (arguments.inputs[0])); -+ -+ /* Parse our arguments */ -+ if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) -+ grub_util_error ("%s", _("Error in parsing command line arguments\n")); -+ -+ /* If there's no inputs in argv, add one for stdin */ -+ if (!arguments.ninputs) -+ { -+ arguments.ninputs = 1; -+ arguments.inputs[0] = xmalloc (2); -+ strcpy(arguments.inputs[0], "-"); -+ } -+ -+ for (i = 0; i < arguments.ninputs; i++) -+ add_input(arguments.inputs[i], &package_names, &n_package_names); -+ -+ if (package_names == NULL || n_package_names < 1) -+ grub_util_error ("%s", _("Invalid input\n")); -+ -+ qsort (package_names, n_package_names, sizeof (char *), -+ package_version_compare); -+ -+ /* send sorted list to stdout */ -+ for (i = 0; i < n_package_names; i++) -+ { -+ fprintf (stdout, "%s\n", package_names[i]); -+ free (package_names[i]); -+ } -+ -+ free (package_names); -+ for (i = 0; i < arguments.ninputs; i++) -+ free (arguments.inputs[i]); -+ -+ free (arguments.inputs); -+ -+ return 0; -+} -diff --git a/docs/man/grub-rpm-sort.h2m b/docs/man/grub-rpm-sort.h2m -new file mode 100644 -index 0000000000..fe711ae102 ---- /dev/null -+++ b/docs/man/grub-rpm-sort.h2m -@@ -0,0 +1,2 @@ -+[NAME] -+grub-rpm-sort \- sort input according to RPM version compare -diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in -index 0f6505bf3b..42c2ea9ba5 100644 ---- a/util/grub-mkconfig_lib.in -+++ b/util/grub-mkconfig_lib.in -@@ -33,6 +33,9 @@ fi - if test "x$grub_mkrelpath" = x; then - grub_mkrelpath="${bindir}/@grub_mkrelpath@" - fi -+if test "x$grub_rpm_sort" = x; then -+ grub_rpm_sort="${sbindir}/@grub_rpm_sort@" -+fi - - if command -v gettext >/dev/null; then - : -@@ -218,6 +221,12 @@ version_sort () - esac - } - -+if [ "x$grub_rpm_sort" != x -a -x "$grub_rpm_sort" ]; then -+ kernel_sort="$grub_rpm_sort" -+else -+ kernel_sort=version_sort -+fi -+ - version_test_numeric () - { - version_test_numeric_a="$1" -@@ -234,7 +243,7 @@ version_test_numeric () - version_test_numeric_a="$version_test_numeric_b" - version_test_numeric_b="$version_test_numeric_c" - fi -- if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | version_sort | head -n 1 | grep -qx "$version_test_numeric_b" ; then -+ if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | "$kernel_sort" | head -n 1 | grep -qx "$version_test_numeric_b" ; then - return 0 - else - return 1 diff --git a/0033-Add-friendly-grub2-password-config-tool-985962.patch b/0033-Add-friendly-grub2-password-config-tool-985962.patch new file mode 100644 index 0000000..f430e96 --- /dev/null +++ b/0033-Add-friendly-grub2-password-config-tool-985962.patch @@ -0,0 +1,245 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robert Marshall +Date: Thu, 25 Jun 2015 11:13:11 -0400 +Subject: [PATCH] Add friendly grub2 password config tool (#985962) + +Provided a tool for users to reset the grub2 root user password +without having to alter the grub.cfg. The hashed password now +lives in a root-only-readable configuration file. + +Resolves: rhbz#985962 + +Signed-off-by: Robert Marshall +[pjones: fix the efidir in grub-setpassword and rename tool] +Signed-off-by: Peter Jones +[luto: fix grub-setpassword -o's output path] +Signed-off-by: Andy Lutomirski +[rharwood: migrate man page to h2m, context] +Signed-off-by: Robbie Harwood +--- + configure.ac | 1 + + Makefile.util.def | 13 +++++ + docs/man/grub-set-password.h2m | 2 + + util/grub-mkconfig.in | 2 + + util/grub-set-password.in | 128 +++++++++++++++++++++++++++++++++++++++++ + util/grub.d/01_users.in | 11 ++++ + 6 files changed, 157 insertions(+) + create mode 100644 docs/man/grub-set-password.h2m + create mode 100644 util/grub-set-password.in + create mode 100644 util/grub.d/01_users.in + +diff --git a/configure.ac b/configure.ac +index 8331f95b64..7f59ad788f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath]) + grub_TRANSFORM([grub-mkrescue]) + grub_TRANSFORM([grub-probe]) + grub_TRANSFORM([grub-reboot]) ++grub_TRANSFORM([grub-set-password]) + grub_TRANSFORM([grub-script-check]) + grub_TRANSFORM([grub-set-default]) + grub_TRANSFORM([grub-sparc64-setup]) +diff --git a/Makefile.util.def b/Makefile.util.def +index 2c9b283a23..4ee22c5daa 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -452,6 +452,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '01_users'; ++ common = util/grub.d/01_users.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '10_windows'; + common = util/grub.d/10_windows.in; +@@ -724,6 +730,13 @@ script = { + installdir = sbin; + }; + ++script = { ++ name = grub-set-password; ++ common = util/grub-set-password.in; ++ mansection = 8; ++ installdir = sbin; ++}; ++ + script = { + name = grub-mkconfig_lib; + common = util/grub-mkconfig_lib.in; +diff --git a/docs/man/grub-set-password.h2m b/docs/man/grub-set-password.h2m +new file mode 100644 +index 0000000000..10ee82f4d5 +--- /dev/null ++++ b/docs/man/grub-set-password.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-set-password \- generate the user.cfg file containing the hashed grub bootloader password +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 8ea2315ebc..ba14cf6261 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -276,6 +276,8 @@ for i in "${grub_mkconfig_dir}"/* ; do + *~) ;; + # emacsen autosave files. FIXME: support other editors + */\#*\#) ;; ++ # rpm config files of yore. ++ *.rpmsave|*.rpmnew|*.rpmorig) ;; + *) + if grub_file_is_not_garbage "$i" && test -x "$i" ; then + echo +diff --git a/util/grub-set-password.in b/util/grub-set-password.in +new file mode 100644 +index 0000000000..5ebf50576d +--- /dev/null ++++ b/util/grub-set-password.in +@@ -0,0 +1,128 @@ ++#!/bin/sh -e ++ ++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/') ++if [ -d /sys/firmware/efi/efivars/ ]; then ++ grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` ++else ++ grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` ++fi ++ ++PACKAGE_VERSION="@PACKAGE_VERSION@" ++PACKAGE_NAME="@PACKAGE_NAME@" ++self=`basename $0` ++bindir="@bindir@" ++grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ cat < put user.cfg in a user-selected directory ++ ++Report bugs at https://bugzilla.redhat.com. ++EOF ++} ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++# Ensure that it's the root user running this script ++if [ "${EUID}" -ne 0 ]; then ++ echo "The grub bootloader password may only be set by root." ++ usage ++ exit 2 ++fi ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -v | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ -o | --output) ++ OUTPUT_PATH=`argument $option "$@"`; shift ;; ++ --output=*) ++ OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;; ++ -o=*) ++ OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;; ++ esac ++done ++ ++# set user input or default path for user.cfg file ++if [ -z "${OUTPUT_PATH}" ]; then ++ OUTPUT_PATH="${grubdir}" ++fi ++ ++if [ ! -d "${OUTPUT_PATH}" ]; then ++ echo "${OUTPUT_PATH} does not exist." ++ usage ++ exit 2; ++fi ++ ++ttyopt=$(stty -g) ++fixtty() { ++ stty ${ttyopt} ++} ++ ++trap fixtty EXIT ++stty -echo ++ ++# prompt & confirm new grub2 root user password ++echo -n "Enter password: " ++read PASSWORD ++echo ++echo -n "Confirm password: " ++read PASSWORD_CONFIRM ++echo ++stty ${ttyopt} ++ ++getpass() { ++ local P0 ++ local P1 ++ P0="$1" && shift ++ P1="$1" && shift ++ ++ ( echo ${P0} ; echo ${P1} ) | \ ++ LC_ALL=C ${grub_mkpasswd} | \ ++ grep -v '[eE]nter password:' | \ ++ sed -e "s/PBKDF2 hash of your password is //" ++} ++ ++MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")" ++if [ -z "${MYPASS}" ]; then ++ echo "${self}: error: empty password" 1>&2 ++ exit 1 ++fi ++ ++# on the ESP, these will fail to set the permissions, but it's okay because ++# the directory is protected. ++install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : ++chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : ++echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg" ++ ++if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then ++ echo "WARNING: The current configuration lacks password support!" ++ echo "Update your configuration with @grub_mkconfig@ to support this feature." ++fi +diff --git a/util/grub.d/01_users.in b/util/grub.d/01_users.in +new file mode 100644 +index 0000000000..db2f44bfb7 +--- /dev/null ++++ b/util/grub.d/01_users.in +@@ -0,0 +1,11 @@ ++#!/bin/sh -e ++cat << EOF ++if [ -f \${prefix}/user.cfg ]; then ++ source \${prefix}/user.cfg ++ if [ -n "\${GRUB2_PASSWORD}" ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root \${GRUB2_PASSWORD} ++ fi ++fi ++EOF diff --git a/0033-Make-grub2-mkconfig-construct-titles-that-look-like-.patch b/0033-Make-grub2-mkconfig-construct-titles-that-look-like-.patch deleted file mode 100644 index db101c0..0000000 --- a/0033-Make-grub2-mkconfig-construct-titles-that-look-like-.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 28 Apr 2015 11:15:03 -0400 -Subject: [PATCH] Make grub2-mkconfig construct titles that look like the ones - we want elsewhere. - -Resolves: rhbz#1215839 - -Signed-off-by: Peter Jones ---- - util/grub.d/10_linux.in | 34 +++++++++++++++++++++++++++------- - 1 file changed, 27 insertions(+), 7 deletions(-) - -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index 5f6d3c8d52..786dbabb4a 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -78,6 +78,32 @@ case x"$GRUB_FS" in - ;; - esac - -+mktitle () -+{ -+ local title_type -+ local version -+ local OS_NAME -+ local OS_VERS -+ -+ title_type=$1 && shift -+ version=$1 && shift -+ -+ OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})" -+ OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})" -+ -+ case $title_type in -+ recovery) -+ title=$(printf '%s (%s) %s (recovery mode)' \ -+ "${OS_NAME}" "${version}" "${OS_VERS}") -+ ;; -+ *) -+ title=$(printf '%s (%s) %s' \ -+ "${OS_NAME}" "${version}" "${OS_VERS}") -+ ;; -+ esac -+ echo -n ${title} -+} -+ - title_correction_code= - - linux_entry () -@@ -91,17 +117,11 @@ linux_entry () - boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" - fi - if [ x$type != xsimple ] ; then -- case $type in -- recovery) -- title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;; -- *) -- title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; -- esac -+ title=$(mktitle "$type" "$version") - if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then - replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" - quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" - title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" -- grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" - fi - echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" - else diff --git a/0034-Add-friendly-grub2-password-config-tool-985962.patch b/0034-Add-friendly-grub2-password-config-tool-985962.patch deleted file mode 100644 index 49089f9..0000000 --- a/0034-Add-friendly-grub2-password-config-tool-985962.patch +++ /dev/null @@ -1,245 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robert Marshall -Date: Thu, 25 Jun 2015 11:13:11 -0400 -Subject: [PATCH] Add friendly grub2 password config tool (#985962) - -Provided a tool for users to reset the grub2 root user password -without having to alter the grub.cfg. The hashed password now -lives in a root-only-readable configuration file. - -Resolves: rhbz#985962 - -Signed-off-by: Robert Marshall -[pjones: fix the efidir in grub-setpassword and rename tool] -Signed-off-by: Peter Jones -[luto: fix grub-setpassword -o's output path] -Signed-off-by: Andy Lutomirski -[rharwood: migrate man page to h2m] -Signed-off-by: Robbie Harwood ---- - configure.ac | 1 + - Makefile.util.def | 13 +++++ - docs/man/grub-set-password.h2m | 2 + - util/grub-mkconfig.in | 2 + - util/grub-set-password.in | 128 +++++++++++++++++++++++++++++++++++++++++ - util/grub.d/01_users.in | 11 ++++ - 6 files changed, 157 insertions(+) - create mode 100644 docs/man/grub-set-password.h2m - create mode 100644 util/grub-set-password.in - create mode 100644 util/grub.d/01_users.in - -diff --git a/configure.ac b/configure.ac -index 87c8f17393..916bede6bf 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath]) - grub_TRANSFORM([grub-mkrescue]) - grub_TRANSFORM([grub-probe]) - grub_TRANSFORM([grub-reboot]) -+grub_TRANSFORM([grub-set-password]) - grub_TRANSFORM([grub-rpm-sort]) - grub_TRANSFORM([grub-script-check]) - grub_TRANSFORM([grub-set-default]) -diff --git a/Makefile.util.def b/Makefile.util.def -index bc10cc7972..8ca4c14f0b 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -452,6 +452,12 @@ script = { - installdir = grubconf; - }; - -+script = { -+ name = '01_users'; -+ common = util/grub.d/01_users.in; -+ installdir = grubconf; -+}; -+ - script = { - name = '10_windows'; - common = util/grub.d/10_windows.in; -@@ -741,6 +747,13 @@ script = { - installdir = sbin; - }; - -+script = { -+ name = grub-set-password; -+ common = util/grub-set-password.in; -+ mansection = 8; -+ installdir = sbin; -+}; -+ - script = { - name = grub-mkconfig_lib; - common = util/grub-mkconfig_lib.in; -diff --git a/docs/man/grub-set-password.h2m b/docs/man/grub-set-password.h2m -new file mode 100644 -index 0000000000..10ee82f4d5 ---- /dev/null -+++ b/docs/man/grub-set-password.h2m -@@ -0,0 +1,2 @@ -+[NAME] -+grub-set-password \- generate the user.cfg file containing the hashed grub bootloader password -diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in -index 8ea2315ebc..ba14cf6261 100644 ---- a/util/grub-mkconfig.in -+++ b/util/grub-mkconfig.in -@@ -276,6 +276,8 @@ for i in "${grub_mkconfig_dir}"/* ; do - *~) ;; - # emacsen autosave files. FIXME: support other editors - */\#*\#) ;; -+ # rpm config files of yore. -+ *.rpmsave|*.rpmnew|*.rpmorig) ;; - *) - if grub_file_is_not_garbage "$i" && test -x "$i" ; then - echo -diff --git a/util/grub-set-password.in b/util/grub-set-password.in -new file mode 100644 -index 0000000000..5ebf50576d ---- /dev/null -+++ b/util/grub-set-password.in -@@ -0,0 +1,128 @@ -+#!/bin/sh -e -+ -+EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/') -+if [ -d /sys/firmware/efi/efivars/ ]; then -+ grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` -+else -+ grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` -+fi -+ -+PACKAGE_VERSION="@PACKAGE_VERSION@" -+PACKAGE_NAME="@PACKAGE_NAME@" -+self=`basename $0` -+bindir="@bindir@" -+grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@" -+ -+# Usage: usage -+# Print the usage. -+usage () { -+ cat < put user.cfg in a user-selected directory -+ -+Report bugs at https://bugzilla.redhat.com. -+EOF -+} -+ -+argument () { -+ opt=$1 -+ shift -+ -+ if test $# -eq 0; then -+ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 -+ exit 1 -+ fi -+ echo $1 -+} -+ -+# Ensure that it's the root user running this script -+if [ "${EUID}" -ne 0 ]; then -+ echo "The grub bootloader password may only be set by root." -+ usage -+ exit 2 -+fi -+ -+# Check the arguments. -+while test $# -gt 0 -+do -+ option=$1 -+ shift -+ -+ case "$option" in -+ -h | --help) -+ usage -+ exit 0 ;; -+ -v | --version) -+ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" -+ exit 0 ;; -+ -o | --output) -+ OUTPUT_PATH=`argument $option "$@"`; shift ;; -+ --output=*) -+ OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;; -+ -o=*) -+ OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;; -+ esac -+done -+ -+# set user input or default path for user.cfg file -+if [ -z "${OUTPUT_PATH}" ]; then -+ OUTPUT_PATH="${grubdir}" -+fi -+ -+if [ ! -d "${OUTPUT_PATH}" ]; then -+ echo "${OUTPUT_PATH} does not exist." -+ usage -+ exit 2; -+fi -+ -+ttyopt=$(stty -g) -+fixtty() { -+ stty ${ttyopt} -+} -+ -+trap fixtty EXIT -+stty -echo -+ -+# prompt & confirm new grub2 root user password -+echo -n "Enter password: " -+read PASSWORD -+echo -+echo -n "Confirm password: " -+read PASSWORD_CONFIRM -+echo -+stty ${ttyopt} -+ -+getpass() { -+ local P0 -+ local P1 -+ P0="$1" && shift -+ P1="$1" && shift -+ -+ ( echo ${P0} ; echo ${P1} ) | \ -+ LC_ALL=C ${grub_mkpasswd} | \ -+ grep -v '[eE]nter password:' | \ -+ sed -e "s/PBKDF2 hash of your password is //" -+} -+ -+MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")" -+if [ -z "${MYPASS}" ]; then -+ echo "${self}: error: empty password" 1>&2 -+ exit 1 -+fi -+ -+# on the ESP, these will fail to set the permissions, but it's okay because -+# the directory is protected. -+install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : -+chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : -+echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg" -+ -+if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then -+ echo "WARNING: The current configuration lacks password support!" -+ echo "Update your configuration with @grub_mkconfig@ to support this feature." -+fi -diff --git a/util/grub.d/01_users.in b/util/grub.d/01_users.in -new file mode 100644 -index 0000000000..db2f44bfb7 ---- /dev/null -+++ b/util/grub.d/01_users.in -@@ -0,0 +1,11 @@ -+#!/bin/sh -e -+cat << EOF -+if [ -f \${prefix}/user.cfg ]; then -+ source \${prefix}/user.cfg -+ if [ -n "\${GRUB2_PASSWORD}" ]; then -+ set superusers="root" -+ export superusers -+ password_pbkdf2 root \${GRUB2_PASSWORD} -+ fi -+fi -+EOF diff --git a/0034-tcp-add-window-scaling-support.patch b/0034-tcp-add-window-scaling-support.patch new file mode 100644 index 0000000..61b5a67 --- /dev/null +++ b/0034-tcp-add-window-scaling-support.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Wed, 12 Aug 2015 08:57:55 -0700 +Subject: [PATCH] tcp: add window scaling support + +Sometimes we have to provision boxes across regions, such as California to +Sweden. The http server has a 10 minute timeout, so if we can't get our 250mb +image transferred fast enough our provisioning fails, which is not ideal. So +add tcp window scaling on open connections and set the window size to 1mb. With +this change we're able to get higher sustained transfers between regions and can +transfer our image in well below 10 minutes. Without this patch we'd time out +every time halfway through the transfer. Thanks, + +Signed-off-by: Josef Bacik +--- + grub-core/net/tcp.c | 42 +++++++++++++++++++++++++++++------------- + 1 file changed, 29 insertions(+), 13 deletions(-) + +diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c +index e8ad34b84d..7d4b822626 100644 +--- a/grub-core/net/tcp.c ++++ b/grub-core/net/tcp.c +@@ -106,6 +106,18 @@ struct tcphdr + grub_uint16_t urgent; + } GRUB_PACKED; + ++struct tcp_scale_opt { ++ grub_uint8_t kind; ++ grub_uint8_t length; ++ grub_uint8_t scale; ++} GRUB_PACKED; ++ ++struct tcp_synhdr { ++ struct tcphdr tcphdr; ++ struct tcp_scale_opt scale_opt; ++ grub_uint8_t padding; ++}; ++ + struct tcp_pseudohdr + { + grub_uint32_t src; +@@ -566,7 +578,7 @@ grub_net_tcp_open (char *server, + grub_net_tcp_socket_t socket; + static grub_uint16_t in_port = 21550; + struct grub_net_buff *nb; +- struct tcphdr *tcph; ++ struct tcp_synhdr *tcph; + int i; + grub_uint8_t *nbd; + grub_net_link_level_address_t ll_target_addr; +@@ -635,20 +647,24 @@ grub_net_tcp_open (char *server, + } + + tcph = (void *) nb->data; ++ grub_memset(tcph, 0, sizeof (*tcph)); + socket->my_start_seq = grub_get_time_ms (); + socket->my_cur_seq = socket->my_start_seq + 1; +- socket->my_window = 8192; +- tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq); +- tcph->ack = grub_cpu_to_be32_compile_time (0); +- tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN); +- tcph->window = grub_cpu_to_be16 (socket->my_window); +- tcph->urgent = 0; +- tcph->src = grub_cpu_to_be16 (socket->in_port); +- tcph->dst = grub_cpu_to_be16 (socket->out_port); +- tcph->checksum = 0; +- tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, +- &socket->inf->address, +- &socket->out_nla); ++ socket->my_window = 32768; ++ tcph->tcphdr.seqnr = grub_cpu_to_be32 (socket->my_start_seq); ++ tcph->tcphdr.ack = grub_cpu_to_be32_compile_time (0); ++ tcph->tcphdr.flags = grub_cpu_to_be16_compile_time ((6 << 12) | TCP_SYN); ++ tcph->tcphdr.window = grub_cpu_to_be16 (socket->my_window); ++ tcph->tcphdr.urgent = 0; ++ tcph->tcphdr.src = grub_cpu_to_be16 (socket->in_port); ++ tcph->tcphdr.dst = grub_cpu_to_be16 (socket->out_port); ++ tcph->tcphdr.checksum = 0; ++ tcph->scale_opt.kind = 3; ++ tcph->scale_opt.length = 3; ++ tcph->scale_opt.scale = 5; ++ tcph->tcphdr.checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, ++ &socket->inf->address, ++ &socket->out_nla); + + tcp_socket_register (socket); + diff --git a/0035-efinet-and-bootp-add-support-for-dhcpv6.patch b/0035-efinet-and-bootp-add-support-for-dhcpv6.patch new file mode 100644 index 0000000..efeeee0 --- /dev/null +++ b/0035-efinet-and-bootp-add-support-for-dhcpv6.patch @@ -0,0 +1,651 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 11:47:37 +0200 +Subject: [PATCH] efinet and bootp: add support for dhcpv6 + +Signed-off-by: Peter Jones +--- + grub-core/net/bootp.c | 173 +++++++++++++++++++++++++++++++++++++ + grub-core/net/drivers/efi/efinet.c | 53 ++++++++++-- + grub-core/net/net.c | 72 +++++++++++++++ + grub-core/net/tftp.c | 4 + + include/grub/efi/api.h | 129 +++++++++++++++++++++++++-- + include/grub/net.h | 60 +++++++++++++ + 6 files changed, 477 insertions(+), 14 deletions(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 6fb5627025..e28fb6a09f 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -902,6 +902,179 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), + + static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; + ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_ack (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags ++ __attribute__((__unused__)), ++ const grub_net_link_level_address_t *hwaddr, ++ const struct grub_net_dhcpv6_packet *packet, ++ int is_def, char **device, char **path) ++{ ++ struct grub_net_network_level_interface *inter = NULL; ++ struct grub_net_network_level_address addr; ++ int mask = -1; ++ ++ if (!device || !path) ++ return NULL; ++ ++ *device = 0; ++ *path = 0; ++ ++ grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n", ++ hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2], ++ hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]); ++ ++ if (is_def) ++ grub_net_default_server = 0; ++ ++ if (is_def && !grub_net_default_server && packet) ++ { ++ const grub_uint8_t *options = packet->dhcp_options; ++ unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet); ++ unsigned int i; ++ ++ for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); ) ++ { ++ grub_uint16_t num, len; ++ grub_net_dhcpv6_option_t *opt = ++ (grub_net_dhcpv6_option_t *)(options + i); ++ ++ num = grub_be_to_cpu16(opt->option_num); ++ len = grub_be_to_cpu16(opt->option_len); ++ ++ grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len); ++ ++ if (len == 0) ++ break; ++ ++ if (len + i > 1024) ++ break; ++ ++ if (num == GRUB_NET_DHCP6_BOOTFILE_URL) ++ { ++ char *scheme, *userinfo, *host, *file; ++ char *tmp; ++ int hostlen; ++ int port; ++ int rc = extract_url_info ((const char *)opt->option_data, ++ (grub_size_t)len, ++ &scheme, &userinfo, &host, &port, ++ &file); ++ if (rc < 0) ++ continue; ++ ++ /* right now this only handles tftp. */ ++ if (grub_strcmp("tftp", scheme)) ++ { ++ grub_free (scheme); ++ grub_free (userinfo); ++ grub_free (host); ++ grub_free (file); ++ continue; ++ } ++ grub_free (userinfo); ++ ++ hostlen = grub_strlen (host); ++ if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']') ++ { ++ tmp = host+1; ++ host[hostlen-1] = '\0'; ++ } ++ else ++ tmp = host; ++ ++ *device = grub_xasprintf ("%s,%s", scheme, tmp); ++ grub_free (scheme); ++ grub_free (host); ++ ++ if (file && *file) ++ { ++ tmp = grub_strrchr (file, '/'); ++ if (tmp) ++ *(tmp+1) = '\0'; ++ else ++ file[0] = '\0'; ++ } ++ else if (!file) ++ file = grub_strdup (""); ++ ++ if (file[0] == '/') ++ { ++ *path = grub_strdup (file+1); ++ grub_free (file); ++ } ++ else ++ *path = file; ++ } ++ else if (num == GRUB_NET_DHCP6_IA_NA) ++ { ++ const grub_net_dhcpv6_option_t *ia_na_opt; ++ const grub_net_dhcpv6_opt_ia_na_t *ia_na = ++ (const grub_net_dhcpv6_opt_ia_na_t *)opt; ++ unsigned int left = len - OFFSET_OF (options, ia_na); ++ unsigned int j; ++ ++ if ((grub_uint8_t *)ia_na + left > ++ (grub_uint8_t *)options + option_max) ++ left -= ((grub_uint8_t *)ia_na + left) ++ - ((grub_uint8_t *)options + option_max); ++ ++ if (len < OFFSET_OF (option_data, opt) ++ + sizeof (grub_net_dhcpv6_option_t)) ++ { ++ grub_dprintf ("net", ++ "found dhcpv6 ia_na option with no address\n"); ++ continue; ++ } ++ ++ for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); ) ++ { ++ ia_na_opt = (const grub_net_dhcpv6_option_t *) ++ (ia_na->options + j); ++ grub_uint16_t ia_na_opt_num, ia_na_opt_len; ++ ++ ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num); ++ ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len); ++ if (ia_na_opt_len == 0) ++ break; ++ if (j + ia_na_opt_len > left) ++ break; ++ if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS) ++ { ++ const grub_net_dhcpv6_opt_ia_address_t *ia_addr; ++ ++ ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *) ++ ia_na_opt; ++ addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ grub_memcpy(addr.ipv6, ia_addr->ipv6_address, ++ sizeof (ia_addr->ipv6_address)); ++ inter = grub_net_add_addr (name, card, &addr, hwaddr, 0); ++ } ++ ++ j += ia_na_opt_len; ++ left -= ia_na_opt_len; ++ } ++ } ++ ++ i += len + 4; ++ } ++ ++ grub_print_error (); ++ } ++ ++ if (is_def) ++ { ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++ ++ if (inter) ++ grub_net_add_ipv6_local (inter, mask); ++ return inter; ++} ++ ++ + void + grub_bootp_init (void) + { +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 5388f952ba..173fb63153 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -18,11 +18,14 @@ + + #include + #include ++#include + #include + #include + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -329,7 +332,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) + { + struct grub_net_card *card; +- grub_efi_device_path_t *dp; ++ grub_efi_device_path_t *dp, *ldp = NULL; + + dp = grub_efi_get_device_path (hnd); + if (! dp) +@@ -340,14 +343,19 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; + struct grub_efi_pxe_mode *pxe_mode; ++ + if (card->driver != &efidriver) + continue; ++ + cdp = grub_efi_get_device_path (card->efi_handle); + if (! cdp) + continue; ++ ++ ldp = grub_efi_find_last_device_path (dp); ++ + if (grub_efi_compare_device_paths (dp, cdp) != 0) + { +- grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp; ++ grub_efi_device_path_t *dup_dp, *dup_ldp; + int match; + + /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6 +@@ -356,7 +364,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + devices. We skip them when enumerating cards, so here we need to + find matching MAC device. + */ +- ldp = grub_efi_find_last_device_path (dp); + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) +@@ -373,16 +380,46 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (!match) + continue; + } ++ + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (! pxe) + continue; ++ + pxe_mode = pxe->mode; +- grub_net_configure_by_dhcp_ack (card->name, card, 0, +- (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), +- 1, device, path); ++ if (pxe_mode->using_ipv6) ++ { ++ grub_net_link_level_address_t hwaddr; ++ struct grub_net_network_level_interface *intf; ++ ++ grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); ++ grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", ++ pxe_mode->dhcp_ack_received ? "yes" : "no", ++ pxe_mode->dhcp_ack_received ? "" : " cannot continue"); ++ if (!pxe_mode->dhcp_ack_received) ++ continue; ++ ++ hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ grub_memcpy (hwaddr.mac, ++ card->efi_net->mode->current_address, ++ sizeof (hwaddr.mac)); ++ ++ intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr, ++ (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6, ++ 1, device, path); ++ if (intf && device && path) ++ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ } ++ else ++ { ++ grub_dprintf ("efinet", "using ipv4 and dhcp\n"); ++ grub_net_configure_by_dhcp_ack (card->name, card, 0, ++ (struct grub_net_bootp_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ } + return; + } + } +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 0ef148f4ad..22f2689aae 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -960,6 +960,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa + grub_net_network_level_interfaces = inter; + } + ++int ++grub_ipv6_get_masksize (grub_uint16_t be_mask[8]) ++{ ++ grub_uint8_t *mask; ++ grub_uint16_t mask16[8]; ++ int x, y; ++ int ret = 128; ++ ++ grub_memcpy (mask16, be_mask, sizeof (mask16)); ++ for (x = 0; x < 8; x++) ++ mask16[x] = grub_be_to_cpu16 (mask16[x]); ++ ++ mask = (grub_uint8_t *)mask16; ++ ++ for (x = 15; x >= 0; x--) ++ { ++ grub_uint8_t octet = mask[x]; ++ if (!octet) ++ { ++ ret -= 8; ++ continue; ++ } ++ for (y = 0; y < 8; y++) ++ { ++ if (octet & (1 << y)) ++ break; ++ else ++ ret--; ++ } ++ break; ++ } ++ ++ return ret; ++} ++ ++grub_err_t ++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter, ++ int mask) ++{ ++ struct grub_net_route *route; ++ ++ if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6) ++ return 0; ++ ++ if (mask == -1) ++ mask = grub_ipv6_get_masksize ((grub_uint16_t *)inter->address.ipv6); ++ ++ if (mask == -1) ++ return 0; ++ ++ route = grub_zalloc (sizeof (*route)); ++ if (!route) ++ return grub_errno; ++ ++ route->name = grub_xasprintf ("%s:local", inter->name); ++ if (!route->name) ++ { ++ grub_free (route); ++ return grub_errno; ++ } ++ ++ route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ grub_memcpy (route->target.ipv6.base, inter->address.ipv6, ++ sizeof (inter->address.ipv6)); ++ route->target.ipv6.masksize = mask; ++ route->is_gateway = 0; ++ route->interface = inter; ++ ++ grub_net_route_register (route); ++ ++ return 0; ++} + + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter, +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 7f44b30f52..4ab2f5c735 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -358,18 +358,22 @@ tftp_open (struct grub_file *file, const char *filename) + file->not_easily_seekable = 1; + file->data = data; + ++ grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server); + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { ++ grub_dprintf("tftp", "Address resolution failed: %d\n", err); + grub_free (data); + return err; + } + ++ grub_dprintf("tftp", "opening connection\n"); + data->sock = grub_net_udp_open (addr, + TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { ++ grub_dprintf("tftp", "connection failed\n"); + grub_free (data); + return grub_errno; + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index f1a52210c0..117469450d 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -592,10 +592,16 @@ typedef void *grub_efi_handle_t; + typedef void *grub_efi_event_t; + typedef grub_efi_uint64_t grub_efi_lba_t; + typedef grub_efi_uintn_t grub_efi_tpl_t; +-typedef grub_uint8_t grub_efi_mac_address_t[32]; +-typedef grub_uint8_t grub_efi_ipv4_address_t[4]; +-typedef grub_uint16_t grub_efi_ipv6_address_t[8]; +-typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4))); ++typedef grub_efi_uint8_t grub_efi_mac_address_t[32]; ++typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4]; ++typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16]; ++typedef union ++{ ++ grub_efi_uint32_t addr[4]; ++ grub_efi_ipv4_address_t v4; ++ grub_efi_ipv6_address_t v6; ++} grub_efi_ip_address_t __attribute__ ((aligned(4))); ++ + typedef grub_efi_uint64_t grub_efi_physical_address_t; + typedef grub_efi_uint64_t grub_efi_virtual_address_t; + +@@ -1474,16 +1480,127 @@ struct grub_efi_simple_text_output_interface + }; + typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t; + +-typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; ++typedef struct grub_efi_pxe_dhcpv4_packet ++{ ++ grub_efi_uint8_t bootp_opcode; ++ grub_efi_uint8_t bootp_hwtype; ++ grub_efi_uint8_t bootp_hwaddr_len; ++ grub_efi_uint8_t bootp_gate_hops; ++ grub_efi_uint32_t bootp_ident; ++ grub_efi_uint16_t bootp_seconds; ++ grub_efi_uint16_t bootp_flags; ++ grub_efi_uint8_t bootp_ci_addr[4]; ++ grub_efi_uint8_t bootp_yi_addr[4]; ++ grub_efi_uint8_t bootp_si_addr[4]; ++ grub_efi_uint8_t bootp_gi_addr[4]; ++ grub_efi_uint8_t bootp_hw_addr[16]; ++ grub_efi_uint8_t bootp_srv_name[64]; ++ grub_efi_uint8_t bootp_boot_file[128]; ++ grub_efi_uint32_t dhcp_magik; ++ grub_efi_uint8_t dhcp_options[56]; ++} grub_efi_pxe_dhcpv4_packet_t; ++ ++struct grub_efi_pxe_dhcpv6_packet ++{ ++ grub_efi_uint32_t message_type:8; ++ grub_efi_uint32_t transaction_id:24; ++ grub_efi_uint8_t dhcp_options[1024]; ++} GRUB_PACKED; ++typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t; ++ ++typedef union ++{ ++ grub_efi_uint8_t raw[1472]; ++ grub_efi_pxe_dhcpv4_packet_t dhcpv4; ++ grub_efi_pxe_dhcpv6_packet_t dhcpv6; ++} grub_efi_pxe_packet_t; ++ ++#define GRUB_EFI_PXE_MAX_IPCNT 8 ++#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8 ++#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8 ++ ++typedef struct grub_efi_pxe_ip_filter ++{ ++ grub_efi_uint8_t filters; ++ grub_efi_uint8_t ip_count; ++ grub_efi_uint8_t reserved; ++ grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; ++} grub_efi_pxe_ip_filter_t; ++ ++typedef struct grub_efi_pxe_arp_entry ++{ ++ grub_efi_ip_address_t ip_addr; ++ grub_efi_mac_address_t mac_addr; ++} grub_efi_pxe_arp_entry_t; ++ ++typedef struct grub_efi_pxe_route_entry ++{ ++ grub_efi_ip_address_t ip_addr; ++ grub_efi_ip_address_t subnet_mask; ++ grub_efi_ip_address_t gateway_addr; ++} grub_efi_pxe_route_entry_t; ++ ++typedef struct grub_efi_pxe_icmp_error ++{ ++ grub_efi_uint8_t type; ++ grub_efi_uint8_t code; ++ grub_efi_uint16_t checksum; ++ union ++ { ++ grub_efi_uint32_t reserved; ++ grub_efi_uint32_t mtu; ++ grub_efi_uint32_t pointer; ++ struct ++ { ++ grub_efi_uint16_t identifier; ++ grub_efi_uint16_t sequence; ++ } echo; ++ } u; ++ grub_efi_uint8_t data[494]; ++} grub_efi_pxe_icmp_error_t; ++ ++typedef struct grub_efi_pxe_tftp_error ++{ ++ grub_efi_uint8_t error_code; ++ grub_efi_char8_t error_string[127]; ++} grub_efi_pxe_tftp_error_t; + + typedef struct grub_efi_pxe_mode + { +- grub_uint8_t unused[52]; ++ grub_efi_boolean_t started; ++ grub_efi_boolean_t ipv6_available; ++ grub_efi_boolean_t ipv6_supported; ++ grub_efi_boolean_t using_ipv6; ++ grub_efi_boolean_t bis_supported; ++ grub_efi_boolean_t bis_detected; ++ grub_efi_boolean_t auto_arp; ++ grub_efi_boolean_t send_guid; ++ grub_efi_boolean_t dhcp_discover_valid; ++ grub_efi_boolean_t dhcp_ack_received; ++ grub_efi_boolean_t proxy_offer_received; ++ grub_efi_boolean_t pxe_discover_valid; ++ grub_efi_boolean_t pxe_reply_received; ++ grub_efi_boolean_t pxe_bis_reply_received; ++ grub_efi_boolean_t icmp_error_received; ++ grub_efi_boolean_t tftp_error_received; ++ grub_efi_boolean_t make_callbacks; ++ grub_efi_uint8_t ttl; ++ grub_efi_uint8_t tos; ++ grub_efi_ip_address_t station_ip; ++ grub_efi_ip_address_t subnet_mask; + grub_efi_pxe_packet_t dhcp_discover; + grub_efi_pxe_packet_t dhcp_ack; + grub_efi_pxe_packet_t proxy_offer; + grub_efi_pxe_packet_t pxe_discover; + grub_efi_pxe_packet_t pxe_reply; ++ grub_efi_pxe_packet_t pxe_bis_reply; ++ grub_efi_pxe_ip_filter_t ip_filter; ++ grub_efi_uint32_t arp_cache_entries; ++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES]; ++ grub_efi_uint32_t route_table_entries; ++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES]; ++ grub_efi_pxe_icmp_error_t icmp_error; ++ grub_efi_pxe_tftp_error_t tftp_error; + } grub_efi_pxe_mode_t; + + typedef struct grub_efi_pxe +diff --git a/include/grub/net.h b/include/grub/net.h +index 7ae4b6bd80..8a05ec4fe7 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -447,6 +447,51 @@ struct grub_net_bootp_packet + grub_uint8_t vendor[0]; + } GRUB_PACKED; + ++enum ++ { ++ GRUB_NET_DHCP6_IA_NA = 3, ++ GRUB_NET_DHCP6_IA_ADDRESS = 5, ++ GRUB_NET_DHCP6_BOOTFILE_URL = 59, ++ }; ++ ++struct grub_net_dhcpv6_option ++{ ++ grub_uint16_t option_num; ++ grub_uint16_t option_len; ++ grub_uint8_t option_data[]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t; ++ ++struct grub_net_dhcpv6_opt_ia_na ++{ ++ grub_uint16_t option_num; ++ grub_uint16_t option_len; ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_uint8_t options[]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t; ++ ++struct grub_net_dhcpv6_opt_ia_address ++{ ++ grub_uint16_t option_num; ++ grub_uint16_t option_len; ++ grub_uint64_t ipv6_address[2]; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_uint8_t options[]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t; ++ ++struct grub_net_dhcpv6_packet ++{ ++ grub_uint32_t message_type:8; ++ grub_uint32_t transaction_id:24; ++ grub_uint8_t dhcp_options[1024]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t; ++ + #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 +@@ -482,6 +527,21 @@ grub_net_configure_by_dhcp_ack (const char *name, + grub_size_t size, + int is_def, char **device, char **path); + ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_ack (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const grub_net_link_level_address_t *hwaddr, ++ const struct grub_net_dhcpv6_packet *packet, ++ int is_def, char **device, char **path); ++ ++int ++grub_ipv6_get_masksize(grub_uint16_t *mask); ++ ++grub_err_t ++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf, ++ int mask); ++ + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf, + int mask); diff --git a/0035-tcp-add-window-scaling-support.patch b/0035-tcp-add-window-scaling-support.patch deleted file mode 100644 index 61b5a67..0000000 --- a/0035-tcp-add-window-scaling-support.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Josef Bacik -Date: Wed, 12 Aug 2015 08:57:55 -0700 -Subject: [PATCH] tcp: add window scaling support - -Sometimes we have to provision boxes across regions, such as California to -Sweden. The http server has a 10 minute timeout, so if we can't get our 250mb -image transferred fast enough our provisioning fails, which is not ideal. So -add tcp window scaling on open connections and set the window size to 1mb. With -this change we're able to get higher sustained transfers between regions and can -transfer our image in well below 10 minutes. Without this patch we'd time out -every time halfway through the transfer. Thanks, - -Signed-off-by: Josef Bacik ---- - grub-core/net/tcp.c | 42 +++++++++++++++++++++++++++++------------- - 1 file changed, 29 insertions(+), 13 deletions(-) - -diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c -index e8ad34b84d..7d4b822626 100644 ---- a/grub-core/net/tcp.c -+++ b/grub-core/net/tcp.c -@@ -106,6 +106,18 @@ struct tcphdr - grub_uint16_t urgent; - } GRUB_PACKED; - -+struct tcp_scale_opt { -+ grub_uint8_t kind; -+ grub_uint8_t length; -+ grub_uint8_t scale; -+} GRUB_PACKED; -+ -+struct tcp_synhdr { -+ struct tcphdr tcphdr; -+ struct tcp_scale_opt scale_opt; -+ grub_uint8_t padding; -+}; -+ - struct tcp_pseudohdr - { - grub_uint32_t src; -@@ -566,7 +578,7 @@ grub_net_tcp_open (char *server, - grub_net_tcp_socket_t socket; - static grub_uint16_t in_port = 21550; - struct grub_net_buff *nb; -- struct tcphdr *tcph; -+ struct tcp_synhdr *tcph; - int i; - grub_uint8_t *nbd; - grub_net_link_level_address_t ll_target_addr; -@@ -635,20 +647,24 @@ grub_net_tcp_open (char *server, - } - - tcph = (void *) nb->data; -+ grub_memset(tcph, 0, sizeof (*tcph)); - socket->my_start_seq = grub_get_time_ms (); - socket->my_cur_seq = socket->my_start_seq + 1; -- socket->my_window = 8192; -- tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq); -- tcph->ack = grub_cpu_to_be32_compile_time (0); -- tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN); -- tcph->window = grub_cpu_to_be16 (socket->my_window); -- tcph->urgent = 0; -- tcph->src = grub_cpu_to_be16 (socket->in_port); -- tcph->dst = grub_cpu_to_be16 (socket->out_port); -- tcph->checksum = 0; -- tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, -- &socket->inf->address, -- &socket->out_nla); -+ socket->my_window = 32768; -+ tcph->tcphdr.seqnr = grub_cpu_to_be32 (socket->my_start_seq); -+ tcph->tcphdr.ack = grub_cpu_to_be32_compile_time (0); -+ tcph->tcphdr.flags = grub_cpu_to_be16_compile_time ((6 << 12) | TCP_SYN); -+ tcph->tcphdr.window = grub_cpu_to_be16 (socket->my_window); -+ tcph->tcphdr.urgent = 0; -+ tcph->tcphdr.src = grub_cpu_to_be16 (socket->in_port); -+ tcph->tcphdr.dst = grub_cpu_to_be16 (socket->out_port); -+ tcph->tcphdr.checksum = 0; -+ tcph->scale_opt.kind = 3; -+ tcph->scale_opt.length = 3; -+ tcph->scale_opt.scale = 5; -+ tcph->tcphdr.checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, -+ &socket->inf->address, -+ &socket->out_nla); - - tcp_socket_register (socket); - diff --git a/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch b/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch new file mode 100644 index 0000000..95490cd --- /dev/null +++ b/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch @@ -0,0 +1,271 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 23 Jun 2016 11:01:39 -0400 +Subject: [PATCH] Add grub-get-kernel-settings and use it in 10_linux + +This patch adds grub-get-kernel-settings, which reads the system kernel +installation configuration from /etc/sysconfig/kernel, and outputs +${GRUB_...} variables suitable for evaluation by grub-mkconfig. Those +variables are then used by 10_linux to choose whether or not to create +debug stanzas. + +Resolves: rhbz#1226325 +[rharwood: migrate man page to h2m] +--- + configure.ac | 1 + + Makefile.util.def | 7 ++ + docs/man/grub-get-kernel-settings.h2m | 2 + + util/bash-completion.d/grub-completion.bash.in | 22 +++++++ + util/grub-get-kernel-settings.in | 88 ++++++++++++++++++++++++++ + util/grub-mkconfig.in | 3 + + util/grub.d/10_linux.in | 23 +++++-- + 7 files changed, 141 insertions(+), 5 deletions(-) + create mode 100644 docs/man/grub-get-kernel-settings.h2m + create mode 100644 util/grub-get-kernel-settings.in + +diff --git a/configure.ac b/configure.ac +index 7f59ad788f..0d0e6782a1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -65,6 +65,7 @@ grub_TRANSFORM([grub-install]) + grub_TRANSFORM([grub-mkconfig]) + grub_TRANSFORM([grub-mkfont]) + grub_TRANSFORM([grub-mkimage]) ++grub_TRANSFORM([grub-get-kernel-settings]) + grub_TRANSFORM([grub-glue-efi]) + grub_TRANSFORM([grub-mklayout]) + grub_TRANSFORM([grub-mkpasswd-pbkdf2]) +diff --git a/Makefile.util.def b/Makefile.util.def +index 4ee22c5daa..18a9242776 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -716,6 +716,13 @@ script = { + installdir = sbin; + }; + ++script = { ++ name = grub-get-kernel-settings; ++ common = util/grub-get-kernel-settings.in; ++ mansection = 3; ++ installdir = sbin; ++}; ++ + script = { + name = grub-set-default; + common = util/grub-set-default.in; +diff --git a/docs/man/grub-get-kernel-settings.h2m b/docs/man/grub-get-kernel-settings.h2m +new file mode 100644 +index 0000000000..b8051f01f3 +--- /dev/null ++++ b/docs/man/grub-get-kernel-settings.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-get-kernel-settings \- Evaluate the system's kernel installation settings for use while making a grub configuration file +diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in +index 44bf135b9f..5c4acd496d 100644 +--- a/util/bash-completion.d/grub-completion.bash.in ++++ b/util/bash-completion.d/grub-completion.bash.in +@@ -264,6 +264,28 @@ have ${__grub_sparc64_setup_program} && \ + unset __grub_sparc64_setup_program + + ++# ++# grub-get-kernel-settings ++# ++_grub_get_kernel_settings () { ++ local cur ++ ++ COMPREPLY=() ++ cur=`_get_cword` ++ ++ if [[ "$cur" == -* ]]; then ++ __grubcomp "$(__grub_get_options_from_help)" ++ else ++ # Default complete with a filename ++ _filedir ++ fi ++} ++__grub_get_kernel_settings_program="@grub_get_kernel_settings@" ++have ${__grub_get_kernel_settings_program} && \ ++ complete -F _grub_get_kernel_settings -o filenames ${__grub_get_kernel_settings_program} ++unset __grub_get_kernel_settings_program ++ ++ + # + # grub-install + # +diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in +new file mode 100644 +index 0000000000..7e87dfccc0 +--- /dev/null ++++ b/util/grub-get-kernel-settings.in +@@ -0,0 +1,88 @@ ++#!/bin/sh ++set -e ++ ++# Evaluate new-kernel-pkg's configuration file. ++# Copyright (C) 2016 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 . ++ ++PACKAGE_NAME=@PACKAGE_NAME@ ++PACKAGE_VERSION=@PACKAGE_VERSION@ ++datadir="@datadir@" ++if [ "x$pkgdatadir" = x ]; then ++ pkgdatadir="${datadir}/@PACKAGE@" ++fi ++ ++self=`basename $0` ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR="@localedir@" ++ ++. "${pkgdatadir}/grub-mkconfig_lib" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ gettext_printf "Usage: %s [OPTION]\n" "$self" ++ gettext "Evaluate new-kernel-pkg configuration"; echo ++ echo ++ print_option_help "-h, --help" "$(gettext "print this message and exit")" ++ print_option_help "-v, --version" "$(gettext "print the version information and exit")" ++ echo ++} ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -v | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ -*) ++ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 ++ usage ++ exit 1 ++ ;; ++ # Explicitly ignore non-option arguments, for compatibility. ++ esac ++done ++ ++if test -f /etc/sysconfig/kernel ; then ++ . /etc/sysconfig/kernel ++fi ++ ++if [ "$MAKEDEBUG" = "yes" ]; then ++ echo GRUB_LINUX_MAKE_DEBUG=true ++ echo export GRUB_LINUX_MAKE_DEBUG ++ echo GRUB_CMDLINE_LINUX_DEBUG=\"systemd.log_level=debug systemd.log_target=kmsg\" ++ echo export GRUB_CMDLINE_LINUX_DEBUG ++ echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\" ++ echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX ++fi ++if [ "$DEFAULTDEBUG" = "yes" ]; then ++ echo GRUB_DEFAULT_TO_DEBUG=true ++else ++ echo GRUB_DEFAULT_TO_DEBUG=false ++fi ++echo export GRUB_DEFAULT_TO_DEBUG ++if [ "$UPDATEDEFAULT" = "yes" ]; then ++ echo GRUB_UPDATE_DEFAULT_KERNEL=true ++ echo export GRUB_UPDATE_DEFAULT_KERNEL ++fi +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index ba14cf6261..005f093809 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -45,6 +45,7 @@ grub_probe="${sbindir}/@grub_probe@" + grub_file="${bindir}/@grub_file@" + grub_editenv="${bindir}/@grub_editenv@" + grub_script_check="${bindir}/@grub_script_check@" ++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" + + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" +@@ -158,6 +159,8 @@ if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub + fi + ++eval "$("${grub_get_kernel_settings}")" || true ++ + if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then + if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then + GRUB_DISABLE_LINUX_UUID="true" +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 786dbabb4a..292e333324 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -111,7 +111,8 @@ linux_entry () + os="$1" + version="$2" + type="$3" +- args="$4" ++ isdebug="$4" ++ args="$5" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" +@@ -123,6 +124,9 @@ linux_entry () + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + fi ++ if [ x$isdebug = xdebug ]; then ++ title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}" ++ fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else + echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" +@@ -306,11 +310,15 @@ while [ "x$list" != "x" ] ; do + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then +- linux_entry "${OS}" "${version}" simple \ ++ linux_entry "${OS}" "${version}" simple standard \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ linux_entry "${OS}" "${version}" simple debug \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi + + submenu_indentation="$grub_tab" +- ++ + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi +@@ -319,10 +327,15 @@ while [ "x$list" != "x" ] ; do + is_top_level=false + fi + +- linux_entry "${OS}" "${version}" advanced \ ++ linux_entry "${OS}" "${version}" advanced standard \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ linux_entry "${OS}" "${version}" advanced debug \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi ++ + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then +- linux_entry "${OS}" "${version}" recovery \ ++ linux_entry "${OS}" "${version}" recovery standard \ + "single ${GRUB_CMDLINE_LINUX}" + fi + diff --git a/0036-efinet-and-bootp-add-support-for-dhcpv6.patch b/0036-efinet-and-bootp-add-support-for-dhcpv6.patch deleted file mode 100644 index efeeee0..0000000 --- a/0036-efinet-and-bootp-add-support-for-dhcpv6.patch +++ /dev/null @@ -1,651 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 9 Jul 2019 11:47:37 +0200 -Subject: [PATCH] efinet and bootp: add support for dhcpv6 - -Signed-off-by: Peter Jones ---- - grub-core/net/bootp.c | 173 +++++++++++++++++++++++++++++++++++++ - grub-core/net/drivers/efi/efinet.c | 53 ++++++++++-- - grub-core/net/net.c | 72 +++++++++++++++ - grub-core/net/tftp.c | 4 + - include/grub/efi/api.h | 129 +++++++++++++++++++++++++-- - include/grub/net.h | 60 +++++++++++++ - 6 files changed, 477 insertions(+), 14 deletions(-) - -diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c -index 6fb5627025..e28fb6a09f 100644 ---- a/grub-core/net/bootp.c -+++ b/grub-core/net/bootp.c -@@ -902,6 +902,179 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), - - static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; - -+struct grub_net_network_level_interface * -+grub_net_configure_by_dhcpv6_ack (const char *name, -+ struct grub_net_card *card, -+ grub_net_interface_flags_t flags -+ __attribute__((__unused__)), -+ const grub_net_link_level_address_t *hwaddr, -+ const struct grub_net_dhcpv6_packet *packet, -+ int is_def, char **device, char **path) -+{ -+ struct grub_net_network_level_interface *inter = NULL; -+ struct grub_net_network_level_address addr; -+ int mask = -1; -+ -+ if (!device || !path) -+ return NULL; -+ -+ *device = 0; -+ *path = 0; -+ -+ grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n", -+ hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2], -+ hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]); -+ -+ if (is_def) -+ grub_net_default_server = 0; -+ -+ if (is_def && !grub_net_default_server && packet) -+ { -+ const grub_uint8_t *options = packet->dhcp_options; -+ unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet); -+ unsigned int i; -+ -+ for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); ) -+ { -+ grub_uint16_t num, len; -+ grub_net_dhcpv6_option_t *opt = -+ (grub_net_dhcpv6_option_t *)(options + i); -+ -+ num = grub_be_to_cpu16(opt->option_num); -+ len = grub_be_to_cpu16(opt->option_len); -+ -+ grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len); -+ -+ if (len == 0) -+ break; -+ -+ if (len + i > 1024) -+ break; -+ -+ if (num == GRUB_NET_DHCP6_BOOTFILE_URL) -+ { -+ char *scheme, *userinfo, *host, *file; -+ char *tmp; -+ int hostlen; -+ int port; -+ int rc = extract_url_info ((const char *)opt->option_data, -+ (grub_size_t)len, -+ &scheme, &userinfo, &host, &port, -+ &file); -+ if (rc < 0) -+ continue; -+ -+ /* right now this only handles tftp. */ -+ if (grub_strcmp("tftp", scheme)) -+ { -+ grub_free (scheme); -+ grub_free (userinfo); -+ grub_free (host); -+ grub_free (file); -+ continue; -+ } -+ grub_free (userinfo); -+ -+ hostlen = grub_strlen (host); -+ if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']') -+ { -+ tmp = host+1; -+ host[hostlen-1] = '\0'; -+ } -+ else -+ tmp = host; -+ -+ *device = grub_xasprintf ("%s,%s", scheme, tmp); -+ grub_free (scheme); -+ grub_free (host); -+ -+ if (file && *file) -+ { -+ tmp = grub_strrchr (file, '/'); -+ if (tmp) -+ *(tmp+1) = '\0'; -+ else -+ file[0] = '\0'; -+ } -+ else if (!file) -+ file = grub_strdup (""); -+ -+ if (file[0] == '/') -+ { -+ *path = grub_strdup (file+1); -+ grub_free (file); -+ } -+ else -+ *path = file; -+ } -+ else if (num == GRUB_NET_DHCP6_IA_NA) -+ { -+ const grub_net_dhcpv6_option_t *ia_na_opt; -+ const grub_net_dhcpv6_opt_ia_na_t *ia_na = -+ (const grub_net_dhcpv6_opt_ia_na_t *)opt; -+ unsigned int left = len - OFFSET_OF (options, ia_na); -+ unsigned int j; -+ -+ if ((grub_uint8_t *)ia_na + left > -+ (grub_uint8_t *)options + option_max) -+ left -= ((grub_uint8_t *)ia_na + left) -+ - ((grub_uint8_t *)options + option_max); -+ -+ if (len < OFFSET_OF (option_data, opt) -+ + sizeof (grub_net_dhcpv6_option_t)) -+ { -+ grub_dprintf ("net", -+ "found dhcpv6 ia_na option with no address\n"); -+ continue; -+ } -+ -+ for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); ) -+ { -+ ia_na_opt = (const grub_net_dhcpv6_option_t *) -+ (ia_na->options + j); -+ grub_uint16_t ia_na_opt_num, ia_na_opt_len; -+ -+ ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num); -+ ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len); -+ if (ia_na_opt_len == 0) -+ break; -+ if (j + ia_na_opt_len > left) -+ break; -+ if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS) -+ { -+ const grub_net_dhcpv6_opt_ia_address_t *ia_addr; -+ -+ ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *) -+ ia_na_opt; -+ addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -+ grub_memcpy(addr.ipv6, ia_addr->ipv6_address, -+ sizeof (ia_addr->ipv6_address)); -+ inter = grub_net_add_addr (name, card, &addr, hwaddr, 0); -+ } -+ -+ j += ia_na_opt_len; -+ left -= ia_na_opt_len; -+ } -+ } -+ -+ i += len + 4; -+ } -+ -+ grub_print_error (); -+ } -+ -+ if (is_def) -+ { -+ grub_env_set ("net_default_interface", name); -+ grub_env_export ("net_default_interface"); -+ } -+ -+ if (inter) -+ grub_net_add_ipv6_local (inter, mask); -+ return inter; -+} -+ -+ - void - grub_bootp_init (void) - { -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index 5388f952ba..173fb63153 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -18,11 +18,14 @@ - - #include - #include -+#include - #include - #include - #include - #include - #include -+#include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -329,7 +332,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - char **path) - { - struct grub_net_card *card; -- grub_efi_device_path_t *dp; -+ grub_efi_device_path_t *dp, *ldp = NULL; - - dp = grub_efi_get_device_path (hnd); - if (! dp) -@@ -340,14 +343,19 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - grub_efi_device_path_t *cdp; - struct grub_efi_pxe *pxe; - struct grub_efi_pxe_mode *pxe_mode; -+ - if (card->driver != &efidriver) - continue; -+ - cdp = grub_efi_get_device_path (card->efi_handle); - if (! cdp) - continue; -+ -+ ldp = grub_efi_find_last_device_path (dp); -+ - if (grub_efi_compare_device_paths (dp, cdp) != 0) - { -- grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp; -+ grub_efi_device_path_t *dup_dp, *dup_ldp; - int match; - - /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6 -@@ -356,7 +364,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - devices. We skip them when enumerating cards, so here we need to - find matching MAC device. - */ -- ldp = grub_efi_find_last_device_path (dp); - if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE - || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE - && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) -@@ -373,16 +380,46 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - if (!match) - continue; - } -+ - pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, - GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (! pxe) - continue; -+ - pxe_mode = pxe->mode; -- grub_net_configure_by_dhcp_ack (card->name, card, 0, -- (struct grub_net_bootp_packet *) -- &pxe_mode->dhcp_ack, -- sizeof (pxe_mode->dhcp_ack), -- 1, device, path); -+ if (pxe_mode->using_ipv6) -+ { -+ grub_net_link_level_address_t hwaddr; -+ struct grub_net_network_level_interface *intf; -+ -+ grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); -+ grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", -+ pxe_mode->dhcp_ack_received ? "yes" : "no", -+ pxe_mode->dhcp_ack_received ? "" : " cannot continue"); -+ if (!pxe_mode->dhcp_ack_received) -+ continue; -+ -+ hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -+ grub_memcpy (hwaddr.mac, -+ card->efi_net->mode->current_address, -+ sizeof (hwaddr.mac)); -+ -+ intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr, -+ (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6, -+ 1, device, path); -+ if (intf && device && path) -+ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); -+ } -+ else -+ { -+ grub_dprintf ("efinet", "using ipv4 and dhcp\n"); -+ grub_net_configure_by_dhcp_ack (card->name, card, 0, -+ (struct grub_net_bootp_packet *) -+ &pxe_mode->dhcp_ack, -+ sizeof (pxe_mode->dhcp_ack), -+ 1, device, path); -+ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); -+ } - return; - } - } -diff --git a/grub-core/net/net.c b/grub-core/net/net.c -index 0ef148f4ad..22f2689aae 100644 ---- a/grub-core/net/net.c -+++ b/grub-core/net/net.c -@@ -960,6 +960,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa - grub_net_network_level_interfaces = inter; - } - -+int -+grub_ipv6_get_masksize (grub_uint16_t be_mask[8]) -+{ -+ grub_uint8_t *mask; -+ grub_uint16_t mask16[8]; -+ int x, y; -+ int ret = 128; -+ -+ grub_memcpy (mask16, be_mask, sizeof (mask16)); -+ for (x = 0; x < 8; x++) -+ mask16[x] = grub_be_to_cpu16 (mask16[x]); -+ -+ mask = (grub_uint8_t *)mask16; -+ -+ for (x = 15; x >= 0; x--) -+ { -+ grub_uint8_t octet = mask[x]; -+ if (!octet) -+ { -+ ret -= 8; -+ continue; -+ } -+ for (y = 0; y < 8; y++) -+ { -+ if (octet & (1 << y)) -+ break; -+ else -+ ret--; -+ } -+ break; -+ } -+ -+ return ret; -+} -+ -+grub_err_t -+grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter, -+ int mask) -+{ -+ struct grub_net_route *route; -+ -+ if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6) -+ return 0; -+ -+ if (mask == -1) -+ mask = grub_ipv6_get_masksize ((grub_uint16_t *)inter->address.ipv6); -+ -+ if (mask == -1) -+ return 0; -+ -+ route = grub_zalloc (sizeof (*route)); -+ if (!route) -+ return grub_errno; -+ -+ route->name = grub_xasprintf ("%s:local", inter->name); -+ if (!route->name) -+ { -+ grub_free (route); -+ return grub_errno; -+ } -+ -+ route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -+ grub_memcpy (route->target.ipv6.base, inter->address.ipv6, -+ sizeof (inter->address.ipv6)); -+ route->target.ipv6.masksize = mask; -+ route->is_gateway = 0; -+ route->interface = inter; -+ -+ grub_net_route_register (route); -+ -+ return 0; -+} - - grub_err_t - grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter, -diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c -index 7f44b30f52..4ab2f5c735 100644 ---- a/grub-core/net/tftp.c -+++ b/grub-core/net/tftp.c -@@ -358,18 +358,22 @@ tftp_open (struct grub_file *file, const char *filename) - file->not_easily_seekable = 1; - file->data = data; - -+ grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server); - err = grub_net_resolve_address (file->device->net->server, &addr); - if (err) - { -+ grub_dprintf("tftp", "Address resolution failed: %d\n", err); - grub_free (data); - return err; - } - -+ grub_dprintf("tftp", "opening connection\n"); - data->sock = grub_net_udp_open (addr, - TFTP_SERVER_PORT, tftp_receive, - file); - if (!data->sock) - { -+ grub_dprintf("tftp", "connection failed\n"); - grub_free (data); - return grub_errno; - } -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index f1a52210c0..117469450d 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -592,10 +592,16 @@ typedef void *grub_efi_handle_t; - typedef void *grub_efi_event_t; - typedef grub_efi_uint64_t grub_efi_lba_t; - typedef grub_efi_uintn_t grub_efi_tpl_t; --typedef grub_uint8_t grub_efi_mac_address_t[32]; --typedef grub_uint8_t grub_efi_ipv4_address_t[4]; --typedef grub_uint16_t grub_efi_ipv6_address_t[8]; --typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4))); -+typedef grub_efi_uint8_t grub_efi_mac_address_t[32]; -+typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4]; -+typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16]; -+typedef union -+{ -+ grub_efi_uint32_t addr[4]; -+ grub_efi_ipv4_address_t v4; -+ grub_efi_ipv6_address_t v6; -+} grub_efi_ip_address_t __attribute__ ((aligned(4))); -+ - typedef grub_efi_uint64_t grub_efi_physical_address_t; - typedef grub_efi_uint64_t grub_efi_virtual_address_t; - -@@ -1474,16 +1480,127 @@ struct grub_efi_simple_text_output_interface - }; - typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t; - --typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; -+typedef struct grub_efi_pxe_dhcpv4_packet -+{ -+ grub_efi_uint8_t bootp_opcode; -+ grub_efi_uint8_t bootp_hwtype; -+ grub_efi_uint8_t bootp_hwaddr_len; -+ grub_efi_uint8_t bootp_gate_hops; -+ grub_efi_uint32_t bootp_ident; -+ grub_efi_uint16_t bootp_seconds; -+ grub_efi_uint16_t bootp_flags; -+ grub_efi_uint8_t bootp_ci_addr[4]; -+ grub_efi_uint8_t bootp_yi_addr[4]; -+ grub_efi_uint8_t bootp_si_addr[4]; -+ grub_efi_uint8_t bootp_gi_addr[4]; -+ grub_efi_uint8_t bootp_hw_addr[16]; -+ grub_efi_uint8_t bootp_srv_name[64]; -+ grub_efi_uint8_t bootp_boot_file[128]; -+ grub_efi_uint32_t dhcp_magik; -+ grub_efi_uint8_t dhcp_options[56]; -+} grub_efi_pxe_dhcpv4_packet_t; -+ -+struct grub_efi_pxe_dhcpv6_packet -+{ -+ grub_efi_uint32_t message_type:8; -+ grub_efi_uint32_t transaction_id:24; -+ grub_efi_uint8_t dhcp_options[1024]; -+} GRUB_PACKED; -+typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t; -+ -+typedef union -+{ -+ grub_efi_uint8_t raw[1472]; -+ grub_efi_pxe_dhcpv4_packet_t dhcpv4; -+ grub_efi_pxe_dhcpv6_packet_t dhcpv6; -+} grub_efi_pxe_packet_t; -+ -+#define GRUB_EFI_PXE_MAX_IPCNT 8 -+#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8 -+#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8 -+ -+typedef struct grub_efi_pxe_ip_filter -+{ -+ grub_efi_uint8_t filters; -+ grub_efi_uint8_t ip_count; -+ grub_efi_uint8_t reserved; -+ grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; -+} grub_efi_pxe_ip_filter_t; -+ -+typedef struct grub_efi_pxe_arp_entry -+{ -+ grub_efi_ip_address_t ip_addr; -+ grub_efi_mac_address_t mac_addr; -+} grub_efi_pxe_arp_entry_t; -+ -+typedef struct grub_efi_pxe_route_entry -+{ -+ grub_efi_ip_address_t ip_addr; -+ grub_efi_ip_address_t subnet_mask; -+ grub_efi_ip_address_t gateway_addr; -+} grub_efi_pxe_route_entry_t; -+ -+typedef struct grub_efi_pxe_icmp_error -+{ -+ grub_efi_uint8_t type; -+ grub_efi_uint8_t code; -+ grub_efi_uint16_t checksum; -+ union -+ { -+ grub_efi_uint32_t reserved; -+ grub_efi_uint32_t mtu; -+ grub_efi_uint32_t pointer; -+ struct -+ { -+ grub_efi_uint16_t identifier; -+ grub_efi_uint16_t sequence; -+ } echo; -+ } u; -+ grub_efi_uint8_t data[494]; -+} grub_efi_pxe_icmp_error_t; -+ -+typedef struct grub_efi_pxe_tftp_error -+{ -+ grub_efi_uint8_t error_code; -+ grub_efi_char8_t error_string[127]; -+} grub_efi_pxe_tftp_error_t; - - typedef struct grub_efi_pxe_mode - { -- grub_uint8_t unused[52]; -+ grub_efi_boolean_t started; -+ grub_efi_boolean_t ipv6_available; -+ grub_efi_boolean_t ipv6_supported; -+ grub_efi_boolean_t using_ipv6; -+ grub_efi_boolean_t bis_supported; -+ grub_efi_boolean_t bis_detected; -+ grub_efi_boolean_t auto_arp; -+ grub_efi_boolean_t send_guid; -+ grub_efi_boolean_t dhcp_discover_valid; -+ grub_efi_boolean_t dhcp_ack_received; -+ grub_efi_boolean_t proxy_offer_received; -+ grub_efi_boolean_t pxe_discover_valid; -+ grub_efi_boolean_t pxe_reply_received; -+ grub_efi_boolean_t pxe_bis_reply_received; -+ grub_efi_boolean_t icmp_error_received; -+ grub_efi_boolean_t tftp_error_received; -+ grub_efi_boolean_t make_callbacks; -+ grub_efi_uint8_t ttl; -+ grub_efi_uint8_t tos; -+ grub_efi_ip_address_t station_ip; -+ grub_efi_ip_address_t subnet_mask; - grub_efi_pxe_packet_t dhcp_discover; - grub_efi_pxe_packet_t dhcp_ack; - grub_efi_pxe_packet_t proxy_offer; - grub_efi_pxe_packet_t pxe_discover; - grub_efi_pxe_packet_t pxe_reply; -+ grub_efi_pxe_packet_t pxe_bis_reply; -+ grub_efi_pxe_ip_filter_t ip_filter; -+ grub_efi_uint32_t arp_cache_entries; -+ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES]; -+ grub_efi_uint32_t route_table_entries; -+ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES]; -+ grub_efi_pxe_icmp_error_t icmp_error; -+ grub_efi_pxe_tftp_error_t tftp_error; - } grub_efi_pxe_mode_t; - - typedef struct grub_efi_pxe -diff --git a/include/grub/net.h b/include/grub/net.h -index 7ae4b6bd80..8a05ec4fe7 100644 ---- a/include/grub/net.h -+++ b/include/grub/net.h -@@ -447,6 +447,51 @@ struct grub_net_bootp_packet - grub_uint8_t vendor[0]; - } GRUB_PACKED; - -+enum -+ { -+ GRUB_NET_DHCP6_IA_NA = 3, -+ GRUB_NET_DHCP6_IA_ADDRESS = 5, -+ GRUB_NET_DHCP6_BOOTFILE_URL = 59, -+ }; -+ -+struct grub_net_dhcpv6_option -+{ -+ grub_uint16_t option_num; -+ grub_uint16_t option_len; -+ grub_uint8_t option_data[]; -+} GRUB_PACKED; -+typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t; -+ -+struct grub_net_dhcpv6_opt_ia_na -+{ -+ grub_uint16_t option_num; -+ grub_uint16_t option_len; -+ grub_uint32_t iaid; -+ grub_uint32_t t1; -+ grub_uint32_t t2; -+ grub_uint8_t options[]; -+} GRUB_PACKED; -+typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t; -+ -+struct grub_net_dhcpv6_opt_ia_address -+{ -+ grub_uint16_t option_num; -+ grub_uint16_t option_len; -+ grub_uint64_t ipv6_address[2]; -+ grub_uint32_t preferred_lifetime; -+ grub_uint32_t valid_lifetime; -+ grub_uint8_t options[]; -+} GRUB_PACKED; -+typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t; -+ -+struct grub_net_dhcpv6_packet -+{ -+ grub_uint32_t message_type:8; -+ grub_uint32_t transaction_id:24; -+ grub_uint8_t dhcp_options[1024]; -+} GRUB_PACKED; -+typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t; -+ - #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 - #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 - #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 -@@ -482,6 +527,21 @@ grub_net_configure_by_dhcp_ack (const char *name, - grub_size_t size, - int is_def, char **device, char **path); - -+struct grub_net_network_level_interface * -+grub_net_configure_by_dhcpv6_ack (const char *name, -+ struct grub_net_card *card, -+ grub_net_interface_flags_t flags, -+ const grub_net_link_level_address_t *hwaddr, -+ const struct grub_net_dhcpv6_packet *packet, -+ int is_def, char **device, char **path); -+ -+int -+grub_ipv6_get_masksize(grub_uint16_t *mask); -+ -+grub_err_t -+grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf, -+ int mask); -+ - grub_err_t - grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf, - int mask); diff --git a/0037-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch b/0037-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch deleted file mode 100644 index b3f5df4..0000000 --- a/0037-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch +++ /dev/null @@ -1,271 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 23 Jun 2016 11:01:39 -0400 -Subject: [PATCH] Add grub-get-kernel-settings and use it in 10_linux - -This patch adds grub-get-kernel-settings, which reads the system kernel -installation configuration from /etc/sysconfig/kernel, and outputs -${GRUB_...} variables suitable for evaluation by grub-mkconfig. Those -variables are then used by 10_linux to choose whether or not to create -debug stanzas. - -Resolves: rhbz#1226325 -[rharwood: migrate man page to h2m] ---- - configure.ac | 1 + - Makefile.util.def | 7 ++ - docs/man/grub-get-kernel-settings.h2m | 2 + - util/bash-completion.d/grub-completion.bash.in | 22 +++++++ - util/grub-get-kernel-settings.in | 88 ++++++++++++++++++++++++++ - util/grub-mkconfig.in | 3 + - util/grub.d/10_linux.in | 23 +++++-- - 7 files changed, 141 insertions(+), 5 deletions(-) - create mode 100644 docs/man/grub-get-kernel-settings.h2m - create mode 100644 util/grub-get-kernel-settings.in - -diff --git a/configure.ac b/configure.ac -index 916bede6bf..4f1676967e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -65,6 +65,7 @@ grub_TRANSFORM([grub-install]) - grub_TRANSFORM([grub-mkconfig]) - grub_TRANSFORM([grub-mkfont]) - grub_TRANSFORM([grub-mkimage]) -+grub_TRANSFORM([grub-get-kernel-settings]) - grub_TRANSFORM([grub-glue-efi]) - grub_TRANSFORM([grub-mklayout]) - grub_TRANSFORM([grub-mkpasswd-pbkdf2]) -diff --git a/Makefile.util.def b/Makefile.util.def -index 8ca4c14f0b..43a1c7453b 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -733,6 +733,13 @@ script = { - installdir = sbin; - }; - -+script = { -+ name = grub-get-kernel-settings; -+ common = util/grub-get-kernel-settings.in; -+ mansection = 3; -+ installdir = sbin; -+}; -+ - script = { - name = grub-set-default; - common = util/grub-set-default.in; -diff --git a/docs/man/grub-get-kernel-settings.h2m b/docs/man/grub-get-kernel-settings.h2m -new file mode 100644 -index 0000000000..b8051f01f3 ---- /dev/null -+++ b/docs/man/grub-get-kernel-settings.h2m -@@ -0,0 +1,2 @@ -+[NAME] -+grub-get-kernel-settings \- Evaluate the system's kernel installation settings for use while making a grub configuration file -diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in -index 44bf135b9f..5c4acd496d 100644 ---- a/util/bash-completion.d/grub-completion.bash.in -+++ b/util/bash-completion.d/grub-completion.bash.in -@@ -264,6 +264,28 @@ have ${__grub_sparc64_setup_program} && \ - unset __grub_sparc64_setup_program - - -+# -+# grub-get-kernel-settings -+# -+_grub_get_kernel_settings () { -+ local cur -+ -+ COMPREPLY=() -+ cur=`_get_cword` -+ -+ if [[ "$cur" == -* ]]; then -+ __grubcomp "$(__grub_get_options_from_help)" -+ else -+ # Default complete with a filename -+ _filedir -+ fi -+} -+__grub_get_kernel_settings_program="@grub_get_kernel_settings@" -+have ${__grub_get_kernel_settings_program} && \ -+ complete -F _grub_get_kernel_settings -o filenames ${__grub_get_kernel_settings_program} -+unset __grub_get_kernel_settings_program -+ -+ - # - # grub-install - # -diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in -new file mode 100644 -index 0000000000..7e87dfccc0 ---- /dev/null -+++ b/util/grub-get-kernel-settings.in -@@ -0,0 +1,88 @@ -+#!/bin/sh -+set -e -+ -+# Evaluate new-kernel-pkg's configuration file. -+# Copyright (C) 2016 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 . -+ -+PACKAGE_NAME=@PACKAGE_NAME@ -+PACKAGE_VERSION=@PACKAGE_VERSION@ -+datadir="@datadir@" -+if [ "x$pkgdatadir" = x ]; then -+ pkgdatadir="${datadir}/@PACKAGE@" -+fi -+ -+self=`basename $0` -+ -+export TEXTDOMAIN=@PACKAGE@ -+export TEXTDOMAINDIR="@localedir@" -+ -+. "${pkgdatadir}/grub-mkconfig_lib" -+ -+# Usage: usage -+# Print the usage. -+usage () { -+ gettext_printf "Usage: %s [OPTION]\n" "$self" -+ gettext "Evaluate new-kernel-pkg configuration"; echo -+ echo -+ print_option_help "-h, --help" "$(gettext "print this message and exit")" -+ print_option_help "-v, --version" "$(gettext "print the version information and exit")" -+ echo -+} -+ -+# Check the arguments. -+while test $# -gt 0 -+do -+ option=$1 -+ shift -+ -+ case "$option" in -+ -h | --help) -+ usage -+ exit 0 ;; -+ -v | --version) -+ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" -+ exit 0 ;; -+ -*) -+ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 -+ usage -+ exit 1 -+ ;; -+ # Explicitly ignore non-option arguments, for compatibility. -+ esac -+done -+ -+if test -f /etc/sysconfig/kernel ; then -+ . /etc/sysconfig/kernel -+fi -+ -+if [ "$MAKEDEBUG" = "yes" ]; then -+ echo GRUB_LINUX_MAKE_DEBUG=true -+ echo export GRUB_LINUX_MAKE_DEBUG -+ echo GRUB_CMDLINE_LINUX_DEBUG=\"systemd.log_level=debug systemd.log_target=kmsg\" -+ echo export GRUB_CMDLINE_LINUX_DEBUG -+ echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\" -+ echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX -+fi -+if [ "$DEFAULTDEBUG" = "yes" ]; then -+ echo GRUB_DEFAULT_TO_DEBUG=true -+else -+ echo GRUB_DEFAULT_TO_DEBUG=false -+fi -+echo export GRUB_DEFAULT_TO_DEBUG -+if [ "$UPDATEDEFAULT" = "yes" ]; then -+ echo GRUB_UPDATE_DEFAULT_KERNEL=true -+ echo export GRUB_UPDATE_DEFAULT_KERNEL -+fi -diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in -index ba14cf6261..005f093809 100644 ---- a/util/grub-mkconfig.in -+++ b/util/grub-mkconfig.in -@@ -45,6 +45,7 @@ grub_probe="${sbindir}/@grub_probe@" - grub_file="${bindir}/@grub_file@" - grub_editenv="${bindir}/@grub_editenv@" - grub_script_check="${bindir}/@grub_script_check@" -+grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" - - export TEXTDOMAIN=@PACKAGE@ - export TEXTDOMAINDIR="@localedir@" -@@ -158,6 +159,8 @@ if test -f ${sysconfdir}/default/grub ; then - . ${sysconfdir}/default/grub - fi - -+eval "$("${grub_get_kernel_settings}")" || true -+ - if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then - if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then - GRUB_DISABLE_LINUX_UUID="true" -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index 786dbabb4a..292e333324 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -111,7 +111,8 @@ linux_entry () - os="$1" - version="$2" - type="$3" -- args="$4" -+ isdebug="$4" -+ args="$5" - - if [ -z "$boot_device_id" ]; then - boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" -@@ -123,6 +124,9 @@ linux_entry () - quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" - title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" - fi -+ if [ x$isdebug = xdebug ]; then -+ title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}" -+ fi - echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" - else - echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" -@@ -306,11 +310,15 @@ while [ "x$list" != "x" ] ; do - fi - - if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then -- linux_entry "${OS}" "${version}" simple \ -+ linux_entry "${OS}" "${version}" simple standard \ - "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" -+ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then -+ linux_entry "${OS}" "${version}" simple debug \ -+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" -+ fi - - submenu_indentation="$grub_tab" -- -+ - if [ -z "$boot_device_id" ]; then - boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" - fi -@@ -319,10 +327,15 @@ while [ "x$list" != "x" ] ; do - is_top_level=false - fi - -- linux_entry "${OS}" "${version}" advanced \ -+ linux_entry "${OS}" "${version}" advanced standard \ - "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" -+ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then -+ linux_entry "${OS}" "${version}" advanced debug \ -+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" -+ fi -+ - if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then -- linux_entry "${OS}" "${version}" recovery \ -+ linux_entry "${OS}" "${version}" recovery standard \ - "single ${GRUB_CMDLINE_LINUX}" - fi - diff --git a/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch b/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch new file mode 100644 index 0000000..15b2111 --- /dev/null +++ b/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Masahiro Matsuya +Date: Sat, 29 Oct 2016 08:35:26 +0900 +Subject: [PATCH] bz1374141 fix incorrect mask for ppc64 + +The netmask configured in firmware is not respected on ppc64 (big endian). +When 255.255.252.0 is set as netmask in firmware, the following is the value of bootpath string in grub_ieee1275_parse_bootpath(). + + /vdevice/l-lan@30000002:speed=auto,duplex=auto,192.168.88.10,,192.168.89.113,192.168.88.1,5,5,255.255.252.0,512 + +The netmask in this bootpath is no problem, since it's a value specified in firmware. But, +The value of 'subnet_mask.ipv4' was set with 0xfffffc00, and __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)) returned 16 (not 22). +As a result, 16 was used for netmask wrongly. + +1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) +0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) +1111 1111 0000 0011 0000 0000 0000 0000 # ~grub_le_to_cpu32 (subnet_mask.ipv4) + +And, the count of zero with __builtin_ctz can be 16. +This patch changes it as below. + +1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) +0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) +1111 1111 1111 1111 1111 1100 0000 0000 # grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) +0000 0000 0000 0000 0000 0011 1111 1111 # ~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) + +The count of zero with __builtin_clz can be 22. (clz counts the number of one bits preceding the most significant zero bit) + +Signed-off-by: Masahiro Matsuya +Signed-off-by: Robbie Harwood +--- + grub-core/net/drivers/ieee1275/ofnet.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c +index ac4e62a95c..3860b6f78d 100644 +--- a/grub-core/net/drivers/ieee1275/ofnet.c ++++ b/grub-core/net/drivers/ieee1275/ofnet.c +@@ -220,8 +220,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, + flags); + inter->vlantag = vlantag; + grub_net_add_ipv4_local (inter, +- __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4))); +- ++ __builtin_clz (~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)))); + } + + if (gateway_addr.ipv4 != 0) diff --git a/0038-Make-grub_fatal-also-backtrace.patch b/0038-Make-grub_fatal-also-backtrace.patch new file mode 100644 index 0000000..f876575 --- /dev/null +++ b/0038-Make-grub_fatal-also-backtrace.patch @@ -0,0 +1,172 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 27 Jan 2016 09:22:42 -0500 +Subject: [PATCH] Make grub_fatal() also backtrace. + +--- + grub-core/Makefile.core.def | 3 ++ + grub-core/kern/misc.c | 8 +++++- + grub-core/lib/arm64/backtrace.c | 62 +++++++++++++++++++++++++++++++++++++++++ + grub-core/lib/backtrace.c | 2 ++ + grub-core/lib/i386/backtrace.c | 14 +++++++++- + 5 files changed, 87 insertions(+), 2 deletions(-) + create mode 100644 grub-core/lib/arm64/backtrace.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index c15e91943b..058c88ac3a 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -188,6 +188,9 @@ kernel = { + + softdiv = lib/division.c; + ++ x86 = lib/i386/backtrace.c; ++ x86 = lib/backtrace.c; ++ + i386 = kern/i386/dl.c; + i386_xen = kern/i386/dl.c; + i386_xen_pvh = kern/i386/dl.c; +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 63b586d09c..a3e215155b 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + union printf_arg + { +@@ -1199,8 +1200,13 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) + static void __attribute__ ((noreturn)) + grub_abort (void) + { ++#ifndef GRUB_UTIL ++#if defined(__i386__) || defined(__x86_64__) ++ grub_backtrace(); ++#endif ++#endif + grub_printf ("\nAborted."); +- ++ + #ifndef GRUB_UTIL + if (grub_term_inputs) + #endif +diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c +new file mode 100644 +index 0000000000..1079b5380e +--- /dev/null ++++ b/grub-core/lib/arm64/backtrace.c +@@ -0,0 +1,62 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++void ++grub_backtrace_pointer (int frame) ++{ ++ while (1) ++ { ++ void *lp = __builtin_return_address (frame); ++ if (!lp) ++ break; ++ ++ lp = __builtin_extract_return_addr (lp); ++ ++ grub_printf ("%p: ", lp); ++ grub_backtrace_print_address (lp); ++ grub_printf (" ("); ++ for (i = 0; i < 2; i++) ++ grub_printf ("%p,", ((void **)ptr) [i + 2]); ++ grub_printf ("%p)\n", ((void **)ptr) [i + 2]); ++ nptr = *(void **)ptr; ++ if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME ++ || nptr == ptr) ++ { ++ grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); ++ break; ++ } ++ ptr = nptr; ++ } ++} ++ ++void ++grub_backtrace (void) ++{ ++ grub_backtrace_pointer (1); ++} ++ +diff --git a/grub-core/lib/backtrace.c b/grub-core/lib/backtrace.c +index 825a8800e2..c0ad6ab8be 100644 +--- a/grub-core/lib/backtrace.c ++++ b/grub-core/lib/backtrace.c +@@ -29,6 +29,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + void + grub_backtrace_print_address (void *addr) + { ++#ifndef GRUB_UTIL + grub_dl_t mod; + + FOR_DL_MODULES (mod) +@@ -44,6 +45,7 @@ grub_backtrace_print_address (void *addr) + } + } + ++#endif + grub_printf ("%p", addr); + } + +diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c +index c3e03c7275..c67273db3a 100644 +--- a/grub-core/lib/i386/backtrace.c ++++ b/grub-core/lib/i386/backtrace.c +@@ -15,11 +15,23 @@ + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ ++#include ++#ifdef GRUB_UTIL ++#define REALLY_GRUB_UTIL GRUB_UTIL ++#undef GRUB_UTIL ++#endif ++ ++#include ++#include ++ ++#ifdef REALLY_GRUB_UTIL ++#define GRUB_UTIL REALLY_GRUB_UTIL ++#undef REALLY_GRUB_UTIL ++#endif + + #include + #include + #include +-#include + #include + #include + #include diff --git a/0038-bz1374141-fix-incorrect-mask-for-ppc64.patch b/0038-bz1374141-fix-incorrect-mask-for-ppc64.patch deleted file mode 100644 index 15b2111..0000000 --- a/0038-bz1374141-fix-incorrect-mask-for-ppc64.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Masahiro Matsuya -Date: Sat, 29 Oct 2016 08:35:26 +0900 -Subject: [PATCH] bz1374141 fix incorrect mask for ppc64 - -The netmask configured in firmware is not respected on ppc64 (big endian). -When 255.255.252.0 is set as netmask in firmware, the following is the value of bootpath string in grub_ieee1275_parse_bootpath(). - - /vdevice/l-lan@30000002:speed=auto,duplex=auto,192.168.88.10,,192.168.89.113,192.168.88.1,5,5,255.255.252.0,512 - -The netmask in this bootpath is no problem, since it's a value specified in firmware. But, -The value of 'subnet_mask.ipv4' was set with 0xfffffc00, and __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)) returned 16 (not 22). -As a result, 16 was used for netmask wrongly. - -1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) -0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) -1111 1111 0000 0011 0000 0000 0000 0000 # ~grub_le_to_cpu32 (subnet_mask.ipv4) - -And, the count of zero with __builtin_ctz can be 16. -This patch changes it as below. - -1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) -0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) -1111 1111 1111 1111 1111 1100 0000 0000 # grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) -0000 0000 0000 0000 0000 0011 1111 1111 # ~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) - -The count of zero with __builtin_clz can be 22. (clz counts the number of one bits preceding the most significant zero bit) - -Signed-off-by: Masahiro Matsuya -Signed-off-by: Robbie Harwood ---- - grub-core/net/drivers/ieee1275/ofnet.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c -index ac4e62a95c..3860b6f78d 100644 ---- a/grub-core/net/drivers/ieee1275/ofnet.c -+++ b/grub-core/net/drivers/ieee1275/ofnet.c -@@ -220,8 +220,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, - flags); - inter->vlantag = vlantag; - grub_net_add_ipv4_local (inter, -- __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4))); -- -+ __builtin_clz (~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)))); - } - - if (gateway_addr.ipv4 != 0) diff --git a/0039-Make-grub_fatal-also-backtrace.patch b/0039-Make-grub_fatal-also-backtrace.patch deleted file mode 100644 index f876575..0000000 --- a/0039-Make-grub_fatal-also-backtrace.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 27 Jan 2016 09:22:42 -0500 -Subject: [PATCH] Make grub_fatal() also backtrace. - ---- - grub-core/Makefile.core.def | 3 ++ - grub-core/kern/misc.c | 8 +++++- - grub-core/lib/arm64/backtrace.c | 62 +++++++++++++++++++++++++++++++++++++++++ - grub-core/lib/backtrace.c | 2 ++ - grub-core/lib/i386/backtrace.c | 14 +++++++++- - 5 files changed, 87 insertions(+), 2 deletions(-) - create mode 100644 grub-core/lib/arm64/backtrace.c - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index c15e91943b..058c88ac3a 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -188,6 +188,9 @@ kernel = { - - softdiv = lib/division.c; - -+ x86 = lib/i386/backtrace.c; -+ x86 = lib/backtrace.c; -+ - i386 = kern/i386/dl.c; - i386_xen = kern/i386/dl.c; - i386_xen_pvh = kern/i386/dl.c; -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index 63b586d09c..a3e215155b 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - - union printf_arg - { -@@ -1199,8 +1200,13 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) - static void __attribute__ ((noreturn)) - grub_abort (void) - { -+#ifndef GRUB_UTIL -+#if defined(__i386__) || defined(__x86_64__) -+ grub_backtrace(); -+#endif -+#endif - grub_printf ("\nAborted."); -- -+ - #ifndef GRUB_UTIL - if (grub_term_inputs) - #endif -diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c -new file mode 100644 -index 0000000000..1079b5380e ---- /dev/null -+++ b/grub-core/lib/arm64/backtrace.c -@@ -0,0 +1,62 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MAX_STACK_FRAME 102400 -+ -+void -+grub_backtrace_pointer (int frame) -+{ -+ while (1) -+ { -+ void *lp = __builtin_return_address (frame); -+ if (!lp) -+ break; -+ -+ lp = __builtin_extract_return_addr (lp); -+ -+ grub_printf ("%p: ", lp); -+ grub_backtrace_print_address (lp); -+ grub_printf (" ("); -+ for (i = 0; i < 2; i++) -+ grub_printf ("%p,", ((void **)ptr) [i + 2]); -+ grub_printf ("%p)\n", ((void **)ptr) [i + 2]); -+ nptr = *(void **)ptr; -+ if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME -+ || nptr == ptr) -+ { -+ grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); -+ break; -+ } -+ ptr = nptr; -+ } -+} -+ -+void -+grub_backtrace (void) -+{ -+ grub_backtrace_pointer (1); -+} -+ -diff --git a/grub-core/lib/backtrace.c b/grub-core/lib/backtrace.c -index 825a8800e2..c0ad6ab8be 100644 ---- a/grub-core/lib/backtrace.c -+++ b/grub-core/lib/backtrace.c -@@ -29,6 +29,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); - void - grub_backtrace_print_address (void *addr) - { -+#ifndef GRUB_UTIL - grub_dl_t mod; - - FOR_DL_MODULES (mod) -@@ -44,6 +45,7 @@ grub_backtrace_print_address (void *addr) - } - } - -+#endif - grub_printf ("%p", addr); - } - -diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c -index c3e03c7275..c67273db3a 100644 ---- a/grub-core/lib/i386/backtrace.c -+++ b/grub-core/lib/i386/backtrace.c -@@ -15,11 +15,23 @@ - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ -+#include -+#ifdef GRUB_UTIL -+#define REALLY_GRUB_UTIL GRUB_UTIL -+#undef GRUB_UTIL -+#endif -+ -+#include -+#include -+ -+#ifdef REALLY_GRUB_UTIL -+#define GRUB_UTIL REALLY_GRUB_UTIL -+#undef REALLY_GRUB_UTIL -+#endif - - #include - #include - #include --#include - #include - #include - #include diff --git a/0039-Make-our-info-pages-say-grub2-where-appropriate.patch b/0039-Make-our-info-pages-say-grub2-where-appropriate.patch new file mode 100644 index 0000000..afba285 --- /dev/null +++ b/0039-Make-our-info-pages-say-grub2-where-appropriate.patch @@ -0,0 +1,1008 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 12:59:58 +0200 +Subject: [PATCH] Make our info pages say "grub2" where appropriate. + +This needs to be hooked up to --program-transform=, but I haven't had +time. + +Signed-off-by: Peter Jones +--- + docs/grub-dev.texi | 4 +- + docs/grub.texi | 321 ++++++++++++++++++++++++++++------------------------- + 2 files changed, 171 insertions(+), 154 deletions(-) + +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 6c629a23e2..19f708ee66 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -1,7 +1,7 @@ + \input texinfo + @c -*-texinfo-*- + @c %**start of header +-@setfilename grub-dev.info ++@setfilename grub2-dev.info + @include version-dev.texi + @settitle GNU GRUB Developers Manual @value{VERSION} + @c Unify all our little indices for now. +@@ -32,7 +32,7 @@ Invariant Sections. + + @dircategory Kernel + @direntry +-* grub-dev: (grub-dev). The GRand Unified Bootloader Dev ++* grub2-dev: (grub2-dev). The GRand Unified Bootloader Dev + @end direntry + + @setchapternewpage odd +diff --git a/docs/grub.texi b/docs/grub.texi +index 69f08d289f..0615d0ed97 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -1,7 +1,7 @@ + \input texinfo + @c -*-texinfo-*- + @c %**start of header +-@setfilename grub.info ++@setfilename grub2.info + @include version.texi + @settitle GNU GRUB Manual @value{VERSION} + @c Unify all our little indices for now. +@@ -32,15 +32,15 @@ Invariant Sections. + + @dircategory Kernel + @direntry +-* GRUB: (grub). The GRand Unified Bootloader +-* grub-install: (grub)Invoking grub-install. Install GRUB on your drive +-* grub-mkconfig: (grub)Invoking grub-mkconfig. Generate GRUB configuration +-* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2. +-* grub-mkrelpath: (grub)Invoking grub-mkrelpath. +-* grub-mkrescue: (grub)Invoking grub-mkrescue. Make a GRUB rescue image +-* grub-mount: (grub)Invoking grub-mount. Mount a file system using GRUB +-* grub-probe: (grub)Invoking grub-probe. Probe device information +-* grub-script-check: (grub)Invoking grub-script-check. ++* GRUB2: (grub2). The GRand Unified Bootloader ++* grub2-install: (grub2)Invoking grub2-install. Install GRUB on your drive ++* grub2-mkconfig: (grub2)Invoking grub2-mkconfig. Generate GRUB configuration ++* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2. ++* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath. ++* grub2-mkrescue: (grub2)Invoking grub2-mkrescue. Make a GRUB rescue image ++* grub2-mount: (grub2)Invoking grub2-mount. Mount a file system using GRUB ++* grub2-probe: (grub2)Invoking grub2-probe. Probe device information ++* grub2-script-check: (grub2)Invoking grub2-script-check. + @end direntry + + @setchapternewpage odd +@@ -103,15 +103,15 @@ This edition documents version @value{VERSION}. + * Platform-specific operations:: Platform-specific operations + * Supported kernels:: The list of supported kernels + * Troubleshooting:: Error messages produced by GRUB +-* Invoking grub-install:: How to use the GRUB installer +-* Invoking grub-mkconfig:: Generate a GRUB configuration file +-* Invoking grub-mkpasswd-pbkdf2:: ++* Invoking grub2-install:: How to use the GRUB installer ++* Invoking grub2-mkconfig:: Generate a GRUB configuration file ++* Invoking grub2-mkpasswd-pbkdf2:: + Generate GRUB password hashes +-* Invoking grub-mkrelpath:: Make system path relative to its root +-* Invoking grub-mkrescue:: Make a GRUB rescue image +-* Invoking grub-mount:: Mount a file system using GRUB +-* Invoking grub-probe:: Probe device information for GRUB +-* Invoking grub-script-check:: Check GRUB script file for syntax errors ++* Invoking grub2-mkrelpath:: Make system path relative to its root ++* Invoking grub2-mkrescue:: Make a GRUB rescue image ++* Invoking grub2-mount:: Mount a file system using GRUB ++* Invoking grub2-probe:: Probe device information for GRUB ++* Invoking grub2-script-check:: Check GRUB script file for syntax errors + * Obtaining and Building GRUB:: How to obtain and build GRUB + * Reporting bugs:: Where you should send a bug report + * Future:: Some future plans on GRUB +@@ -230,7 +230,7 @@ surprising. + + @item + @file{grub.cfg} is typically automatically generated by +-@command{grub-mkconfig} (@pxref{Simple configuration}). This makes it ++@command{grub2-mkconfig} (@pxref{Simple configuration}). This makes it + easier to handle versioned kernel upgrades. + + @item +@@ -244,7 +244,7 @@ scripting language: variables, conditionals, and loops are available. + @item + A small amount of persistent storage is available across reboots, using the + @command{save_env} and @command{load_env} commands in GRUB and the +-@command{grub-editenv} utility. This is not available in all configurations ++@command{grub2-editenv} utility. This is not available in all configurations + (@pxref{Environment block}). + + @item +@@ -549,7 +549,7 @@ On OS which have device nodes similar to Unix-like OS GRUB tools use the + OS name. E.g. for GNU/Linux: + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + On AROS we use another syntax. For volumes: +@@ -572,7 +572,7 @@ For disks we use syntax: + E.g. + + @example +-# @kbd{grub-install //:ata.device/0/0} ++# @kbd{grub2-install //:ata.device/0/0} + @end example + + On Windows we use UNC path. For volumes it's typically +@@ -599,7 +599,7 @@ For disks it's + E.g. + + @example +-# @kbd{grub-install \\?\PhysicalDrive0} ++# @kbd{grub2-install \\?\PhysicalDrive0} + @end example + + Beware that you may need to further escape the backslashes depending on your +@@ -609,7 +609,7 @@ When compiled with cygwin support then cygwin drive names are automatically + when needed. E.g. + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + @node Installation +@@ -622,7 +622,7 @@ from the source tarball, or as a package for your OS. + + After you have done that, you need to install the boot loader on a + drive (floppy or hard disk) by using the utility +-@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS. ++@command{grub2-install} (@pxref{Invoking grub2-install}) on a UNIX-like OS. + + GRUB comes with boot images, which are normally put in the directory + @file{/usr/lib/grub/-} (for BIOS-based machines +@@ -633,22 +633,22 @@ loader needs to find them (usually @file{/boot}) will be called + the @dfn{boot directory}. + + @menu +-* Installing GRUB using grub-install:: ++* Installing GRUB using grub2-install:: + * Making a GRUB bootable CD-ROM:: + * Device map:: + * BIOS installation:: + @end menu + + +-@node Installing GRUB using grub-install +-@section Installing GRUB using grub-install ++@node Installing GRUB using grub2-install ++@section Installing GRUB using grub2-install + + For information on where GRUB should be installed on PC BIOS platforms, + @pxref{BIOS installation}. + + In order to install GRUB under a UNIX-like OS (such +-as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking +-grub-install}) as the superuser (@dfn{root}). ++as @sc{gnu}), invoke the program @command{grub2-install} (@pxref{Invoking ++grub2-install}) as the superuser (@dfn{root}). + + The usage is basically very simple. You only need to specify one + argument to the program, namely, where to install the boot loader. The +@@ -657,13 +657,13 @@ For example, under Linux the following will install GRUB into the MBR + of the first IDE disk: + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + Likewise, under GNU/Hurd, this has the same effect: + + @example +-# @kbd{grub-install /dev/hd0} ++# @kbd{grub2-install /dev/hd0} + @end example + + But all the above examples assume that GRUB should put images under +@@ -677,7 +677,7 @@ boot floppy with a filesystem. Here is an example: + # @kbd{mke2fs /dev/fd0} + # @kbd{mount -t ext2 /dev/fd0 /mnt} + # @kbd{mkdir /mnt/boot} +-# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0} ++# @kbd{grub2-install --boot-directory=/mnt/boot /dev/fd0} + # @kbd{umount /mnt} + @end group + @end example +@@ -689,30 +689,37 @@ floppy instead of exposing the USB drive as a hard disk (they call it + @example + # @kbd{losetup /dev/loop0 /dev/sdb1} + # @kbd{mount /dev/loop0 /mnt/usb} +-# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} ++# @kbd{grub2-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} + @end example + + 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: + + @example +-# @kbd{grub-install} ++# @kbd{grub2-install} + @end example + + Otherwise you need to specify where your EFI System partition is mounted: + + @example +-# @kbd{grub-install --efi-directory=/mnt/efi} ++# @kbd{grub2-install --efi-directory=/mnt/efi} + @end example + + For removable installs you have to use @option{--removable} and specify both + @option{--boot-directory} and @option{--efi-directory}: + + @example +-# @kbd{grub-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} ++# @kbd{grub2-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} + @end example + + @node Making a GRUB bootable CD-ROM +@@ -732,10 +739,10 @@ usually also need to include a configuration file @file{grub.cfg} and some + other GRUB modules. + + To make a simple generic GRUB rescue CD, you can use the +-@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}): ++@command{grub2-mkrescue} program (@pxref{Invoking grub2-mkrescue}): + + @example +-$ @kbd{grub-mkrescue -o grub.iso} ++$ @kbd{grub2-mkrescue -o grub.iso} + @end example + + You will often need to include other files in your image. To do this, first +@@ -758,7 +765,7 @@ directory @file{iso/}. + Finally, make the image: + + @example +-$ @kbd{grub-mkrescue -o grub.iso iso} ++$ @kbd{grub2-mkrescue -o grub.iso iso} + @end example + + This produces a file named @file{grub.iso}, which then can be burned +@@ -774,7 +781,7 @@ storage devices. + @node Device map + @section The map between BIOS drives and OS devices + +-If the device map file exists, the GRUB utilities (@command{grub-probe}, ++If the device map file exists, the GRUB utilities (@command{grub2-probe}, + etc.) read it to map BIOS drives to OS devices. This file consists of lines + like this: + +@@ -1254,23 +1261,23 @@ need to write the whole thing by hand. + @node Simple configuration + @section Simple configuration handling + +-The program @command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}) ++The program @command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}) + generates @file{grub.cfg} files suitable for most cases. It is suitable for + use when upgrading a distribution, and will discover available kernels and + attempt to generate menu entries for them. + +-@command{grub-mkconfig} does have some limitations. While adding extra ++@command{grub2-mkconfig} does have some limitations. While adding extra + custom menu entries to the end of the list can be done by editing +-@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg}, ++@file{/etc/grub.d/40_custom} or creating @file{/boot/grub2/custom.cfg}, + changing the order of menu entries or changing their titles may require + making complex changes to shell scripts stored in @file{/etc/grub.d/}. This + may be improved in the future. In the meantime, those who feel that it + would be easier to write @file{grub.cfg} directly are encouraged to do so + (@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system +-provided by their distribution to automatically run @command{grub-mkconfig}. ++provided by their distribution to automatically run @command{grub2-mkconfig}. + + The file @file{/etc/default/grub} controls the operation of +-@command{grub-mkconfig}. It is sourced by a shell script, and so must be ++@command{grub2-mkconfig}. It is sourced by a shell script, and so must be + valid POSIX shell input; normally, it will just be a sequence of + @samp{KEY=value} lines, but if the value contains spaces or other special + characters then it must be quoted. For example: +@@ -1308,7 +1315,7 @@ works it's not recommended since titles often contain unstable device names + and may be translated + + If you set this to @samp{saved}, then the default menu entry will be that +-saved by @samp{GRUB_SAVEDEFAULT} or @command{grub-set-default}. This relies on ++saved by @samp{GRUB_SAVEDEFAULT} or @command{grub2-set-default}. This relies on + the environment block, which may not be available in all situations + (@pxref{Environment block}). + +@@ -1319,7 +1326,7 @@ If this option is set to @samp{true}, then, when an entry is selected, save + it as a new default entry for use by future runs of GRUB. This is only + useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because + @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with +-@command{grub-set-default}. Unset by default. ++@command{grub2-set-default}. Unset by default. + This option relies on the environment block, which may not be available in + all situations (@pxref{Environment block}). + +@@ -1449,7 +1456,7 @@ intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode + @end example + + @item GRUB_DISABLE_LINUX_UUID +-Normally, @command{grub-mkconfig} will generate menu entries that use ++Normally, @command{grub2-mkconfig} will generate menu entries that use + universally-unique identifiers (UUIDs) to identify the root filesystem to + the Linux kernel, using a @samp{root=UUID=...} kernel parameter. This is + usually more reliable, but in some cases it may not be appropriate. To +@@ -1471,7 +1478,7 @@ If this option is set to @samp{true}, disable the generation of recovery + mode menu entries. + + @item GRUB_DISABLE_UUID +-Normally, @command{grub-mkconfig} will generate menu entries that use ++Normally, @command{grub2-mkconfig} will generate menu entries that use + universally-unique identifiers (UUIDs) to identify various filesystems to + search for files. This is usually more reliable, but in some cases it may + not be appropriate. To disable this use of UUIDs, set this option to +@@ -1482,12 +1489,12 @@ not be appropriate. To disable this use of UUIDs, set this option to + @item GRUB_VIDEO_BACKEND + If graphical video support is required, either because the @samp{gfxterm} + graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set, +-then @command{grub-mkconfig} will normally load all available GRUB video ++then @command{grub2-mkconfig} will normally load all available GRUB video + drivers and use the one most appropriate for your hardware. If you need to + override this for some reason, then you can set this option. + +-After @command{grub-install} has been run, the available video drivers are +-listed in @file{/boot/grub/video.lst}. ++After @command{grub2-install} has been run, the available video drivers are ++listed in @file{/boot/grub2/video.lst}. + + @item GRUB_GFXMODE + Set the resolution used on the @samp{gfxterm} graphical terminal. Note that +@@ -1519,7 +1526,7 @@ boot sequence. If you have problems, set this option to @samp{text} and + GRUB will tell Linux to boot in normal text mode. + + @item GRUB_DISABLE_OS_PROBER +-Normally, @command{grub-mkconfig} will try to use the external ++Normally, @command{grub2-mkconfig} will try to use the external + @command{os-prober} program, if installed, to discover other operating + systems installed on the same system and generate appropriate menu entries + for them. Set this option to @samp{true} to disable this. +@@ -1529,7 +1536,7 @@ List of space-separated FS UUIDs of filesystems to be ignored from os-prober + output. For efi chainloaders it's @@ + + @item GRUB_DISABLE_SUBMENU +-Normally, @command{grub-mkconfig} will generate top level menu entry for ++Normally, @command{grub2-mkconfig} will generate top level menu entry for + the kernel with highest version number and put all other found kernels + or alternative menu entries for recovery mode in submenu. For entries returned + by @command{os-prober} first entry will be put on top level and all others +@@ -1537,11 +1544,11 @@ in submenu. If this option is set to @samp{true}, flat menu with all entries + on top level will be generated instead. Changing this option will require + changing existing values of @samp{GRUB_DEFAULT}, @samp{fallback} (@pxref{fallback}) + and @samp{default} (@pxref{default}) environment variables as well as saved +-default entry using @command{grub-set-default} and value used with +-@command{grub-reboot}. ++default entry using @command{grub2-set-default} and value used with ++@command{grub2-reboot}. + + @item GRUB_ENABLE_CRYPTODISK +-If set to @samp{y}, @command{grub-mkconfig} and @command{grub-install} will ++If set to @samp{y}, @command{grub2-mkconfig} and @command{grub2-install} will + check for encrypted disks and generate additional commands needed to access + them during boot. Note that in this case unattended boot is not possible + because GRUB will wait for passphrase to unlock encrypted container. +@@ -1600,7 +1607,7 @@ confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or + + @end table + +-For more detailed customisation of @command{grub-mkconfig}'s output, you may ++For more detailed customisation of @command{grub2-mkconfig}'s output, you may + edit the scripts in @file{/etc/grub.d} directly. + @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom + menu entries; simply type the menu entries you want to add at the end of +@@ -1862,7 +1869,7 @@ images as well. + Mount this partition on/mnt/boot and disable GRUB in all OSes and manually + install self-compiled latest GRUB with: + +-@code{grub-install --boot-directory=/mnt/boot /dev/sda} ++@code{grub2-install --boot-directory=/mnt/boot /dev/sda} + + In all the OSes install GRUB tools but disable installing GRUB in bootsector, + so you'll have menu.lst and grub.cfg available for use. Also disable os-prober +@@ -1872,20 +1879,20 @@ use by setting: + + in /etc/default/grub + +-Then write a grub.cfg (/mnt/boot/grub/grub.cfg): ++Then write a grub.cfg (/mnt/boot/grub2/grub.cfg): + + @example + + menuentry "OS using grub2" @{ + insmod xfs + search --set=root --label OS1 --hint hd0,msdos8 +- configfile /boot/grub/grub.cfg ++ configfile /boot/grub2/grub.cfg + @} + + menuentry "OS using grub2-legacy" @{ + insmod ext2 + search --set=root --label OS2 --hint hd0,msdos6 +- legacy_configfile /boot/grub/menu.lst ++ legacy_configfile /boot/grub2/menu.lst + @} + + menuentry "Windows XP" @{ +@@ -1948,15 +1955,15 @@ GRUB supports embedding a configuration file directly into the core image, + so that it is loaded before entering normal mode. This is useful, for + example, when it is not straightforward to find the real configuration file, + or when you need to debug problems with loading that file. +-@command{grub-install} uses this feature when it is not using BIOS disk ++@command{grub2-install} uses this feature when it is not using BIOS disk + functions or when installing to a different disk from the one containing + @file{/boot/grub}, in which case it needs to use the @command{search} + command (@pxref{search}) to find @file{/boot/grub}. + + To embed a configuration file, use the @option{-c} option to +-@command{grub-mkimage}. The file is copied into the core image, so it may ++@command{grub2-mkimage}. The file is copied into the core image, so it may + reside anywhere on the file system, and may be removed after running +-@command{grub-mkimage}. ++@command{grub2-mkimage}. + + After the embedded configuration file (if any) is executed, GRUB will load + the @samp{normal} module (@pxref{normal}), which will then read the real +@@ -1991,13 +1998,13 @@ included in the core image: + @example + @group + search.fs_label grub root +-if [ -e /boot/grub/example/test1.cfg ]; then ++if [ -e /boot/grub2/example/test1.cfg ]; then + set prefix=($root)/boot/grub +- configfile /boot/grub/example/test1.cfg ++ configfile /boot/grub2/example/test1.cfg + else +- if [ -e /boot/grub/example/test2.cfg ]; then ++ if [ -e /boot/grub2/example/test2.cfg ]; then + set prefix=($root)/boot/grub +- configfile /boot/grub/example/test2.cfg ++ configfile /boot/grub2/example/test2.cfg + else + echo "Could not find an example configuration file!" + fi +@@ -2521,7 +2528,7 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38 + @end group + @end example + +-Then follow instructions printed out by grub-mknetdir on configuring your DHCP ++Then follow instructions printed out by grub2-mknetdir on configuring your DHCP + server. + + The grub.cfg file is placed in the same directory as the path output by +@@ -2715,7 +2722,7 @@ team are: + @end table + + To take full advantage of this function, install GRUB into the MBR +-(@pxref{Installing GRUB using grub-install}). ++(@pxref{Installing GRUB using grub2-install}). + + If you have a laptop which has a similar feature and not in the above list + could you figure your address and contribute? +@@ -2776,7 +2783,7 @@ bytes. + The sole function of @file{boot.img} is to read the first sector of the core + image from a local disk and jump to it. Because of the size restriction, + @file{boot.img} cannot understand any file system structure, so +-@command{grub-install} hardcodes the location of the first sector of the ++@command{grub2-install} hardcodes the location of the first sector of the + core image into @file{boot.img} when installing GRUB. + + @item diskboot.img +@@ -2806,7 +2813,7 @@ images. + + @item core.img + This is the core image of GRUB. It is built dynamically from the kernel +-image and an arbitrary list of modules by the @command{grub-mkimage} ++image and an arbitrary list of modules by the @command{grub2-mkimage} + program. Usually, it contains enough modules to access @file{/boot/grub}, + and loads everything else (including menu handling, the ability to load + target operating systems, and so on) from the file system at run-time. The +@@ -2858,7 +2865,7 @@ GRUB 2 has no single Stage 2 image. Instead, it loads modules from + In GRUB 2, images for booting from CD-ROM drives are now constructed using + @file{cdboot.img} and @file{core.img}, making sure that the core image + contains the @samp{iso9660} module. It is usually best to use the +-@command{grub-mkrescue} program for this. ++@command{grub2-mkrescue} program for this. + + @item nbgrub + There is as yet no equivalent for @file{nbgrub} in GRUB 2; it was used by +@@ -3014,8 +3021,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by + + An absolute file name resembles a Unix absolute file name, using + @samp{/} for the directory separator (not @samp{\} as in DOS). One +-example is @samp{(hd0,1)/boot/grub/grub.cfg}. This means the file +-@file{/boot/grub/grub.cfg} in the first partition of the first hard ++example is @samp{(hd0,1)/boot/grub2/grub.cfg}. This means the file ++@file{/boot/grub2/grub.cfg} in the first partition of the first hard + disk. If you omit the device name in an absolute file name, GRUB uses + GRUB's @dfn{root device} implicitly. So if you set the root device to, + say, @samp{(hd1,1)} by the command @samp{set root=(hd1,1)} (@pxref{set}), +@@ -3023,8 +3030,8 @@ then @code{/boot/kernel} is the same as @code{(hd1,1)/boot/kernel}. + + On ZFS filesystem the first path component must be + @var{volume}@samp{@@}[@var{snapshot}]. +-So @samp{/rootvol@@snap-129/boot/grub/grub.cfg} refers to file +-@samp{/boot/grub/grub.cfg} in snapshot of volume @samp{rootvol} with name ++So @samp{/rootvol@@snap-129/boot/grub2/grub.cfg} refers to file ++@samp{/boot/grub2/grub.cfg} in snapshot of volume @samp{rootvol} with name + @samp{snap-129}. Trailing @samp{@@} after volume name is mandatory even if + snapshot name is omitted. + +@@ -3427,7 +3434,7 @@ The more recent release of Minix would then be identified as + @samp{other>minix>minix-3.4.0}. + + This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple +-configuration}), @command{grub-set-default}, or @command{grub-reboot}. ++configuration}), @command{grub2-set-default}, or @command{grub2-reboot}. + + + @node fallback +@@ -3517,7 +3524,7 @@ If this variable is set, it names the language code that the + example, French would be named as @samp{fr}, and Simplified Chinese as + @samp{zh_CN}. + +-@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a ++@command{grub2-mkconfig} (@pxref{Simple configuration}) will try to set a + reasonable default for this variable based on the system locale. + + +@@ -3525,10 +3532,10 @@ reasonable default for this variable based on the system locale. + @subsection locale_dir + + If this variable is set, it names the directory where translation files may +-be found (@pxref{gettext}), usually @file{/boot/grub/locale}. Otherwise, ++be found (@pxref{gettext}), usually @file{/boot/grub2/locale}. Otherwise, + internationalization is disabled. + +-@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable ++@command{grub2-mkconfig} (@pxref{Simple configuration}) will set a reasonable + default for this variable if internationalization is needed and any + translation files are available. + +@@ -3646,7 +3653,7 @@ input. The default is not to pause output. + + The location of the @samp{/boot/grub} directory as an absolute file name + (@pxref{File name syntax}). This is normally set by GRUB at startup based +-on information provided by @command{grub-install}. GRUB modules are ++on information provided by @command{grub2-install}. GRUB modules are + dynamically loaded from this directory, so it must be set correctly in order + for many parts of GRUB to work. + +@@ -3737,17 +3744,17 @@ GRUB provides an ``environment block'' which can be used to save a small + amount of state. + + The environment block is a preallocated 1024-byte file, which normally lives +-in @file{/boot/grub/grubenv} (although you should not assume this). At boot ++in @file{/boot/grub2/grubenv} (although you should not assume this). At boot + time, the @command{load_env} command (@pxref{load_env}) loads environment + variables from it, and the @command{save_env} (@pxref{save_env}) command + saves environment variables to it. From a running system, the +-@command{grub-editenv} utility can be used to edit the environment block. ++@command{grub2-editenv} utility can be used to edit the environment block. + + For safety reasons, this storage is only available when installed on a plain + disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and + using BIOS or EFI functions (no ATA, USB or IEEE1275). + +-@command{grub-mkconfig} uses this facility to implement ++@command{grub2-mkconfig} uses this facility to implement + @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}). + + +@@ -4476,7 +4483,7 @@ Translate @var{string} into the current language. + + The current language code is stored in the @samp{lang} variable in GRUB's + environment (@pxref{lang}). Translation files in MO format are read from +-@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}. ++@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub2/locale}. + @end deffn + + +@@ -4871,7 +4878,7 @@ Define a user named @var{user} with password @var{clear-password}. + + @deffn Command password_pbkdf2 user hashed-password + Define a user named @var{user} with password hash @var{hashed-password}. +-Use @command{grub-mkpasswd-pbkdf2} (@pxref{Invoking grub-mkpasswd-pbkdf2}) ++Use @command{grub2-mkpasswd-pbkdf2} (@pxref{Invoking grub2-mkpasswd-pbkdf2}) + to generate password hashes. @xref{Security}. + @end deffn + +@@ -5814,8 +5821,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2} + which has an associated password. @samp{password} sets the password in + plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2} + sets the password hashed using the Password-Based Key Derivation Function +-(RFC 2898), requiring the use of @command{grub-mkpasswd-pbkdf2} +-(@pxref{Invoking grub-mkpasswd-pbkdf2}) to generate password hashes. ++(RFC 2898), requiring the use of @command{grub2-mkpasswd-pbkdf2} ++(@pxref{Invoking grub2-mkpasswd-pbkdf2}) to generate password hashes. + + In order to enable authentication support, the @samp{superusers} environment + variable must be set to a list of usernames, separated by any of spaces, +@@ -5860,7 +5867,7 @@ menuentry "May be run by user1 or a superuser" --users user1 @{ + @end group + @end example + +-The @command{grub-mkconfig} program does not yet have built-in support for ++The @command{grub2-mkconfig} program does not yet have built-in support for + generating configuration files with authentication. You can use + @file{/etc/grub.d/40_custom} to add simple superuser authentication, by + adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} +@@ -5887,7 +5894,17 @@ may halt or otherwise impact the boot process. + + An initial trusted public key can be embedded within the GRUB @file{core.img} + using the @code{--pubkey} option to @command{grub-install} +-(@pxref{Invoking grub-install}). ++(@pxref{Invoking grub2-install}). ++ ++@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}. + + GRUB uses GPG-style detached signatures (meaning that a file + @file{foo.sig} will be produced when file @file{foo} is signed), and +@@ -5907,8 +5924,8 @@ gpg --detach-sign /path/to/file + For successful validation of all of GRUB's subcomponents and the + loaded OS kernel, they must all be signed. One way to accomplish this + is the following (after having already produced the desired +-@file{grub.cfg} file, e.g., by running @command{grub-mkconfig} +-(@pxref{Invoking grub-mkconfig}): ++@file{grub.cfg} file, e.g., by running @command{grub2-mkconfig} ++(@pxref{Invoking grub2-mkconfig}): + + @example + @group +@@ -5930,7 +5947,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust}, + Note that internally signature enforcement is controlled by setting + the environment variable @code{check_signatures} equal to + @code{enforce}. Passing one or more @code{--pubkey} options to +-@command{grub-mkimage} implicitly defines @code{check_signatures} ++@command{grub2-mkimage} implicitly defines @code{check_signatures} + equal to @code{enforce} in @file{core.img} prior to processing any + configuration files. + +@@ -6388,10 +6405,10 @@ Required files are: + + GRUB's normal start-up procedure involves setting the @samp{prefix} + environment variable to a value set in the core image by +-@command{grub-install}, setting the @samp{root} variable to match, loading ++@command{grub2-install}, setting the @samp{root} variable to match, loading + the @samp{normal} module from the prefix, and running the @samp{normal} + command (@pxref{normal}). This command is responsible for reading +-@file{/boot/grub/grub.cfg}, running the menu, and doing all the useful ++@file{/boot/grub2/grub.cfg}, running the menu, and doing all the useful + things GRUB is supposed to do. + + If, instead, you only get a rescue shell, this usually means that GRUB +@@ -6417,8 +6434,8 @@ normal + + However, any problem that leaves you in the rescue shell probably means that + GRUB was not correctly installed. It may be more useful to try to reinstall +-it properly using @kbd{grub-install @var{device}} (@pxref{Invoking +-grub-install}). When doing this, there are a few things to remember: ++it properly using @kbd{grub2-install @var{device}} (@pxref{Invoking ++grub2-install}). When doing this, there are a few things to remember: + + @itemize @bullet{} + @item +@@ -6430,7 +6447,7 @@ is usually better to use UUIDs or file system labels and avoid depending on + drive ordering entirely. + + @item +-At least on BIOS systems, if you tell @command{grub-install} to install GRUB ++At least on BIOS systems, if you tell @command{grub2-install} to install GRUB + to a partition but GRUB has already been installed in the master boot + record, then the GRUB installation in the partition will be ignored. + +@@ -6461,21 +6478,21 @@ entry which claims partition start at block 0. This change will not hamper + bootability on other machines. + + +-@node Invoking grub-install +-@chapter Invoking grub-install ++@node Invoking grub2-install ++@chapter Invoking grub2-install + +-The program @command{grub-install} generates a GRUB core image using +-@command{grub-mkimage} and installs it on your system. You must specify the ++The program @command{grub2-install} generates a GRUB core image using ++@command{grub2-mkimage} and installs it on your system. You must specify the + device name on which you want to install GRUB, like this: + + @example +-grub-install @var{install_device} ++grub2-install @var{install_device} + @end example + + The device name @var{install_device} is an OS device name or a GRUB + device name. + +-@command{grub-install} accepts the following options: ++@command{grub2-install} accepts the following options: + + @table @option + @item --help +@@ -6491,13 +6508,13 @@ separate partition or a removable disk. + If this option is not specified then it defaults to @file{/boot}, so + + @example +-@kbd{grub-install /dev/sda} ++@kbd{grub2-install /dev/sda} + @end example + + is equivalent to + + @example +-@kbd{grub-install --boot-directory=/boot/ /dev/sda} ++@kbd{grub2-install --boot-directory=/boot/ /dev/sda} + @end example + + Here is an example in which you have a separate @dfn{boot} partition which is +@@ -6505,16 +6522,16 @@ mounted on + @file{/mnt/boot}: + + @example +-@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb} ++@kbd{grub2-install --boot-directory=/mnt/boot /dev/sdb} + @end example + + @item --recheck +-Recheck the device map, even if @file{/boot/grub/device.map} already ++Recheck the device map, even if @file{/boot/grub2/device.map} already + exists. You should use this option whenever you add/remove a disk + into/from your computer. + + @item --no-rs-codes +-By default on x86 BIOS systems, @command{grub-install} will use some ++By default on x86 BIOS systems, @command{grub2-install} will use some + extra space in the bootloader embedding area for Reed-Solomon + error-correcting codes. This enables GRUB to still boot successfully + if some blocks are corrupted. The exact amount of protection offered +@@ -6527,17 +6544,17 @@ installation}) where GRUB does not reside in any unpartitioned space + outside of the MBR. Disable the Reed-Solomon codes with this option. + @end table + +-@node Invoking grub-mkconfig +-@chapter Invoking grub-mkconfig ++@node Invoking grub2-mkconfig ++@chapter Invoking grub2-mkconfig + +-The program @command{grub-mkconfig} generates a configuration file for GRUB ++The program @command{grub2-mkconfig} generates a configuration file for GRUB + (@pxref{Simple configuration}). + + @example +-grub-mkconfig -o /boot/grub/grub.cfg ++grub-mkconfig -o /boot/grub2/grub.cfg + @end example + +-@command{grub-mkconfig} accepts the following options: ++@command{grub2-mkconfig} accepts the following options: + + @table @option + @item --help +@@ -6553,17 +6570,17 @@ it to standard output. + @end table + + +-@node Invoking grub-mkpasswd-pbkdf2 +-@chapter Invoking grub-mkpasswd-pbkdf2 ++@node Invoking grub2-mkpasswd-pbkdf2 ++@chapter Invoking grub2-mkpasswd-pbkdf2 + +-The program @command{grub-mkpasswd-pbkdf2} generates password hashes for ++The program @command{grub2-mkpasswd-pbkdf2} generates password hashes for + GRUB (@pxref{Security}). + + @example + grub-mkpasswd-pbkdf2 + @end example + +-@command{grub-mkpasswd-pbkdf2} accepts the following options: ++@command{grub2-mkpasswd-pbkdf2} accepts the following options: + + @table @option + @item -c @var{number} +@@ -6581,23 +6598,23 @@ Length of the salt. Defaults to 64. + @end table + + +-@node Invoking grub-mkrelpath +-@chapter Invoking grub-mkrelpath ++@node Invoking grub2-mkrelpath ++@chapter Invoking grub2-mkrelpath + +-The program @command{grub-mkrelpath} makes a file system path relative to ++The program @command{grub2-mkrelpath} makes a file system path relative to + the root of its containing file system. For instance, if @file{/usr} is a + mount point, then: + + @example +-$ @kbd{grub-mkrelpath /usr/share/grub/unicode.pf2} ++$ @kbd{grub2-mkrelpath /usr/share/grub/unicode.pf2} + @samp{/share/grub/unicode.pf2} + @end example + + This is mainly used internally by other GRUB utilities such as +-@command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}), but may ++@command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}), but may + occasionally also be useful for debugging. + +-@command{grub-mkrelpath} accepts the following options: ++@command{grub2-mkrelpath} accepts the following options: + + @table @option + @item --help +@@ -6608,17 +6625,17 @@ Print the version number of GRUB and exit. + @end table + + +-@node Invoking grub-mkrescue +-@chapter Invoking grub-mkrescue ++@node Invoking grub2-mkrescue ++@chapter Invoking grub2-mkrescue + +-The program @command{grub-mkrescue} generates a bootable GRUB rescue image ++The program @command{grub2-mkrescue} generates a bootable GRUB rescue image + (@pxref{Making a GRUB bootable CD-ROM}). + + @example + grub-mkrescue -o grub.iso + @end example + +-All arguments not explicitly listed as @command{grub-mkrescue} options are ++All arguments not explicitly listed as @command{grub2-mkrescue} options are + passed on directly to @command{xorriso} in @command{mkisofs} emulation mode. + Options passed to @command{xorriso} will normally be interpreted as + @command{mkisofs} options; if the option @samp{--} is used, then anything +@@ -6633,7 +6650,7 @@ mkdir -p disk/boot/grub + grub-mkrescue -o grub.iso disk + @end example + +-@command{grub-mkrescue} accepts the following options: ++@command{grub2-mkrescue} accepts the following options: + + @table @option + @item --help +@@ -6661,15 +6678,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in + default. + + @item --grub-mkimage=@var{file} +-Use @var{file} as the @command{grub-mkimage} program, rather than the ++Use @var{file} as the @command{grub2-mkimage} program, rather than the + built-in default. + @end table + + +-@node Invoking grub-mount +-@chapter Invoking grub-mount ++@node Invoking grub2-mount ++@chapter Invoking grub2-mount + +-The program @command{grub-mount} performs a read-only mount of any file ++The program @command{grub2-mount} performs a read-only mount of any file + system or file system image that GRUB understands, using GRUB's file system + drivers via FUSE. (It is only available if FUSE development files were + present when GRUB was built.) This has a number of uses: +@@ -6701,13 +6718,13 @@ even if nobody has yet written a FUSE module specifically for that file + system type. + @end itemize + +-Using @command{grub-mount} is normally as simple as: ++Using @command{grub2-mount} is normally as simple as: + + @example + grub-mount /dev/sda1 /mnt + @end example + +-@command{grub-mount} must be given one or more images and a mount point as ++@command{grub2-mount} must be given one or more images and a mount point as + non-option arguments (if it is given more than one image, it will treat them + as a RAID set), and also accepts the following options: + +@@ -6729,13 +6746,13 @@ Show debugging output for conditions matching @var{string}. + @item -K prompt|@var{file} + @itemx --zfs-key=prompt|@var{file} + Load a ZFS encryption key. If you use @samp{prompt} as the argument, +-@command{grub-mount} will read a passphrase from the terminal; otherwise, it ++@command{grub2-mount} will read a passphrase from the terminal; otherwise, it + will read key material from the specified file. + + @item -r @var{device} + @itemx --root=@var{device} + Set the GRUB root device to @var{device}. You do not normally need to set +-this; @command{grub-mount} will automatically set the root device to the ++this; @command{grub2-mount} will automatically set the root device to the + root of the supplied file system. + + If @var{device} is just a number, then it will be treated as a partition +@@ -6753,10 +6770,10 @@ Print verbose messages. + @end table + + +-@node Invoking grub-probe +-@chapter Invoking grub-probe ++@node Invoking grub2-probe ++@chapter Invoking grub2-probe + +-The program @command{grub-probe} probes device information for a given path ++The program @command{grub2-probe} probes device information for a given path + or device. + + @example +@@ -6764,7 +6781,7 @@ grub-probe --target=fs /boot/grub + grub-probe --target=drive --device /dev/sda1 + @end example + +-@command{grub-probe} must be given a path or device as a non-option ++@command{grub2-probe} must be given a path or device as a non-option + argument, and also accepts the following options: + + @table @option +@@ -6777,16 +6794,16 @@ Print the version number of GRUB and exit. + @item -d + @itemx --device + If this option is given, then the non-option argument is a system device +-name (such as @samp{/dev/sda1}), and @command{grub-probe} will print ++name (such as @samp{/dev/sda1}), and @command{grub2-probe} will print + information about that device. If it is not given, then the non-option + argument is a filesystem path (such as @samp{/boot/grub}), and +-@command{grub-probe} will print information about the device containing that ++@command{grub2-probe} will print information about the device containing that + part of the filesystem. + + @item -m @var{file} + @itemx --device-map=@var{file} + Use @var{file} as the device map (@pxref{Device map}) rather than the +-default, usually @samp{/boot/grub/device.map}. ++default, usually @samp{/boot/grub2/device.map}. + + @item -t @var{target} + @itemx --target=@var{target} +@@ -6839,19 +6856,19 @@ Print verbose messages. + @end table + + +-@node Invoking grub-script-check +-@chapter Invoking grub-script-check ++@node Invoking grub2-script-check ++@chapter Invoking grub2-script-check + +-The program @command{grub-script-check} takes a GRUB script file ++The program @command{grub2-script-check} takes a GRUB script file + (@pxref{Shell-like scripting}) and checks it for syntax errors, similar to + commands such as @command{sh -n}. It may take a @var{path} as a non-option + argument; if none is supplied, it will read from standard input. + + @example +-grub-script-check /boot/grub/grub.cfg ++grub-script-check /boot/grub2/grub.cfg + @end example + +-@command{grub-script-check} accepts the following options: ++@command{grub2-script-check} accepts the following options: + + @table @option + @item --help diff --git a/0040-Make-our-info-pages-say-grub2-where-appropriate.patch b/0040-Make-our-info-pages-say-grub2-where-appropriate.patch deleted file mode 100644 index afba285..0000000 --- a/0040-Make-our-info-pages-say-grub2-where-appropriate.patch +++ /dev/null @@ -1,1008 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 9 Jul 2019 12:59:58 +0200 -Subject: [PATCH] Make our info pages say "grub2" where appropriate. - -This needs to be hooked up to --program-transform=, but I haven't had -time. - -Signed-off-by: Peter Jones ---- - docs/grub-dev.texi | 4 +- - docs/grub.texi | 321 ++++++++++++++++++++++++++++------------------------- - 2 files changed, 171 insertions(+), 154 deletions(-) - -diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi -index 6c629a23e2..19f708ee66 100644 ---- a/docs/grub-dev.texi -+++ b/docs/grub-dev.texi -@@ -1,7 +1,7 @@ - \input texinfo - @c -*-texinfo-*- - @c %**start of header --@setfilename grub-dev.info -+@setfilename grub2-dev.info - @include version-dev.texi - @settitle GNU GRUB Developers Manual @value{VERSION} - @c Unify all our little indices for now. -@@ -32,7 +32,7 @@ Invariant Sections. - - @dircategory Kernel - @direntry --* grub-dev: (grub-dev). The GRand Unified Bootloader Dev -+* grub2-dev: (grub2-dev). The GRand Unified Bootloader Dev - @end direntry - - @setchapternewpage odd -diff --git a/docs/grub.texi b/docs/grub.texi -index 69f08d289f..0615d0ed97 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -1,7 +1,7 @@ - \input texinfo - @c -*-texinfo-*- - @c %**start of header --@setfilename grub.info -+@setfilename grub2.info - @include version.texi - @settitle GNU GRUB Manual @value{VERSION} - @c Unify all our little indices for now. -@@ -32,15 +32,15 @@ Invariant Sections. - - @dircategory Kernel - @direntry --* GRUB: (grub). The GRand Unified Bootloader --* grub-install: (grub)Invoking grub-install. Install GRUB on your drive --* grub-mkconfig: (grub)Invoking grub-mkconfig. Generate GRUB configuration --* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2. --* grub-mkrelpath: (grub)Invoking grub-mkrelpath. --* grub-mkrescue: (grub)Invoking grub-mkrescue. Make a GRUB rescue image --* grub-mount: (grub)Invoking grub-mount. Mount a file system using GRUB --* grub-probe: (grub)Invoking grub-probe. Probe device information --* grub-script-check: (grub)Invoking grub-script-check. -+* GRUB2: (grub2). The GRand Unified Bootloader -+* grub2-install: (grub2)Invoking grub2-install. Install GRUB on your drive -+* grub2-mkconfig: (grub2)Invoking grub2-mkconfig. Generate GRUB configuration -+* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2. -+* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath. -+* grub2-mkrescue: (grub2)Invoking grub2-mkrescue. Make a GRUB rescue image -+* grub2-mount: (grub2)Invoking grub2-mount. Mount a file system using GRUB -+* grub2-probe: (grub2)Invoking grub2-probe. Probe device information -+* grub2-script-check: (grub2)Invoking grub2-script-check. - @end direntry - - @setchapternewpage odd -@@ -103,15 +103,15 @@ This edition documents version @value{VERSION}. - * Platform-specific operations:: Platform-specific operations - * Supported kernels:: The list of supported kernels - * Troubleshooting:: Error messages produced by GRUB --* Invoking grub-install:: How to use the GRUB installer --* Invoking grub-mkconfig:: Generate a GRUB configuration file --* Invoking grub-mkpasswd-pbkdf2:: -+* Invoking grub2-install:: How to use the GRUB installer -+* Invoking grub2-mkconfig:: Generate a GRUB configuration file -+* Invoking grub2-mkpasswd-pbkdf2:: - Generate GRUB password hashes --* Invoking grub-mkrelpath:: Make system path relative to its root --* Invoking grub-mkrescue:: Make a GRUB rescue image --* Invoking grub-mount:: Mount a file system using GRUB --* Invoking grub-probe:: Probe device information for GRUB --* Invoking grub-script-check:: Check GRUB script file for syntax errors -+* Invoking grub2-mkrelpath:: Make system path relative to its root -+* Invoking grub2-mkrescue:: Make a GRUB rescue image -+* Invoking grub2-mount:: Mount a file system using GRUB -+* Invoking grub2-probe:: Probe device information for GRUB -+* Invoking grub2-script-check:: Check GRUB script file for syntax errors - * Obtaining and Building GRUB:: How to obtain and build GRUB - * Reporting bugs:: Where you should send a bug report - * Future:: Some future plans on GRUB -@@ -230,7 +230,7 @@ surprising. - - @item - @file{grub.cfg} is typically automatically generated by --@command{grub-mkconfig} (@pxref{Simple configuration}). This makes it -+@command{grub2-mkconfig} (@pxref{Simple configuration}). This makes it - easier to handle versioned kernel upgrades. - - @item -@@ -244,7 +244,7 @@ scripting language: variables, conditionals, and loops are available. - @item - A small amount of persistent storage is available across reboots, using the - @command{save_env} and @command{load_env} commands in GRUB and the --@command{grub-editenv} utility. This is not available in all configurations -+@command{grub2-editenv} utility. This is not available in all configurations - (@pxref{Environment block}). - - @item -@@ -549,7 +549,7 @@ On OS which have device nodes similar to Unix-like OS GRUB tools use the - OS name. E.g. for GNU/Linux: - - @example --# @kbd{grub-install /dev/sda} -+# @kbd{grub2-install /dev/sda} - @end example - - On AROS we use another syntax. For volumes: -@@ -572,7 +572,7 @@ For disks we use syntax: - E.g. - - @example --# @kbd{grub-install //:ata.device/0/0} -+# @kbd{grub2-install //:ata.device/0/0} - @end example - - On Windows we use UNC path. For volumes it's typically -@@ -599,7 +599,7 @@ For disks it's - E.g. - - @example --# @kbd{grub-install \\?\PhysicalDrive0} -+# @kbd{grub2-install \\?\PhysicalDrive0} - @end example - - Beware that you may need to further escape the backslashes depending on your -@@ -609,7 +609,7 @@ When compiled with cygwin support then cygwin drive names are automatically - when needed. E.g. - - @example --# @kbd{grub-install /dev/sda} -+# @kbd{grub2-install /dev/sda} - @end example - - @node Installation -@@ -622,7 +622,7 @@ from the source tarball, or as a package for your OS. - - After you have done that, you need to install the boot loader on a - drive (floppy or hard disk) by using the utility --@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS. -+@command{grub2-install} (@pxref{Invoking grub2-install}) on a UNIX-like OS. - - GRUB comes with boot images, which are normally put in the directory - @file{/usr/lib/grub/-} (for BIOS-based machines -@@ -633,22 +633,22 @@ loader needs to find them (usually @file{/boot}) will be called - the @dfn{boot directory}. - - @menu --* Installing GRUB using grub-install:: -+* Installing GRUB using grub2-install:: - * Making a GRUB bootable CD-ROM:: - * Device map:: - * BIOS installation:: - @end menu - - --@node Installing GRUB using grub-install --@section Installing GRUB using grub-install -+@node Installing GRUB using grub2-install -+@section Installing GRUB using grub2-install - - For information on where GRUB should be installed on PC BIOS platforms, - @pxref{BIOS installation}. - - In order to install GRUB under a UNIX-like OS (such --as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking --grub-install}) as the superuser (@dfn{root}). -+as @sc{gnu}), invoke the program @command{grub2-install} (@pxref{Invoking -+grub2-install}) as the superuser (@dfn{root}). - - The usage is basically very simple. You only need to specify one - argument to the program, namely, where to install the boot loader. The -@@ -657,13 +657,13 @@ For example, under Linux the following will install GRUB into the MBR - of the first IDE disk: - - @example --# @kbd{grub-install /dev/sda} -+# @kbd{grub2-install /dev/sda} - @end example - - Likewise, under GNU/Hurd, this has the same effect: - - @example --# @kbd{grub-install /dev/hd0} -+# @kbd{grub2-install /dev/hd0} - @end example - - But all the above examples assume that GRUB should put images under -@@ -677,7 +677,7 @@ boot floppy with a filesystem. Here is an example: - # @kbd{mke2fs /dev/fd0} - # @kbd{mount -t ext2 /dev/fd0 /mnt} - # @kbd{mkdir /mnt/boot} --# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0} -+# @kbd{grub2-install --boot-directory=/mnt/boot /dev/fd0} - # @kbd{umount /mnt} - @end group - @end example -@@ -689,30 +689,37 @@ floppy instead of exposing the USB drive as a hard disk (they call it - @example - # @kbd{losetup /dev/loop0 /dev/sdb1} - # @kbd{mount /dev/loop0 /mnt/usb} --# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} -+# @kbd{grub2-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} - @end example - - 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: - - @example --# @kbd{grub-install} -+# @kbd{grub2-install} - @end example - - Otherwise you need to specify where your EFI System partition is mounted: - - @example --# @kbd{grub-install --efi-directory=/mnt/efi} -+# @kbd{grub2-install --efi-directory=/mnt/efi} - @end example - - For removable installs you have to use @option{--removable} and specify both - @option{--boot-directory} and @option{--efi-directory}: - - @example --# @kbd{grub-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} -+# @kbd{grub2-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} - @end example - - @node Making a GRUB bootable CD-ROM -@@ -732,10 +739,10 @@ usually also need to include a configuration file @file{grub.cfg} and some - other GRUB modules. - - To make a simple generic GRUB rescue CD, you can use the --@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}): -+@command{grub2-mkrescue} program (@pxref{Invoking grub2-mkrescue}): - - @example --$ @kbd{grub-mkrescue -o grub.iso} -+$ @kbd{grub2-mkrescue -o grub.iso} - @end example - - You will often need to include other files in your image. To do this, first -@@ -758,7 +765,7 @@ directory @file{iso/}. - Finally, make the image: - - @example --$ @kbd{grub-mkrescue -o grub.iso iso} -+$ @kbd{grub2-mkrescue -o grub.iso iso} - @end example - - This produces a file named @file{grub.iso}, which then can be burned -@@ -774,7 +781,7 @@ storage devices. - @node Device map - @section The map between BIOS drives and OS devices - --If the device map file exists, the GRUB utilities (@command{grub-probe}, -+If the device map file exists, the GRUB utilities (@command{grub2-probe}, - etc.) read it to map BIOS drives to OS devices. This file consists of lines - like this: - -@@ -1254,23 +1261,23 @@ need to write the whole thing by hand. - @node Simple configuration - @section Simple configuration handling - --The program @command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}) -+The program @command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}) - generates @file{grub.cfg} files suitable for most cases. It is suitable for - use when upgrading a distribution, and will discover available kernels and - attempt to generate menu entries for them. - --@command{grub-mkconfig} does have some limitations. While adding extra -+@command{grub2-mkconfig} does have some limitations. While adding extra - custom menu entries to the end of the list can be done by editing --@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg}, -+@file{/etc/grub.d/40_custom} or creating @file{/boot/grub2/custom.cfg}, - changing the order of menu entries or changing their titles may require - making complex changes to shell scripts stored in @file{/etc/grub.d/}. This - may be improved in the future. In the meantime, those who feel that it - would be easier to write @file{grub.cfg} directly are encouraged to do so - (@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system --provided by their distribution to automatically run @command{grub-mkconfig}. -+provided by their distribution to automatically run @command{grub2-mkconfig}. - - The file @file{/etc/default/grub} controls the operation of --@command{grub-mkconfig}. It is sourced by a shell script, and so must be -+@command{grub2-mkconfig}. It is sourced by a shell script, and so must be - valid POSIX shell input; normally, it will just be a sequence of - @samp{KEY=value} lines, but if the value contains spaces or other special - characters then it must be quoted. For example: -@@ -1308,7 +1315,7 @@ works it's not recommended since titles often contain unstable device names - and may be translated - - If you set this to @samp{saved}, then the default menu entry will be that --saved by @samp{GRUB_SAVEDEFAULT} or @command{grub-set-default}. This relies on -+saved by @samp{GRUB_SAVEDEFAULT} or @command{grub2-set-default}. This relies on - the environment block, which may not be available in all situations - (@pxref{Environment block}). - -@@ -1319,7 +1326,7 @@ If this option is set to @samp{true}, then, when an entry is selected, save - it as a new default entry for use by future runs of GRUB. This is only - useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because - @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with --@command{grub-set-default}. Unset by default. -+@command{grub2-set-default}. Unset by default. - This option relies on the environment block, which may not be available in - all situations (@pxref{Environment block}). - -@@ -1449,7 +1456,7 @@ intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode - @end example - - @item GRUB_DISABLE_LINUX_UUID --Normally, @command{grub-mkconfig} will generate menu entries that use -+Normally, @command{grub2-mkconfig} will generate menu entries that use - universally-unique identifiers (UUIDs) to identify the root filesystem to - the Linux kernel, using a @samp{root=UUID=...} kernel parameter. This is - usually more reliable, but in some cases it may not be appropriate. To -@@ -1471,7 +1478,7 @@ If this option is set to @samp{true}, disable the generation of recovery - mode menu entries. - - @item GRUB_DISABLE_UUID --Normally, @command{grub-mkconfig} will generate menu entries that use -+Normally, @command{grub2-mkconfig} will generate menu entries that use - universally-unique identifiers (UUIDs) to identify various filesystems to - search for files. This is usually more reliable, but in some cases it may - not be appropriate. To disable this use of UUIDs, set this option to -@@ -1482,12 +1489,12 @@ not be appropriate. To disable this use of UUIDs, set this option to - @item GRUB_VIDEO_BACKEND - If graphical video support is required, either because the @samp{gfxterm} - graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set, --then @command{grub-mkconfig} will normally load all available GRUB video -+then @command{grub2-mkconfig} will normally load all available GRUB video - drivers and use the one most appropriate for your hardware. If you need to - override this for some reason, then you can set this option. - --After @command{grub-install} has been run, the available video drivers are --listed in @file{/boot/grub/video.lst}. -+After @command{grub2-install} has been run, the available video drivers are -+listed in @file{/boot/grub2/video.lst}. - - @item GRUB_GFXMODE - Set the resolution used on the @samp{gfxterm} graphical terminal. Note that -@@ -1519,7 +1526,7 @@ boot sequence. If you have problems, set this option to @samp{text} and - GRUB will tell Linux to boot in normal text mode. - - @item GRUB_DISABLE_OS_PROBER --Normally, @command{grub-mkconfig} will try to use the external -+Normally, @command{grub2-mkconfig} will try to use the external - @command{os-prober} program, if installed, to discover other operating - systems installed on the same system and generate appropriate menu entries - for them. Set this option to @samp{true} to disable this. -@@ -1529,7 +1536,7 @@ List of space-separated FS UUIDs of filesystems to be ignored from os-prober - output. For efi chainloaders it's @@ - - @item GRUB_DISABLE_SUBMENU --Normally, @command{grub-mkconfig} will generate top level menu entry for -+Normally, @command{grub2-mkconfig} will generate top level menu entry for - the kernel with highest version number and put all other found kernels - or alternative menu entries for recovery mode in submenu. For entries returned - by @command{os-prober} first entry will be put on top level and all others -@@ -1537,11 +1544,11 @@ in submenu. If this option is set to @samp{true}, flat menu with all entries - on top level will be generated instead. Changing this option will require - changing existing values of @samp{GRUB_DEFAULT}, @samp{fallback} (@pxref{fallback}) - and @samp{default} (@pxref{default}) environment variables as well as saved --default entry using @command{grub-set-default} and value used with --@command{grub-reboot}. -+default entry using @command{grub2-set-default} and value used with -+@command{grub2-reboot}. - - @item GRUB_ENABLE_CRYPTODISK --If set to @samp{y}, @command{grub-mkconfig} and @command{grub-install} will -+If set to @samp{y}, @command{grub2-mkconfig} and @command{grub2-install} will - check for encrypted disks and generate additional commands needed to access - them during boot. Note that in this case unattended boot is not possible - because GRUB will wait for passphrase to unlock encrypted container. -@@ -1600,7 +1607,7 @@ confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or - - @end table - --For more detailed customisation of @command{grub-mkconfig}'s output, you may -+For more detailed customisation of @command{grub2-mkconfig}'s output, you may - edit the scripts in @file{/etc/grub.d} directly. - @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom - menu entries; simply type the menu entries you want to add at the end of -@@ -1862,7 +1869,7 @@ images as well. - Mount this partition on/mnt/boot and disable GRUB in all OSes and manually - install self-compiled latest GRUB with: - --@code{grub-install --boot-directory=/mnt/boot /dev/sda} -+@code{grub2-install --boot-directory=/mnt/boot /dev/sda} - - In all the OSes install GRUB tools but disable installing GRUB in bootsector, - so you'll have menu.lst and grub.cfg available for use. Also disable os-prober -@@ -1872,20 +1879,20 @@ use by setting: - - in /etc/default/grub - --Then write a grub.cfg (/mnt/boot/grub/grub.cfg): -+Then write a grub.cfg (/mnt/boot/grub2/grub.cfg): - - @example - - menuentry "OS using grub2" @{ - insmod xfs - search --set=root --label OS1 --hint hd0,msdos8 -- configfile /boot/grub/grub.cfg -+ configfile /boot/grub2/grub.cfg - @} - - menuentry "OS using grub2-legacy" @{ - insmod ext2 - search --set=root --label OS2 --hint hd0,msdos6 -- legacy_configfile /boot/grub/menu.lst -+ legacy_configfile /boot/grub2/menu.lst - @} - - menuentry "Windows XP" @{ -@@ -1948,15 +1955,15 @@ GRUB supports embedding a configuration file directly into the core image, - so that it is loaded before entering normal mode. This is useful, for - example, when it is not straightforward to find the real configuration file, - or when you need to debug problems with loading that file. --@command{grub-install} uses this feature when it is not using BIOS disk -+@command{grub2-install} uses this feature when it is not using BIOS disk - functions or when installing to a different disk from the one containing - @file{/boot/grub}, in which case it needs to use the @command{search} - command (@pxref{search}) to find @file{/boot/grub}. - - To embed a configuration file, use the @option{-c} option to --@command{grub-mkimage}. The file is copied into the core image, so it may -+@command{grub2-mkimage}. The file is copied into the core image, so it may - reside anywhere on the file system, and may be removed after running --@command{grub-mkimage}. -+@command{grub2-mkimage}. - - After the embedded configuration file (if any) is executed, GRUB will load - the @samp{normal} module (@pxref{normal}), which will then read the real -@@ -1991,13 +1998,13 @@ included in the core image: - @example - @group - search.fs_label grub root --if [ -e /boot/grub/example/test1.cfg ]; then -+if [ -e /boot/grub2/example/test1.cfg ]; then - set prefix=($root)/boot/grub -- configfile /boot/grub/example/test1.cfg -+ configfile /boot/grub2/example/test1.cfg - else -- if [ -e /boot/grub/example/test2.cfg ]; then -+ if [ -e /boot/grub2/example/test2.cfg ]; then - set prefix=($root)/boot/grub -- configfile /boot/grub/example/test2.cfg -+ configfile /boot/grub2/example/test2.cfg - else - echo "Could not find an example configuration file!" - fi -@@ -2521,7 +2528,7 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38 - @end group - @end example - --Then follow instructions printed out by grub-mknetdir on configuring your DHCP -+Then follow instructions printed out by grub2-mknetdir on configuring your DHCP - server. - - The grub.cfg file is placed in the same directory as the path output by -@@ -2715,7 +2722,7 @@ team are: - @end table - - To take full advantage of this function, install GRUB into the MBR --(@pxref{Installing GRUB using grub-install}). -+(@pxref{Installing GRUB using grub2-install}). - - If you have a laptop which has a similar feature and not in the above list - could you figure your address and contribute? -@@ -2776,7 +2783,7 @@ bytes. - The sole function of @file{boot.img} is to read the first sector of the core - image from a local disk and jump to it. Because of the size restriction, - @file{boot.img} cannot understand any file system structure, so --@command{grub-install} hardcodes the location of the first sector of the -+@command{grub2-install} hardcodes the location of the first sector of the - core image into @file{boot.img} when installing GRUB. - - @item diskboot.img -@@ -2806,7 +2813,7 @@ images. - - @item core.img - This is the core image of GRUB. It is built dynamically from the kernel --image and an arbitrary list of modules by the @command{grub-mkimage} -+image and an arbitrary list of modules by the @command{grub2-mkimage} - program. Usually, it contains enough modules to access @file{/boot/grub}, - and loads everything else (including menu handling, the ability to load - target operating systems, and so on) from the file system at run-time. The -@@ -2858,7 +2865,7 @@ GRUB 2 has no single Stage 2 image. Instead, it loads modules from - In GRUB 2, images for booting from CD-ROM drives are now constructed using - @file{cdboot.img} and @file{core.img}, making sure that the core image - contains the @samp{iso9660} module. It is usually best to use the --@command{grub-mkrescue} program for this. -+@command{grub2-mkrescue} program for this. - - @item nbgrub - There is as yet no equivalent for @file{nbgrub} in GRUB 2; it was used by -@@ -3014,8 +3021,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by - - An absolute file name resembles a Unix absolute file name, using - @samp{/} for the directory separator (not @samp{\} as in DOS). One --example is @samp{(hd0,1)/boot/grub/grub.cfg}. This means the file --@file{/boot/grub/grub.cfg} in the first partition of the first hard -+example is @samp{(hd0,1)/boot/grub2/grub.cfg}. This means the file -+@file{/boot/grub2/grub.cfg} in the first partition of the first hard - disk. If you omit the device name in an absolute file name, GRUB uses - GRUB's @dfn{root device} implicitly. So if you set the root device to, - say, @samp{(hd1,1)} by the command @samp{set root=(hd1,1)} (@pxref{set}), -@@ -3023,8 +3030,8 @@ then @code{/boot/kernel} is the same as @code{(hd1,1)/boot/kernel}. - - On ZFS filesystem the first path component must be - @var{volume}@samp{@@}[@var{snapshot}]. --So @samp{/rootvol@@snap-129/boot/grub/grub.cfg} refers to file --@samp{/boot/grub/grub.cfg} in snapshot of volume @samp{rootvol} with name -+So @samp{/rootvol@@snap-129/boot/grub2/grub.cfg} refers to file -+@samp{/boot/grub2/grub.cfg} in snapshot of volume @samp{rootvol} with name - @samp{snap-129}. Trailing @samp{@@} after volume name is mandatory even if - snapshot name is omitted. - -@@ -3427,7 +3434,7 @@ The more recent release of Minix would then be identified as - @samp{other>minix>minix-3.4.0}. - - This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple --configuration}), @command{grub-set-default}, or @command{grub-reboot}. -+configuration}), @command{grub2-set-default}, or @command{grub2-reboot}. - - - @node fallback -@@ -3517,7 +3524,7 @@ If this variable is set, it names the language code that the - example, French would be named as @samp{fr}, and Simplified Chinese as - @samp{zh_CN}. - --@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a -+@command{grub2-mkconfig} (@pxref{Simple configuration}) will try to set a - reasonable default for this variable based on the system locale. - - -@@ -3525,10 +3532,10 @@ reasonable default for this variable based on the system locale. - @subsection locale_dir - - If this variable is set, it names the directory where translation files may --be found (@pxref{gettext}), usually @file{/boot/grub/locale}. Otherwise, -+be found (@pxref{gettext}), usually @file{/boot/grub2/locale}. Otherwise, - internationalization is disabled. - --@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable -+@command{grub2-mkconfig} (@pxref{Simple configuration}) will set a reasonable - default for this variable if internationalization is needed and any - translation files are available. - -@@ -3646,7 +3653,7 @@ input. The default is not to pause output. - - The location of the @samp{/boot/grub} directory as an absolute file name - (@pxref{File name syntax}). This is normally set by GRUB at startup based --on information provided by @command{grub-install}. GRUB modules are -+on information provided by @command{grub2-install}. GRUB modules are - dynamically loaded from this directory, so it must be set correctly in order - for many parts of GRUB to work. - -@@ -3737,17 +3744,17 @@ GRUB provides an ``environment block'' which can be used to save a small - amount of state. - - The environment block is a preallocated 1024-byte file, which normally lives --in @file{/boot/grub/grubenv} (although you should not assume this). At boot -+in @file{/boot/grub2/grubenv} (although you should not assume this). At boot - time, the @command{load_env} command (@pxref{load_env}) loads environment - variables from it, and the @command{save_env} (@pxref{save_env}) command - saves environment variables to it. From a running system, the --@command{grub-editenv} utility can be used to edit the environment block. -+@command{grub2-editenv} utility can be used to edit the environment block. - - For safety reasons, this storage is only available when installed on a plain - disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and - using BIOS or EFI functions (no ATA, USB or IEEE1275). - --@command{grub-mkconfig} uses this facility to implement -+@command{grub2-mkconfig} uses this facility to implement - @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}). - - -@@ -4476,7 +4483,7 @@ Translate @var{string} into the current language. - - The current language code is stored in the @samp{lang} variable in GRUB's - environment (@pxref{lang}). Translation files in MO format are read from --@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}. -+@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub2/locale}. - @end deffn - - -@@ -4871,7 +4878,7 @@ Define a user named @var{user} with password @var{clear-password}. - - @deffn Command password_pbkdf2 user hashed-password - Define a user named @var{user} with password hash @var{hashed-password}. --Use @command{grub-mkpasswd-pbkdf2} (@pxref{Invoking grub-mkpasswd-pbkdf2}) -+Use @command{grub2-mkpasswd-pbkdf2} (@pxref{Invoking grub2-mkpasswd-pbkdf2}) - to generate password hashes. @xref{Security}. - @end deffn - -@@ -5814,8 +5821,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2} - which has an associated password. @samp{password} sets the password in - plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2} - sets the password hashed using the Password-Based Key Derivation Function --(RFC 2898), requiring the use of @command{grub-mkpasswd-pbkdf2} --(@pxref{Invoking grub-mkpasswd-pbkdf2}) to generate password hashes. -+(RFC 2898), requiring the use of @command{grub2-mkpasswd-pbkdf2} -+(@pxref{Invoking grub2-mkpasswd-pbkdf2}) to generate password hashes. - - In order to enable authentication support, the @samp{superusers} environment - variable must be set to a list of usernames, separated by any of spaces, -@@ -5860,7 +5867,7 @@ menuentry "May be run by user1 or a superuser" --users user1 @{ - @end group - @end example - --The @command{grub-mkconfig} program does not yet have built-in support for -+The @command{grub2-mkconfig} program does not yet have built-in support for - generating configuration files with authentication. You can use - @file{/etc/grub.d/40_custom} to add simple superuser authentication, by - adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} -@@ -5887,7 +5894,17 @@ may halt or otherwise impact the boot process. - - An initial trusted public key can be embedded within the GRUB @file{core.img} - using the @code{--pubkey} option to @command{grub-install} --(@pxref{Invoking grub-install}). -+(@pxref{Invoking grub2-install}). -+ -+@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}. - - GRUB uses GPG-style detached signatures (meaning that a file - @file{foo.sig} will be produced when file @file{foo} is signed), and -@@ -5907,8 +5924,8 @@ gpg --detach-sign /path/to/file - For successful validation of all of GRUB's subcomponents and the - loaded OS kernel, they must all be signed. One way to accomplish this - is the following (after having already produced the desired --@file{grub.cfg} file, e.g., by running @command{grub-mkconfig} --(@pxref{Invoking grub-mkconfig}): -+@file{grub.cfg} file, e.g., by running @command{grub2-mkconfig} -+(@pxref{Invoking grub2-mkconfig}): - - @example - @group -@@ -5930,7 +5947,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust}, - Note that internally signature enforcement is controlled by setting - the environment variable @code{check_signatures} equal to - @code{enforce}. Passing one or more @code{--pubkey} options to --@command{grub-mkimage} implicitly defines @code{check_signatures} -+@command{grub2-mkimage} implicitly defines @code{check_signatures} - equal to @code{enforce} in @file{core.img} prior to processing any - configuration files. - -@@ -6388,10 +6405,10 @@ Required files are: - - GRUB's normal start-up procedure involves setting the @samp{prefix} - environment variable to a value set in the core image by --@command{grub-install}, setting the @samp{root} variable to match, loading -+@command{grub2-install}, setting the @samp{root} variable to match, loading - the @samp{normal} module from the prefix, and running the @samp{normal} - command (@pxref{normal}). This command is responsible for reading --@file{/boot/grub/grub.cfg}, running the menu, and doing all the useful -+@file{/boot/grub2/grub.cfg}, running the menu, and doing all the useful - things GRUB is supposed to do. - - If, instead, you only get a rescue shell, this usually means that GRUB -@@ -6417,8 +6434,8 @@ normal - - However, any problem that leaves you in the rescue shell probably means that - GRUB was not correctly installed. It may be more useful to try to reinstall --it properly using @kbd{grub-install @var{device}} (@pxref{Invoking --grub-install}). When doing this, there are a few things to remember: -+it properly using @kbd{grub2-install @var{device}} (@pxref{Invoking -+grub2-install}). When doing this, there are a few things to remember: - - @itemize @bullet{} - @item -@@ -6430,7 +6447,7 @@ is usually better to use UUIDs or file system labels and avoid depending on - drive ordering entirely. - - @item --At least on BIOS systems, if you tell @command{grub-install} to install GRUB -+At least on BIOS systems, if you tell @command{grub2-install} to install GRUB - to a partition but GRUB has already been installed in the master boot - record, then the GRUB installation in the partition will be ignored. - -@@ -6461,21 +6478,21 @@ entry which claims partition start at block 0. This change will not hamper - bootability on other machines. - - --@node Invoking grub-install --@chapter Invoking grub-install -+@node Invoking grub2-install -+@chapter Invoking grub2-install - --The program @command{grub-install} generates a GRUB core image using --@command{grub-mkimage} and installs it on your system. You must specify the -+The program @command{grub2-install} generates a GRUB core image using -+@command{grub2-mkimage} and installs it on your system. You must specify the - device name on which you want to install GRUB, like this: - - @example --grub-install @var{install_device} -+grub2-install @var{install_device} - @end example - - The device name @var{install_device} is an OS device name or a GRUB - device name. - --@command{grub-install} accepts the following options: -+@command{grub2-install} accepts the following options: - - @table @option - @item --help -@@ -6491,13 +6508,13 @@ separate partition or a removable disk. - If this option is not specified then it defaults to @file{/boot}, so - - @example --@kbd{grub-install /dev/sda} -+@kbd{grub2-install /dev/sda} - @end example - - is equivalent to - - @example --@kbd{grub-install --boot-directory=/boot/ /dev/sda} -+@kbd{grub2-install --boot-directory=/boot/ /dev/sda} - @end example - - Here is an example in which you have a separate @dfn{boot} partition which is -@@ -6505,16 +6522,16 @@ mounted on - @file{/mnt/boot}: - - @example --@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb} -+@kbd{grub2-install --boot-directory=/mnt/boot /dev/sdb} - @end example - - @item --recheck --Recheck the device map, even if @file{/boot/grub/device.map} already -+Recheck the device map, even if @file{/boot/grub2/device.map} already - exists. You should use this option whenever you add/remove a disk - into/from your computer. - - @item --no-rs-codes --By default on x86 BIOS systems, @command{grub-install} will use some -+By default on x86 BIOS systems, @command{grub2-install} will use some - extra space in the bootloader embedding area for Reed-Solomon - error-correcting codes. This enables GRUB to still boot successfully - if some blocks are corrupted. The exact amount of protection offered -@@ -6527,17 +6544,17 @@ installation}) where GRUB does not reside in any unpartitioned space - outside of the MBR. Disable the Reed-Solomon codes with this option. - @end table - --@node Invoking grub-mkconfig --@chapter Invoking grub-mkconfig -+@node Invoking grub2-mkconfig -+@chapter Invoking grub2-mkconfig - --The program @command{grub-mkconfig} generates a configuration file for GRUB -+The program @command{grub2-mkconfig} generates a configuration file for GRUB - (@pxref{Simple configuration}). - - @example --grub-mkconfig -o /boot/grub/grub.cfg -+grub-mkconfig -o /boot/grub2/grub.cfg - @end example - --@command{grub-mkconfig} accepts the following options: -+@command{grub2-mkconfig} accepts the following options: - - @table @option - @item --help -@@ -6553,17 +6570,17 @@ it to standard output. - @end table - - --@node Invoking grub-mkpasswd-pbkdf2 --@chapter Invoking grub-mkpasswd-pbkdf2 -+@node Invoking grub2-mkpasswd-pbkdf2 -+@chapter Invoking grub2-mkpasswd-pbkdf2 - --The program @command{grub-mkpasswd-pbkdf2} generates password hashes for -+The program @command{grub2-mkpasswd-pbkdf2} generates password hashes for - GRUB (@pxref{Security}). - - @example - grub-mkpasswd-pbkdf2 - @end example - --@command{grub-mkpasswd-pbkdf2} accepts the following options: -+@command{grub2-mkpasswd-pbkdf2} accepts the following options: - - @table @option - @item -c @var{number} -@@ -6581,23 +6598,23 @@ Length of the salt. Defaults to 64. - @end table - - --@node Invoking grub-mkrelpath --@chapter Invoking grub-mkrelpath -+@node Invoking grub2-mkrelpath -+@chapter Invoking grub2-mkrelpath - --The program @command{grub-mkrelpath} makes a file system path relative to -+The program @command{grub2-mkrelpath} makes a file system path relative to - the root of its containing file system. For instance, if @file{/usr} is a - mount point, then: - - @example --$ @kbd{grub-mkrelpath /usr/share/grub/unicode.pf2} -+$ @kbd{grub2-mkrelpath /usr/share/grub/unicode.pf2} - @samp{/share/grub/unicode.pf2} - @end example - - This is mainly used internally by other GRUB utilities such as --@command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}), but may -+@command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}), but may - occasionally also be useful for debugging. - --@command{grub-mkrelpath} accepts the following options: -+@command{grub2-mkrelpath} accepts the following options: - - @table @option - @item --help -@@ -6608,17 +6625,17 @@ Print the version number of GRUB and exit. - @end table - - --@node Invoking grub-mkrescue --@chapter Invoking grub-mkrescue -+@node Invoking grub2-mkrescue -+@chapter Invoking grub2-mkrescue - --The program @command{grub-mkrescue} generates a bootable GRUB rescue image -+The program @command{grub2-mkrescue} generates a bootable GRUB rescue image - (@pxref{Making a GRUB bootable CD-ROM}). - - @example - grub-mkrescue -o grub.iso - @end example - --All arguments not explicitly listed as @command{grub-mkrescue} options are -+All arguments not explicitly listed as @command{grub2-mkrescue} options are - passed on directly to @command{xorriso} in @command{mkisofs} emulation mode. - Options passed to @command{xorriso} will normally be interpreted as - @command{mkisofs} options; if the option @samp{--} is used, then anything -@@ -6633,7 +6650,7 @@ mkdir -p disk/boot/grub - grub-mkrescue -o grub.iso disk - @end example - --@command{grub-mkrescue} accepts the following options: -+@command{grub2-mkrescue} accepts the following options: - - @table @option - @item --help -@@ -6661,15 +6678,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in - default. - - @item --grub-mkimage=@var{file} --Use @var{file} as the @command{grub-mkimage} program, rather than the -+Use @var{file} as the @command{grub2-mkimage} program, rather than the - built-in default. - @end table - - --@node Invoking grub-mount --@chapter Invoking grub-mount -+@node Invoking grub2-mount -+@chapter Invoking grub2-mount - --The program @command{grub-mount} performs a read-only mount of any file -+The program @command{grub2-mount} performs a read-only mount of any file - system or file system image that GRUB understands, using GRUB's file system - drivers via FUSE. (It is only available if FUSE development files were - present when GRUB was built.) This has a number of uses: -@@ -6701,13 +6718,13 @@ even if nobody has yet written a FUSE module specifically for that file - system type. - @end itemize - --Using @command{grub-mount} is normally as simple as: -+Using @command{grub2-mount} is normally as simple as: - - @example - grub-mount /dev/sda1 /mnt - @end example - --@command{grub-mount} must be given one or more images and a mount point as -+@command{grub2-mount} must be given one or more images and a mount point as - non-option arguments (if it is given more than one image, it will treat them - as a RAID set), and also accepts the following options: - -@@ -6729,13 +6746,13 @@ Show debugging output for conditions matching @var{string}. - @item -K prompt|@var{file} - @itemx --zfs-key=prompt|@var{file} - Load a ZFS encryption key. If you use @samp{prompt} as the argument, --@command{grub-mount} will read a passphrase from the terminal; otherwise, it -+@command{grub2-mount} will read a passphrase from the terminal; otherwise, it - will read key material from the specified file. - - @item -r @var{device} - @itemx --root=@var{device} - Set the GRUB root device to @var{device}. You do not normally need to set --this; @command{grub-mount} will automatically set the root device to the -+this; @command{grub2-mount} will automatically set the root device to the - root of the supplied file system. - - If @var{device} is just a number, then it will be treated as a partition -@@ -6753,10 +6770,10 @@ Print verbose messages. - @end table - - --@node Invoking grub-probe --@chapter Invoking grub-probe -+@node Invoking grub2-probe -+@chapter Invoking grub2-probe - --The program @command{grub-probe} probes device information for a given path -+The program @command{grub2-probe} probes device information for a given path - or device. - - @example -@@ -6764,7 +6781,7 @@ grub-probe --target=fs /boot/grub - grub-probe --target=drive --device /dev/sda1 - @end example - --@command{grub-probe} must be given a path or device as a non-option -+@command{grub2-probe} must be given a path or device as a non-option - argument, and also accepts the following options: - - @table @option -@@ -6777,16 +6794,16 @@ Print the version number of GRUB and exit. - @item -d - @itemx --device - If this option is given, then the non-option argument is a system device --name (such as @samp{/dev/sda1}), and @command{grub-probe} will print -+name (such as @samp{/dev/sda1}), and @command{grub2-probe} will print - information about that device. If it is not given, then the non-option - argument is a filesystem path (such as @samp{/boot/grub}), and --@command{grub-probe} will print information about the device containing that -+@command{grub2-probe} will print information about the device containing that - part of the filesystem. - - @item -m @var{file} - @itemx --device-map=@var{file} - Use @var{file} as the device map (@pxref{Device map}) rather than the --default, usually @samp{/boot/grub/device.map}. -+default, usually @samp{/boot/grub2/device.map}. - - @item -t @var{target} - @itemx --target=@var{target} -@@ -6839,19 +6856,19 @@ Print verbose messages. - @end table - - --@node Invoking grub-script-check --@chapter Invoking grub-script-check -+@node Invoking grub2-script-check -+@chapter Invoking grub2-script-check - --The program @command{grub-script-check} takes a GRUB script file -+The program @command{grub2-script-check} takes a GRUB script file - (@pxref{Shell-like scripting}) and checks it for syntax errors, similar to - commands such as @command{sh -n}. It may take a @var{path} as a non-option - argument; if none is supplied, it will read from standard input. - - @example --grub-script-check /boot/grub/grub.cfg -+grub-script-check /boot/grub2/grub.cfg - @end example - --@command{grub-script-check} accepts the following options: -+@command{grub2-script-check} accepts the following options: - - @table @option - @item --help diff --git a/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch b/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch new file mode 100644 index 0000000..8d3139d --- /dev/null +++ b/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 24 May 2017 12:42:32 -0400 +Subject: [PATCH] macos: just build chainloader entries, don't try any xnu xnu. + +Since our bugs tell us that the xnu boot entries really just don't work +most of the time, and they create piles of extra boot entries, because +they can't quite figure out 32-vs-64 and other stuff like that. + +It's rediculous, and we should just boot their bootloader through the +chainloader instead. + +So this patch does that. + +Resolves: rhbz#893179 + +Signed-off-by: Peter Jones +--- + util/grub.d/30_os-prober.in | 78 +++++++++++---------------------------------- + 1 file changed, 18 insertions(+), 60 deletions(-) + +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 1b91c102f3..4b27bd2015 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -42,68 +42,25 @@ if [ -z "${OSPROBED}" ] ; then + fi + + osx_entry() { +- if [ x$2 = x32 ]; then +- # TRANSLATORS: it refers to kernel architecture (32-bit) +- bitstr="$(gettext "(32-bit)")" +- else +- # TRANSLATORS: it refers to kernel architecture (64-bit) +- bitstr="$(gettext "(64-bit)")" +- fi + # TRANSLATORS: it refers on the OS residing on device %s + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" +- cat << EOF +-menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { ++ hints="" ++ for hint in `"${grub_probe}" --device ${device} --target=efi_hints 2> /dev/null` ; do ++ hints="${hints} --hint=${hint}" ++ done ++ cat << EOF ++menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { + EOF + save_default_entry | grub_add_tab + prepare_grub_to_access_device ${DEVICE} | grub_add_tab + cat << EOF ++ set gfxpayload=keep + load_video +- set do_resume=0 +- if [ /var/vm/sleepimage -nt10 / ]; then +- if xnu_resume /var/vm/sleepimage; then +- set do_resume=1 +- fi +- fi +- if [ \$do_resume = 0 ]; then +- xnu_uuid ${OSXUUID} uuid +- if [ -f /Extra/DSDT.aml ]; then +- acpi -e /Extra/DSDT.aml +- fi +- if [ /kernelcache -nt /System/Library/Extensions ]; then +- $1 /kernelcache boot-uuid=\${uuid} rd=*uuid +- elif [ -f /System/Library/Kernels/kernel ]; then +- $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid +- xnu_kextdir /System/Library/Extensions +- else +- $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid +- if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then +- xnu_mkext /System/Library/Extensions.mkext +- else +- xnu_kextdir /System/Library/Extensions +- fi +- fi +- if [ -f /Extra/Extensions.mkext ]; then +- xnu_mkext /Extra/Extensions.mkext +- fi +- if [ -d /Extra/Extensions ]; then +- xnu_kextdir /Extra/Extensions +- fi +- if [ -f /Extra/devprop.bin ]; then +- xnu_devprop_load /Extra/devprop.bin +- fi +- if [ -f /Extra/splash.jpg ]; then +- insmod jpeg +- xnu_splash /Extra/splash.jpg +- fi +- if [ -f /Extra/splash.png ]; then +- insmod png +- xnu_splash /Extra/splash.png +- fi +- if [ -f /Extra/splash.tga ]; then +- insmod tga +- xnu_splash /Extra/splash.tga +- fi +- fi ++ insmod part_gpt ++ insmod hfsplus ++ search --no-floppy --fs-uuid --set=root ${hints} $(grub_get_device_id "${DEVICE}") ++ chainloader (\$root)/System/Library/CoreServices/boot.efi ++ boot + } + EOF + } +@@ -292,11 +249,12 @@ EOF + echo "$title_correction_code" + ;; + macosx) +- if [ "${UUID}" ]; then +- OSXUUID="${UUID}" +- osx_entry xnu_kernel 32 +- osx_entry xnu_kernel64 64 +- fi ++ for subdevice in ${DEVICE%[[:digit:]]*}* ; do ++ parttype="`"${grub_probe}" --device ${device} --target=gpt_parttype "${subdevice}" 2> /dev/null`" ++ if [[ "$parttype" = "426f6f74-0000-11aa-aa11-00306543ecac" ]]; then ++ DEVICE="${subdevice}" osx_entry ++ fi ++ done + ;; + hurd) + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" diff --git a/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch b/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch new file mode 100644 index 0000000..57d2391 --- /dev/null +++ b/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch @@ -0,0 +1,703 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeff Mahoney +Date: Tue, 9 Jul 2019 13:39:45 +0200 +Subject: [PATCH] grub2/btrfs: Add ability to boot from subvolumes + +This patch adds the ability to specify a different root on a btrfs +filesystem too boot from other than the default one. + +btrfs-list-snapshots will list the subvolumes available on the +filesystem. + +set btrfs_subvol= and set btrfs_subvolid= will specify +which subvolume to use and any pathnames provided with either of those +variables set will start using that root. If the subvolume or subvolume id +doesn't exist, then an error case will result. + +It is possible to boot into a separate GRUB instance by exporting the +variable and loading the config file from the subvolume. + +Signed-off-by: Jeff Mahoney +--- + grub-core/fs/btrfs.c | 552 +++++++++++++++++++++++++++++++++++++++++++++++++-- + include/grub/btrfs.h | 1 + + 2 files changed, 533 insertions(+), 20 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 63203034df..f1fff7385b 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -38,6 +38,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -79,9 +82,11 @@ struct grub_btrfs_superblock + grub_uint64_t generation; + grub_uint64_t root_tree; + grub_uint64_t chunk_tree; +- grub_uint8_t dummy2[0x20]; ++ grub_uint8_t dummy2[0x18]; ++ grub_uint64_t bytes_used; + grub_uint64_t root_dir_objectid; +- grub_uint8_t dummy3[0x41]; ++ grub_uint64_t num_devices; ++ grub_uint8_t dummy3[0x39]; + struct grub_btrfs_device this_device; + char label[0x100]; + grub_uint8_t dummy4[0x100]; +@@ -121,6 +126,7 @@ struct grub_btrfs_data + grub_uint64_t exttree; + grub_size_t extsize; + struct grub_btrfs_extent_data *extent; ++ grub_uint64_t fs_tree; + }; + + struct grub_btrfs_chunk_item +@@ -191,6 +197,14 @@ struct grub_btrfs_leaf_descriptor + } *data; + }; + ++struct grub_btrfs_root_ref ++{ ++ grub_uint64_t dirid; ++ grub_uint64_t sequence; ++ grub_uint16_t name_len; ++ const char name[0]; ++} __attribute__ ((packed)); ++ + struct grub_btrfs_time + { + grub_int64_t sec; +@@ -236,6 +250,14 @@ struct grub_btrfs_extent_data + + #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 + ++#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL ++#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL ++#define GRUB_BTRFS_ROOT_REF_KEY 156 ++#define GRUB_BTRFS_ROOT_ITEM_KEY 132 ++ ++static grub_uint64_t btrfs_default_subvolid = 0; ++static char *btrfs_default_subvol = NULL; ++ + static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, + 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 + }; +@@ -1173,6 +1195,62 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return GRUB_ERR_NONE; + } + ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root); ++ ++static grub_err_t ++lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id) ++{ ++ grub_err_t err; ++ grub_uint64_t tree; ++ ++ err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree); ++ if (!err) ++ data->fs_tree = tree; ++ return err; ++} ++ ++static grub_err_t ++find_path (struct grub_btrfs_data *data, ++ const char *path, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++static grub_err_t ++lookup_root_by_name(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ struct grub_btrfs_key key; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return lookup_root_by_name(data, btrfs_default_subvol); ++ ++ if (btrfs_default_subvolid) ++ return lookup_root_by_id(data, btrfs_default_subvolid); ++ ++ data->fs_tree = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++ + static struct grub_btrfs_data * + grub_btrfs_mount (grub_device_t dev) + { +@@ -1208,6 +1286,13 @@ grub_btrfs_mount (grub_device_t dev) + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + ++ err = btrfs_handle_subvol (data); ++ if (err) ++ { ++ grub_free (data); ++ return NULL; ++ } ++ + return data; + } + +@@ -1673,6 +1758,91 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, + return GRUB_ERR_NONE; + } + ++static grub_err_t ++find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid, ++ grub_uint64_t fs_root, const char *name, char **pathname) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF, ++ .offset = 0, ++ }; ++ struct grub_btrfs_key key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ char *p = grub_strdup (name); ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ grub_size_t alloc = grub_strlen(name) + 1; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ { ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ "Can't find inode ref for {%"PRIuGRUB_UINT64_T ++ ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T ++ "/%"PRIuGRUB_SIZE"\n", ++ key_out.object_id, key_out.type, ++ key_out.offset, elemaddr, elemsize); ++ } ++ ++ ++ while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF && ++ key_out.object_id != key_out.offset) { ++ struct grub_btrfs_inode_ref *inode_ref; ++ char *new; ++ ++ inode_ref = grub_malloc(elemsize + 1); ++ if (!inode_ref) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize); ++ ++ err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0); ++ if (err) ++ return grub_error(err, "read_logical caught %d\n", err); ++ ++ alloc += grub_le_to_cpu16 (inode_ref->n) + 2; ++ new = grub_malloc(alloc); ++ if (!new) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc); ++ ++ grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n)); ++ if (p) ++ { ++ new[grub_le_to_cpu16 (inode_ref->n)] = '/'; ++ grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p); ++ grub_free(p); ++ } ++ else ++ new[grub_le_to_cpu16 (inode_ref->n)] = 0; ++ grub_free(inode_ref); ++ ++ p = new; ++ ++ key.object_id = key_out.offset; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, &elemaddr, ++ &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ } ++ ++ *pathname = p; ++ return 0; ++} ++ + static grub_err_t + find_path (struct grub_btrfs_data *data, + const char *path, struct grub_btrfs_key *key, +@@ -1691,14 +1861,26 @@ find_path (struct grub_btrfs_data *data, + char *origpath = NULL; + unsigned symlinks_max = 32; + +- err = get_root (data, key, tree, type); +- if (err) +- return err; +- + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ return err; ++ } ++ + while (1) + { + while (path[0] == '/') +@@ -1871,9 +2053,21 @@ find_path (struct grub_btrfs_data *data, + path = path_alloc = tmp; + if (path[0] == '/') + { +- err = get_root (data, key, tree, type); +- if (err) +- return err; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ return err; ++ } + } + continue; + } +@@ -2114,18 +2308,10 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) + data->tree, file->offset, buf, len); + } + +-static grub_err_t +-grub_btrfs_uuid (grub_device_t device, char **uuid) ++static char * ++btrfs_unparse_uuid(struct grub_btrfs_data *data) + { +- struct grub_btrfs_data *data; +- +- *uuid = NULL; +- +- data = grub_btrfs_mount (device); +- if (!data) +- return grub_errno; +- +- *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", ++ return grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->sblock.uuid[0]), + grub_be_to_cpu16 (data->sblock.uuid[1]), + grub_be_to_cpu16 (data->sblock.uuid[2]), +@@ -2134,6 +2320,20 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) + grub_be_to_cpu16 (data->sblock.uuid[5]), + grub_be_to_cpu16 (data->sblock.uuid[6]), + grub_be_to_cpu16 (data->sblock.uuid[7])); ++} ++ ++static grub_err_t ++grub_btrfs_uuid (grub_device_t device, char **uuid) ++{ ++ struct grub_btrfs_data *data; ++ ++ *uuid = NULL; ++ ++ data = grub_btrfs_mount (device); ++ if (!data) ++ return grub_errno; ++ ++ *uuid = btrfs_unparse_uuid(data); + + grub_btrfs_unmount (data); + +@@ -2190,6 +2390,242 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + } + #endif + ++static grub_err_t ++grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ grub_device_t dev; ++ char *devname; ++ struct grub_btrfs_data *data; ++ char *uuid; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ grub_device_close(dev); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs"); ++ } ++ ++ if (data->sblock.label) ++ grub_printf("Label: '%s' ", data->sblock.label); ++ else ++ grub_printf("Label: none "); ++ ++ uuid = btrfs_unparse_uuid(data); ++ ++ grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T ++ " FS bytes used %" PRIuGRUB_UINT64_T "\n", ++ uuid, grub_cpu_to_le64(data->sblock.num_devices), ++ grub_cpu_to_le64(data->sblock.bytes_used)); ++ ++ grub_btrfs_unmount (data); ++ ++ return 0; ++} ++ ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key_in = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ROOT_ITEM_KEY, ++ .offset = offset, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_root_item ri; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"), ++ key_in.object_id); ++ ++ err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0); ++ if (err) ++ return err; ++ ++ *fs_root = ri.tree; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static const struct grub_arg_option options[] = { ++ {"output", 'o', 0, N_("Output to a variable instead of the console."), ++ N_("VARNAME"), ARG_TYPE_STRING}, ++ {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0}, ++ {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0}, ++ {0, 0, 0, 0, 0, 0} ++}; ++ ++static grub_err_t ++grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ struct grub_btrfs_data *data; ++ grub_device_t dev; ++ char *devname; ++ grub_uint64_t tree; ++ struct grub_btrfs_key key_in = { ++ .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ .type = GRUB_BTRFS_ROOT_REF_KEY, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_uint64_t fs_root = 0; ++ grub_size_t elemsize; ++ grub_size_t allocated = 0; ++ int r = 0; ++ grub_err_t err; ++ char *buf = NULL; ++ int print = 1; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ char *varname = NULL; ++ char *output = NULL; ++ ++ if (ctxt->state[0].set) { ++ varname = ctxt->state[0].arg; ++ print = 0; ++ } ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device"); ++ ++ tree = data->sblock.root_tree; ++ err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ 0, &fs_root); ++ if (err) ++ goto out; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ { ++ grub_btrfs_unmount(data); ++ return err; ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0) ++ { ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) { ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs")); ++ goto out; ++ } ++ ++ do ++ { ++ struct grub_btrfs_root_ref *ref; ++ char *p = NULL; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) ++ { ++ r = 0; ++ break; ++ } ++ ++ if (elemsize > allocated) ++ { ++ grub_free(buf); ++ allocated = 2 * elemsize; ++ buf = grub_malloc(allocated + 1); ++ if (!buf) ++ { ++ r = -grub_errno; ++ break; ++ } ++ } ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ r = -err; ++ break; ++ } ++ buf[elemsize] = 0; ++ ++ find_pathname(data, ref->dirid, fs_root, ref->name, &p); ++ ++ if (print) ++ { ++ if (num_only) ++ grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset); ++ else if (path_only) ++ grub_printf("%s\n", p); ++ else ++ grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p); ++ } else { ++ char *old = output; ++ if (num_only) ++ output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n", ++ old ?: "", key_out.offset); ++ else if (path_only) ++ output = grub_xasprintf("%s%s\n", old ?: "", p); ++ else ++ output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n", ++ old ?: "", key_out.offset, p); ++ ++ if (old) ++ grub_free(old); ++ } ++ ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } while(r > 0); ++ ++ if (output) ++ grub_env_set(varname, output); ++ ++out: ++ free_iterator(&desc); ++ grub_btrfs_unmount(data); ++ ++ grub_device_close (dev); ++ ++ return 0; ++} ++ + static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, +@@ -2205,12 +2641,88 @@ static struct grub_fs grub_btrfs_fs = { + #endif + }; + ++static grub_command_t cmd_info; ++static grub_extcmd_t cmd_list_subvols; ++ ++static char * ++subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ unsigned long long result = 0; ++ ++ grub_errno = GRUB_ERR_NONE; ++ if (*val) ++ { ++ result = grub_strtoull(val, NULL, 10); ++ if (grub_errno) ++ return NULL; ++ } ++ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = NULL; ++ btrfs_default_subvolid = result; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return grub_xasprintf("subvol:%s", btrfs_default_subvol); ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid); ++ else ++ return ""; ++} ++ ++static char * ++subvol_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = grub_strdup (val); ++ btrfs_default_subvolid = 0; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvol_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return btrfs_default_subvol; ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T, ++ btrfs_default_subvolid); ++ else ++ return ""; ++} ++ + GRUB_MOD_INIT (btrfs) + { + grub_fs_register (&grub_btrfs_fs); ++ cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, ++ "DEVICE", ++ "Print BtrFS info about DEVICE."); ++ cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", ++ grub_cmd_btrfs_list_subvols, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print list of BtrFS subvolumes on " ++ "DEVICE.", options); ++ grub_register_variable_hook ("btrfs_subvol", subvol_get_env, ++ subvol_set_env); ++ grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, ++ subvolid_set_env); + } + + GRUB_MOD_FINI (btrfs) + { ++ grub_register_variable_hook ("btrfs_subvol", NULL, NULL); ++ grub_register_variable_hook ("btrfs_subvolid", NULL, NULL); ++ grub_unregister_command (cmd_info); ++ grub_unregister_extcmd (cmd_list_subvols); + grub_fs_unregister (&grub_btrfs_fs); + } ++ ++// vim: si et sw=2: +diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h +index 9d93fb6c18..234ad97677 100644 +--- a/include/grub/btrfs.h ++++ b/include/grub/btrfs.h +@@ -29,6 +29,7 @@ enum + GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84, + GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90, + GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8, ++ GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c, + GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4 + }; + diff --git a/0041-macos-just-build-chainloader-entries-don-t-try-any-x.patch b/0041-macos-just-build-chainloader-entries-don-t-try-any-x.patch deleted file mode 100644 index 8d3139d..0000000 --- a/0041-macos-just-build-chainloader-entries-don-t-try-any-x.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 24 May 2017 12:42:32 -0400 -Subject: [PATCH] macos: just build chainloader entries, don't try any xnu xnu. - -Since our bugs tell us that the xnu boot entries really just don't work -most of the time, and they create piles of extra boot entries, because -they can't quite figure out 32-vs-64 and other stuff like that. - -It's rediculous, and we should just boot their bootloader through the -chainloader instead. - -So this patch does that. - -Resolves: rhbz#893179 - -Signed-off-by: Peter Jones ---- - util/grub.d/30_os-prober.in | 78 +++++++++++---------------------------------- - 1 file changed, 18 insertions(+), 60 deletions(-) - -diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in -index 1b91c102f3..4b27bd2015 100644 ---- a/util/grub.d/30_os-prober.in -+++ b/util/grub.d/30_os-prober.in -@@ -42,68 +42,25 @@ if [ -z "${OSPROBED}" ] ; then - fi - - osx_entry() { -- if [ x$2 = x32 ]; then -- # TRANSLATORS: it refers to kernel architecture (32-bit) -- bitstr="$(gettext "(32-bit)")" -- else -- # TRANSLATORS: it refers to kernel architecture (64-bit) -- bitstr="$(gettext "(64-bit)")" -- fi - # TRANSLATORS: it refers on the OS residing on device %s - onstr="$(gettext_printf "(on %s)" "${DEVICE}")" -- cat << EOF --menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { -+ hints="" -+ for hint in `"${grub_probe}" --device ${device} --target=efi_hints 2> /dev/null` ; do -+ hints="${hints} --hint=${hint}" -+ done -+ cat << EOF -+menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { - EOF - save_default_entry | grub_add_tab - prepare_grub_to_access_device ${DEVICE} | grub_add_tab - cat << EOF -+ set gfxpayload=keep - load_video -- set do_resume=0 -- if [ /var/vm/sleepimage -nt10 / ]; then -- if xnu_resume /var/vm/sleepimage; then -- set do_resume=1 -- fi -- fi -- if [ \$do_resume = 0 ]; then -- xnu_uuid ${OSXUUID} uuid -- if [ -f /Extra/DSDT.aml ]; then -- acpi -e /Extra/DSDT.aml -- fi -- if [ /kernelcache -nt /System/Library/Extensions ]; then -- $1 /kernelcache boot-uuid=\${uuid} rd=*uuid -- elif [ -f /System/Library/Kernels/kernel ]; then -- $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid -- xnu_kextdir /System/Library/Extensions -- else -- $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid -- if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then -- xnu_mkext /System/Library/Extensions.mkext -- else -- xnu_kextdir /System/Library/Extensions -- fi -- fi -- if [ -f /Extra/Extensions.mkext ]; then -- xnu_mkext /Extra/Extensions.mkext -- fi -- if [ -d /Extra/Extensions ]; then -- xnu_kextdir /Extra/Extensions -- fi -- if [ -f /Extra/devprop.bin ]; then -- xnu_devprop_load /Extra/devprop.bin -- fi -- if [ -f /Extra/splash.jpg ]; then -- insmod jpeg -- xnu_splash /Extra/splash.jpg -- fi -- if [ -f /Extra/splash.png ]; then -- insmod png -- xnu_splash /Extra/splash.png -- fi -- if [ -f /Extra/splash.tga ]; then -- insmod tga -- xnu_splash /Extra/splash.tga -- fi -- fi -+ insmod part_gpt -+ insmod hfsplus -+ search --no-floppy --fs-uuid --set=root ${hints} $(grub_get_device_id "${DEVICE}") -+ chainloader (\$root)/System/Library/CoreServices/boot.efi -+ boot - } - EOF - } -@@ -292,11 +249,12 @@ EOF - echo "$title_correction_code" - ;; - macosx) -- if [ "${UUID}" ]; then -- OSXUUID="${UUID}" -- osx_entry xnu_kernel 32 -- osx_entry xnu_kernel64 64 -- fi -+ for subdevice in ${DEVICE%[[:digit:]]*}* ; do -+ parttype="`"${grub_probe}" --device ${device} --target=gpt_parttype "${subdevice}" 2> /dev/null`" -+ if [[ "$parttype" = "426f6f74-0000-11aa-aa11-00306543ecac" ]]; then -+ DEVICE="${subdevice}" osx_entry -+ fi -+ done - ;; - hurd) - onstr="$(gettext_printf "(on %s)" "${DEVICE}")" diff --git a/0042-export-btrfs_subvol-and-btrfs_subvolid.patch b/0042-export-btrfs_subvol-and-btrfs_subvolid.patch new file mode 100644 index 0000000..719866e --- /dev/null +++ b/0042-export-btrfs_subvol-and-btrfs_subvolid.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 18 Dec 2013 09:57:04 +0000 +Subject: [PATCH] export btrfs_subvol and btrfs_subvolid + +We should export btrfs_subvol and btrfs_subvolid to have both visible +to subsidiary configuration files loaded using configfile. + +Signed-off-by: Michael Chang +--- + grub-core/fs/btrfs.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index f1fff7385b..ad1b56b716 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2714,6 +2714,8 @@ GRUB_MOD_INIT (btrfs) + subvol_set_env); + grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, + subvolid_set_env); ++ grub_env_export ("btrfs_subvol"); ++ grub_env_export ("btrfs_subvolid"); + } + + GRUB_MOD_FINI (btrfs) diff --git a/0042-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch b/0042-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch deleted file mode 100644 index 57d2391..0000000 --- a/0042-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch +++ /dev/null @@ -1,703 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeff Mahoney -Date: Tue, 9 Jul 2019 13:39:45 +0200 -Subject: [PATCH] grub2/btrfs: Add ability to boot from subvolumes - -This patch adds the ability to specify a different root on a btrfs -filesystem too boot from other than the default one. - -btrfs-list-snapshots will list the subvolumes available on the -filesystem. - -set btrfs_subvol= and set btrfs_subvolid= will specify -which subvolume to use and any pathnames provided with either of those -variables set will start using that root. If the subvolume or subvolume id -doesn't exist, then an error case will result. - -It is possible to boot into a separate GRUB instance by exporting the -variable and loading the config file from the subvolume. - -Signed-off-by: Jeff Mahoney ---- - grub-core/fs/btrfs.c | 552 +++++++++++++++++++++++++++++++++++++++++++++++++-- - include/grub/btrfs.h | 1 + - 2 files changed, 533 insertions(+), 20 deletions(-) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 63203034df..f1fff7385b 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -38,6 +38,9 @@ - #include - #include - #include -+#include -+#include -+#include - #include - #include - #include -@@ -79,9 +82,11 @@ struct grub_btrfs_superblock - grub_uint64_t generation; - grub_uint64_t root_tree; - grub_uint64_t chunk_tree; -- grub_uint8_t dummy2[0x20]; -+ grub_uint8_t dummy2[0x18]; -+ grub_uint64_t bytes_used; - grub_uint64_t root_dir_objectid; -- grub_uint8_t dummy3[0x41]; -+ grub_uint64_t num_devices; -+ grub_uint8_t dummy3[0x39]; - struct grub_btrfs_device this_device; - char label[0x100]; - grub_uint8_t dummy4[0x100]; -@@ -121,6 +126,7 @@ struct grub_btrfs_data - grub_uint64_t exttree; - grub_size_t extsize; - struct grub_btrfs_extent_data *extent; -+ grub_uint64_t fs_tree; - }; - - struct grub_btrfs_chunk_item -@@ -191,6 +197,14 @@ struct grub_btrfs_leaf_descriptor - } *data; - }; - -+struct grub_btrfs_root_ref -+{ -+ grub_uint64_t dirid; -+ grub_uint64_t sequence; -+ grub_uint16_t name_len; -+ const char name[0]; -+} __attribute__ ((packed)); -+ - struct grub_btrfs_time - { - grub_int64_t sec; -@@ -236,6 +250,14 @@ struct grub_btrfs_extent_data - - #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 - -+#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL -+#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL -+#define GRUB_BTRFS_ROOT_REF_KEY 156 -+#define GRUB_BTRFS_ROOT_ITEM_KEY 132 -+ -+static grub_uint64_t btrfs_default_subvolid = 0; -+static char *btrfs_default_subvol = NULL; -+ - static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, - 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 - }; -@@ -1173,6 +1195,62 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - return GRUB_ERR_NONE; - } - -+static grub_err_t -+get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, -+ grub_uint64_t objectid, grub_uint64_t offset, -+ grub_uint64_t *fs_root); -+ -+static grub_err_t -+lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id) -+{ -+ grub_err_t err; -+ grub_uint64_t tree; -+ -+ err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree); -+ if (!err) -+ data->fs_tree = tree; -+ return err; -+} -+ -+static grub_err_t -+find_path (struct grub_btrfs_data *data, -+ const char *path, struct grub_btrfs_key *key, -+ grub_uint64_t *tree, grub_uint8_t *type); -+ -+static grub_err_t -+lookup_root_by_name(struct grub_btrfs_data *data, const char *path) -+{ -+ grub_err_t err; -+ grub_uint64_t tree = 0; -+ grub_uint8_t type; -+ struct grub_btrfs_key key; -+ -+ err = find_path (data, path, &key, &tree, &type); -+ if (err) -+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); -+ -+ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) -+ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); -+ -+ data->fs_tree = tree; -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) -+{ -+ if (btrfs_default_subvol) -+ return lookup_root_by_name(data, btrfs_default_subvol); -+ -+ if (btrfs_default_subvolid) -+ return lookup_root_by_id(data, btrfs_default_subvolid); -+ -+ data->fs_tree = 0; -+ -+ return GRUB_ERR_NONE; -+} -+ -+ - static struct grub_btrfs_data * - grub_btrfs_mount (grub_device_t dev) - { -@@ -1208,6 +1286,13 @@ grub_btrfs_mount (grub_device_t dev) - data->devices_attached[0].dev = dev; - data->devices_attached[0].id = data->sblock.this_device.device_id; - -+ err = btrfs_handle_subvol (data); -+ if (err) -+ { -+ grub_free (data); -+ return NULL; -+ } -+ - return data; - } - -@@ -1673,6 +1758,91 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, - return GRUB_ERR_NONE; - } - -+static grub_err_t -+find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid, -+ grub_uint64_t fs_root, const char *name, char **pathname) -+{ -+ grub_err_t err; -+ struct grub_btrfs_key key = { -+ .object_id = objectid, -+ .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF, -+ .offset = 0, -+ }; -+ struct grub_btrfs_key key_out; -+ struct grub_btrfs_leaf_descriptor desc; -+ char *p = grub_strdup (name); -+ grub_disk_addr_t elemaddr; -+ grub_size_t elemsize; -+ grub_size_t alloc = grub_strlen(name) + 1; -+ -+ err = lower_bound(data, &key, &key_out, fs_root, -+ &elemaddr, &elemsize, &desc, 0); -+ if (err) -+ return grub_error(err, "lower_bound caught %d\n", err); -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) -+ next(data, &desc, &elemaddr, &elemsize, &key_out); -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) -+ { -+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, -+ "Can't find inode ref for {%"PRIuGRUB_UINT64_T -+ ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T -+ "/%"PRIuGRUB_SIZE"\n", -+ key_out.object_id, key_out.type, -+ key_out.offset, elemaddr, elemsize); -+ } -+ -+ -+ while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF && -+ key_out.object_id != key_out.offset) { -+ struct grub_btrfs_inode_ref *inode_ref; -+ char *new; -+ -+ inode_ref = grub_malloc(elemsize + 1); -+ if (!inode_ref) -+ return grub_error(GRUB_ERR_OUT_OF_MEMORY, -+ "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize); -+ -+ err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0); -+ if (err) -+ return grub_error(err, "read_logical caught %d\n", err); -+ -+ alloc += grub_le_to_cpu16 (inode_ref->n) + 2; -+ new = grub_malloc(alloc); -+ if (!new) -+ return grub_error(GRUB_ERR_OUT_OF_MEMORY, -+ "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc); -+ -+ grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n)); -+ if (p) -+ { -+ new[grub_le_to_cpu16 (inode_ref->n)] = '/'; -+ grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p); -+ grub_free(p); -+ } -+ else -+ new[grub_le_to_cpu16 (inode_ref->n)] = 0; -+ grub_free(inode_ref); -+ -+ p = new; -+ -+ key.object_id = key_out.offset; -+ -+ err = lower_bound(data, &key, &key_out, fs_root, &elemaddr, -+ &elemsize, &desc, 0); -+ if (err) -+ return grub_error(err, "lower_bound caught %d\n", err); -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) -+ next(data, &desc, &elemaddr, &elemsize, &key_out); -+ -+ } -+ -+ *pathname = p; -+ return 0; -+} -+ - static grub_err_t - find_path (struct grub_btrfs_data *data, - const char *path, struct grub_btrfs_key *key, -@@ -1691,14 +1861,26 @@ find_path (struct grub_btrfs_data *data, - char *origpath = NULL; - unsigned symlinks_max = 32; - -- err = get_root (data, key, tree, type); -- if (err) -- return err; -- - origpath = grub_strdup (path); - if (!origpath) - return grub_errno; - -+ if (data->fs_tree) -+ { -+ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -+ *tree = data->fs_tree; -+ /* This is a tree root, so everything starts at objectid 256 */ -+ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); -+ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -+ key->offset = 0; -+ } -+ else -+ { -+ err = get_root (data, key, tree, type); -+ if (err) -+ return err; -+ } -+ - while (1) - { - while (path[0] == '/') -@@ -1871,9 +2053,21 @@ find_path (struct grub_btrfs_data *data, - path = path_alloc = tmp; - if (path[0] == '/') - { -- err = get_root (data, key, tree, type); -- if (err) -- return err; -+ if (data->fs_tree) -+ { -+ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -+ *tree = data->fs_tree; -+ /* This is a tree root, so everything starts at objectid 256 */ -+ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); -+ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -+ key->offset = 0; -+ } -+ else -+ { -+ err = get_root (data, key, tree, type); -+ if (err) -+ return err; -+ } - } - continue; - } -@@ -2114,18 +2308,10 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) - data->tree, file->offset, buf, len); - } - --static grub_err_t --grub_btrfs_uuid (grub_device_t device, char **uuid) -+static char * -+btrfs_unparse_uuid(struct grub_btrfs_data *data) - { -- struct grub_btrfs_data *data; -- -- *uuid = NULL; -- -- data = grub_btrfs_mount (device); -- if (!data) -- return grub_errno; -- -- *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", -+ return grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - grub_be_to_cpu16 (data->sblock.uuid[0]), - grub_be_to_cpu16 (data->sblock.uuid[1]), - grub_be_to_cpu16 (data->sblock.uuid[2]), -@@ -2134,6 +2320,20 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) - grub_be_to_cpu16 (data->sblock.uuid[5]), - grub_be_to_cpu16 (data->sblock.uuid[6]), - grub_be_to_cpu16 (data->sblock.uuid[7])); -+} -+ -+static grub_err_t -+grub_btrfs_uuid (grub_device_t device, char **uuid) -+{ -+ struct grub_btrfs_data *data; -+ -+ *uuid = NULL; -+ -+ data = grub_btrfs_mount (device); -+ if (!data) -+ return grub_errno; -+ -+ *uuid = btrfs_unparse_uuid(data); - - grub_btrfs_unmount (data); - -@@ -2190,6 +2390,242 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), - } - #endif - -+static grub_err_t -+grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, -+ char **argv) -+{ -+ grub_device_t dev; -+ char *devname; -+ struct grub_btrfs_data *data; -+ char *uuid; -+ -+ if (argc < 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); -+ -+ devname = grub_file_get_device_name(argv[0]); -+ -+ if (!devname) -+ return grub_errno; -+ -+ dev = grub_device_open (devname); -+ grub_free (devname); -+ if (!dev) -+ return grub_errno; -+ -+ data = grub_btrfs_mount (dev); -+ if (!data) -+ { -+ grub_device_close(dev); -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs"); -+ } -+ -+ if (data->sblock.label) -+ grub_printf("Label: '%s' ", data->sblock.label); -+ else -+ grub_printf("Label: none "); -+ -+ uuid = btrfs_unparse_uuid(data); -+ -+ grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T -+ " FS bytes used %" PRIuGRUB_UINT64_T "\n", -+ uuid, grub_cpu_to_le64(data->sblock.num_devices), -+ grub_cpu_to_le64(data->sblock.bytes_used)); -+ -+ grub_btrfs_unmount (data); -+ -+ return 0; -+} -+ -+static grub_err_t -+get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, -+ grub_uint64_t objectid, grub_uint64_t offset, -+ grub_uint64_t *fs_root) -+{ -+ grub_err_t err; -+ struct grub_btrfs_key key_in = { -+ .object_id = objectid, -+ .type = GRUB_BTRFS_ROOT_ITEM_KEY, -+ .offset = offset, -+ }, key_out; -+ struct grub_btrfs_leaf_descriptor desc; -+ grub_disk_addr_t elemaddr; -+ grub_size_t elemsize; -+ struct grub_btrfs_root_item ri; -+ -+ err = lower_bound(data, &key_in, &key_out, tree, -+ &elemaddr, &elemsize, &desc, 0); -+ -+ if (err) -+ return err; -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0) -+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, -+ N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"), -+ key_in.object_id); -+ -+ err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0); -+ if (err) -+ return err; -+ -+ *fs_root = ri.tree; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static const struct grub_arg_option options[] = { -+ {"output", 'o', 0, N_("Output to a variable instead of the console."), -+ N_("VARNAME"), ARG_TYPE_STRING}, -+ {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0}, -+ {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0}, -+ {0, 0, 0, 0, 0, 0} -+}; -+ -+static grub_err_t -+grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt, -+ int argc, char **argv) -+{ -+ struct grub_btrfs_data *data; -+ grub_device_t dev; -+ char *devname; -+ grub_uint64_t tree; -+ struct grub_btrfs_key key_in = { -+ .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), -+ .type = GRUB_BTRFS_ROOT_REF_KEY, -+ .offset = 0, -+ }, key_out; -+ struct grub_btrfs_leaf_descriptor desc; -+ grub_disk_addr_t elemaddr; -+ grub_uint64_t fs_root = 0; -+ grub_size_t elemsize; -+ grub_size_t allocated = 0; -+ int r = 0; -+ grub_err_t err; -+ char *buf = NULL; -+ int print = 1; -+ int path_only = ctxt->state[1].set; -+ int num_only = ctxt->state[2].set; -+ char *varname = NULL; -+ char *output = NULL; -+ -+ if (ctxt->state[0].set) { -+ varname = ctxt->state[0].arg; -+ print = 0; -+ } -+ -+ if (argc < 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); -+ -+ devname = grub_file_get_device_name(argv[0]); -+ if (!devname) -+ return grub_errno; -+ -+ dev = grub_device_open (devname); -+ grub_free (devname); -+ if (!dev) -+ return grub_errno; -+ -+ data = grub_btrfs_mount(dev); -+ if (!data) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device"); -+ -+ tree = data->sblock.root_tree; -+ err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), -+ 0, &fs_root); -+ if (err) -+ goto out; -+ -+ err = lower_bound(data, &key_in, &key_out, tree, -+ &elemaddr, &elemsize, &desc, 0); -+ -+ if (err) -+ { -+ grub_btrfs_unmount(data); -+ return err; -+ } -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0) -+ { -+ r = next(data, &desc, &elemaddr, &elemsize, &key_out); -+ } -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) { -+ err = GRUB_ERR_FILE_NOT_FOUND; -+ grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs")); -+ goto out; -+ } -+ -+ do -+ { -+ struct grub_btrfs_root_ref *ref; -+ char *p = NULL; -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) -+ { -+ r = 0; -+ break; -+ } -+ -+ if (elemsize > allocated) -+ { -+ grub_free(buf); -+ allocated = 2 * elemsize; -+ buf = grub_malloc(allocated + 1); -+ if (!buf) -+ { -+ r = -grub_errno; -+ break; -+ } -+ } -+ ref = (struct grub_btrfs_root_ref *)buf; -+ -+ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); -+ if (err) -+ { -+ r = -err; -+ break; -+ } -+ buf[elemsize] = 0; -+ -+ find_pathname(data, ref->dirid, fs_root, ref->name, &p); -+ -+ if (print) -+ { -+ if (num_only) -+ grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset); -+ else if (path_only) -+ grub_printf("%s\n", p); -+ else -+ grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p); -+ } else { -+ char *old = output; -+ if (num_only) -+ output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n", -+ old ?: "", key_out.offset); -+ else if (path_only) -+ output = grub_xasprintf("%s%s\n", old ?: "", p); -+ else -+ output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n", -+ old ?: "", key_out.offset, p); -+ -+ if (old) -+ grub_free(old); -+ } -+ -+ r = next(data, &desc, &elemaddr, &elemsize, &key_out); -+ } while(r > 0); -+ -+ if (output) -+ grub_env_set(varname, output); -+ -+out: -+ free_iterator(&desc); -+ grub_btrfs_unmount(data); -+ -+ grub_device_close (dev); -+ -+ return 0; -+} -+ - static struct grub_fs grub_btrfs_fs = { - .name = "btrfs", - .fs_dir = grub_btrfs_dir, -@@ -2205,12 +2641,88 @@ static struct grub_fs grub_btrfs_fs = { - #endif - }; - -+static grub_command_t cmd_info; -+static grub_extcmd_t cmd_list_subvols; -+ -+static char * -+subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val) -+{ -+ unsigned long long result = 0; -+ -+ grub_errno = GRUB_ERR_NONE; -+ if (*val) -+ { -+ result = grub_strtoull(val, NULL, 10); -+ if (grub_errno) -+ return NULL; -+ } -+ -+ grub_free (btrfs_default_subvol); -+ btrfs_default_subvol = NULL; -+ btrfs_default_subvolid = result; -+ return grub_strdup(val); -+} -+ -+static const char * -+subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val __attribute__ ((unused))) -+{ -+ if (btrfs_default_subvol) -+ return grub_xasprintf("subvol:%s", btrfs_default_subvol); -+ else if (btrfs_default_subvolid) -+ return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid); -+ else -+ return ""; -+} -+ -+static char * -+subvol_set_env (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val) -+{ -+ grub_free (btrfs_default_subvol); -+ btrfs_default_subvol = grub_strdup (val); -+ btrfs_default_subvolid = 0; -+ return grub_strdup(val); -+} -+ -+static const char * -+subvol_get_env (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val __attribute__ ((unused))) -+{ -+ if (btrfs_default_subvol) -+ return btrfs_default_subvol; -+ else if (btrfs_default_subvolid) -+ return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T, -+ btrfs_default_subvolid); -+ else -+ return ""; -+} -+ - GRUB_MOD_INIT (btrfs) - { - grub_fs_register (&grub_btrfs_fs); -+ cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, -+ "DEVICE", -+ "Print BtrFS info about DEVICE."); -+ cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", -+ grub_cmd_btrfs_list_subvols, 0, -+ "[-p|-n] [-o var] DEVICE", -+ "Print list of BtrFS subvolumes on " -+ "DEVICE.", options); -+ grub_register_variable_hook ("btrfs_subvol", subvol_get_env, -+ subvol_set_env); -+ grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, -+ subvolid_set_env); - } - - GRUB_MOD_FINI (btrfs) - { -+ grub_register_variable_hook ("btrfs_subvol", NULL, NULL); -+ grub_register_variable_hook ("btrfs_subvolid", NULL, NULL); -+ grub_unregister_command (cmd_info); -+ grub_unregister_extcmd (cmd_list_subvols); - grub_fs_unregister (&grub_btrfs_fs); - } -+ -+// vim: si et sw=2: -diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h -index 9d93fb6c18..234ad97677 100644 ---- a/include/grub/btrfs.h -+++ b/include/grub/btrfs.h -@@ -29,6 +29,7 @@ enum - GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84, - GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90, - GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8, -+ GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c, - GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4 - }; - diff --git a/0043-export-btrfs_subvol-and-btrfs_subvolid.patch b/0043-export-btrfs_subvol-and-btrfs_subvolid.patch deleted file mode 100644 index 719866e..0000000 --- a/0043-export-btrfs_subvol-and-btrfs_subvolid.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Wed, 18 Dec 2013 09:57:04 +0000 -Subject: [PATCH] export btrfs_subvol and btrfs_subvolid - -We should export btrfs_subvol and btrfs_subvolid to have both visible -to subsidiary configuration files loaded using configfile. - -Signed-off-by: Michael Chang ---- - grub-core/fs/btrfs.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index f1fff7385b..ad1b56b716 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -2714,6 +2714,8 @@ GRUB_MOD_INIT (btrfs) - subvol_set_env); - grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, - subvolid_set_env); -+ grub_env_export ("btrfs_subvol"); -+ grub_env_export ("btrfs_subvolid"); - } - - GRUB_MOD_FINI (btrfs) diff --git a/0043-grub2-btrfs-03-follow_default.patch b/0043-grub2-btrfs-03-follow_default.patch new file mode 100644 index 0000000..621f029 --- /dev/null +++ b/0043-grub2-btrfs-03-follow_default.patch @@ -0,0 +1,198 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 21 Aug 2014 03:39:11 +0000 +Subject: [PATCH] grub2-btrfs-03-follow_default + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 107 ++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 76 insertions(+), 31 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index ad1b56b716..113c1f746c 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1256,6 +1256,7 @@ grub_btrfs_mount (grub_device_t dev) + { + struct grub_btrfs_data *data; + grub_err_t err; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + + if (!dev->disk) + { +@@ -1286,11 +1287,14 @@ grub_btrfs_mount (grub_device_t dev) + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + +- err = btrfs_handle_subvol (data); +- if (err) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- grub_free (data); +- return NULL; ++ err = btrfs_handle_subvol (data); ++ if (err) ++ { ++ grub_free (data); ++ return NULL; ++ } + } + + return data; +@@ -1855,24 +1859,39 @@ find_path (struct grub_btrfs_data *data, + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_key key_out; ++ int follow_default; + const char *ctoken; + grub_size_t ctokenlen; + char *path_alloc = NULL; + char *origpath = NULL; + unsigned symlinks_max = 32; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + ++ follow_default = 0; + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + +- if (data->fs_tree) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; +- *tree = data->fs_tree; +- /* This is a tree root, so everything starts at objectid 256 */ +- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); +- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; +- key->offset = 0; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } + } + else + { +@@ -1883,15 +1902,23 @@ find_path (struct grub_btrfs_data *data, + + while (1) + { +- while (path[0] == '/') +- path++; +- if (!path[0]) +- break; +- slash = grub_strchr (path, '/'); +- if (!slash) +- slash = path + grub_strlen (path); +- ctoken = path; +- ctokenlen = slash - path; ++ if (!follow_default) ++ { ++ while (path[0] == '/') ++ path++; ++ if (!path[0]) ++ break; ++ slash = grub_strchr (path, '/'); ++ if (!slash) ++ slash = path + grub_strlen (path); ++ ctoken = path; ++ ctokenlen = slash - path; ++ } ++ else ++ { ++ ctoken = "default"; ++ ctokenlen = sizeof ("default") - 1; ++ } + + if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { +@@ -1902,7 +1929,9 @@ find_path (struct grub_btrfs_data *data, + + if (ctokenlen == 1 && ctoken[0] == '.') + { +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.') +@@ -1933,8 +1962,9 @@ find_path (struct grub_btrfs_data *data, + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + key->object_id = key_out.offset; + +- path = slash; +- ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + +@@ -2003,7 +2033,9 @@ find_path (struct grub_btrfs_data *data, + return err; + } + +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) + { + struct grub_btrfs_inode inode; +@@ -2053,14 +2085,26 @@ find_path (struct grub_btrfs_data *data, + path = path_alloc = tmp; + if (path[0] == '/') + { +- if (data->fs_tree) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; +- *tree = data->fs_tree; +- /* This is a tree root, so everything starts at objectid 256 */ +- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); +- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; +- key->offset = 0; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } + } + else + { +@@ -2716,6 +2760,7 @@ GRUB_MOD_INIT (btrfs) + subvolid_set_env); + grub_env_export ("btrfs_subvol"); + grub_env_export ("btrfs_subvolid"); ++ grub_env_export ("btrfs_relative_path"); + } + + GRUB_MOD_FINI (btrfs) diff --git a/0044-grub2-btrfs-03-follow_default.patch b/0044-grub2-btrfs-03-follow_default.patch deleted file mode 100644 index 621f029..0000000 --- a/0044-grub2-btrfs-03-follow_default.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Thu, 21 Aug 2014 03:39:11 +0000 -Subject: [PATCH] grub2-btrfs-03-follow_default - -Signed-off-by: Michael Chang -Signed-off-by: Robbie Harwood ---- - grub-core/fs/btrfs.c | 107 ++++++++++++++++++++++++++++++++++++--------------- - 1 file changed, 76 insertions(+), 31 deletions(-) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index ad1b56b716..113c1f746c 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -1256,6 +1256,7 @@ grub_btrfs_mount (grub_device_t dev) - { - struct grub_btrfs_data *data; - grub_err_t err; -+ const char *relpath = grub_env_get ("btrfs_relative_path"); - - if (!dev->disk) - { -@@ -1286,11 +1287,14 @@ grub_btrfs_mount (grub_device_t dev) - data->devices_attached[0].dev = dev; - data->devices_attached[0].id = data->sblock.this_device.device_id; - -- err = btrfs_handle_subvol (data); -- if (err) -+ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) - { -- grub_free (data); -- return NULL; -+ err = btrfs_handle_subvol (data); -+ if (err) -+ { -+ grub_free (data); -+ return NULL; -+ } - } - - return data; -@@ -1855,24 +1859,39 @@ find_path (struct grub_btrfs_data *data, - grub_size_t allocated = 0; - struct grub_btrfs_dir_item *direl = NULL; - struct grub_btrfs_key key_out; -+ int follow_default; - const char *ctoken; - grub_size_t ctokenlen; - char *path_alloc = NULL; - char *origpath = NULL; - unsigned symlinks_max = 32; -+ const char *relpath = grub_env_get ("btrfs_relative_path"); - -+ follow_default = 0; - origpath = grub_strdup (path); - if (!origpath) - return grub_errno; - -- if (data->fs_tree) -+ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) - { -- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -- *tree = data->fs_tree; -- /* This is a tree root, so everything starts at objectid 256 */ -- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); -- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -- key->offset = 0; -+ if (data->fs_tree) -+ { -+ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -+ *tree = data->fs_tree; -+ /* This is a tree root, so everything starts at objectid 256 */ -+ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); -+ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -+ key->offset = 0; -+ } -+ else -+ { -+ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -+ *tree = data->sblock.root_tree; -+ key->object_id = data->sblock.root_dir_objectid; -+ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -+ key->offset = 0; -+ follow_default = 1; -+ } - } - else - { -@@ -1883,15 +1902,23 @@ find_path (struct grub_btrfs_data *data, - - while (1) - { -- while (path[0] == '/') -- path++; -- if (!path[0]) -- break; -- slash = grub_strchr (path, '/'); -- if (!slash) -- slash = path + grub_strlen (path); -- ctoken = path; -- ctokenlen = slash - path; -+ if (!follow_default) -+ { -+ while (path[0] == '/') -+ path++; -+ if (!path[0]) -+ break; -+ slash = grub_strchr (path, '/'); -+ if (!slash) -+ slash = path + grub_strlen (path); -+ ctoken = path; -+ ctokenlen = slash - path; -+ } -+ else -+ { -+ ctoken = "default"; -+ ctokenlen = sizeof ("default") - 1; -+ } - - if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) - { -@@ -1902,7 +1929,9 @@ find_path (struct grub_btrfs_data *data, - - if (ctokenlen == 1 && ctoken[0] == '.') - { -- path = slash; -+ if (!follow_default) -+ path = slash; -+ follow_default = 0; - continue; - } - if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.') -@@ -1933,8 +1962,9 @@ find_path (struct grub_btrfs_data *data, - *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; - key->object_id = key_out.offset; - -- path = slash; -- -+ if (!follow_default) -+ path = slash; -+ follow_default = 0; - continue; - } - -@@ -2003,7 +2033,9 @@ find_path (struct grub_btrfs_data *data, - return err; - } - -- path = slash; -+ if (!follow_default) -+ path = slash; -+ follow_default = 0; - if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) - { - struct grub_btrfs_inode inode; -@@ -2053,14 +2085,26 @@ find_path (struct grub_btrfs_data *data, - path = path_alloc = tmp; - if (path[0] == '/') - { -- if (data->fs_tree) -+ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) - { -- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -- *tree = data->fs_tree; -- /* This is a tree root, so everything starts at objectid 256 */ -- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); -- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -- key->offset = 0; -+ if (data->fs_tree) -+ { -+ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -+ *tree = data->fs_tree; -+ /* This is a tree root, so everything starts at objectid 256 */ -+ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); -+ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -+ key->offset = 0; -+ } -+ else -+ { -+ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; -+ *tree = data->sblock.root_tree; -+ key->object_id = data->sblock.root_dir_objectid; -+ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -+ key->offset = 0; -+ follow_default = 1; -+ } - } - else - { -@@ -2716,6 +2760,7 @@ GRUB_MOD_INIT (btrfs) - subvolid_set_env); - grub_env_export ("btrfs_subvol"); - grub_env_export ("btrfs_subvolid"); -+ grub_env_export ("btrfs_relative_path"); - } - - GRUB_MOD_FINI (btrfs) diff --git a/0044-grub2-btrfs-04-grub2-install.patch b/0044-grub2-btrfs-04-grub2-install.patch new file mode 100644 index 0000000..6b2bc78 --- /dev/null +++ b/0044-grub2-btrfs-04-grub2-install.patch @@ -0,0 +1,176 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 21 Aug 2014 03:39:11 +0000 +Subject: [PATCH] grub2-btrfs-04-grub2-install + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/osdep/linux/getroot.c | 7 +++++++ + grub-core/osdep/unix/config.c | 17 +++++++++++++++-- + util/config.c | 10 ++++++++++ + util/grub-install.c | 15 +++++++++++++++ + util/grub-mkrelpath.c | 6 ++++++ + include/grub/emu/config.h | 1 + + 6 files changed, 54 insertions(+), 2 deletions(-) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 001b818fe5..caf9b1ccd3 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -376,6 +376,7 @@ get_btrfs_fs_prefix (const char *mount_path) + return NULL; + } + ++int use_relative_path_on_btrfs = 0; + + char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) +@@ -519,6 +520,12 @@ again: + { + ret = grub_find_root_devices_from_btrfs (dir); + fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); ++ if (use_relative_path_on_btrfs) ++ { ++ if (fs_prefix) ++ free (fs_prefix); ++ fs_prefix = xstrdup ("/"); ++ } + } + else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) + { +diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c +index 7d6325138c..46a881530c 100644 +--- a/grub-core/osdep/unix/config.c ++++ b/grub-core/osdep/unix/config.c +@@ -82,6 +82,19 @@ grub_util_load_config (struct grub_util_config *cfg) + if (v) + cfg->grub_distributor = xstrdup (v); + ++ v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING"); ++ if (v) ++ { ++ if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0) ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ } ++ else ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 0; ++ } ++ } ++ + cfgfile = grub_util_get_config_filename (); + if (!grub_util_is_regular (cfgfile)) + return; +@@ -105,8 +118,8 @@ grub_util_load_config (struct grub_util_config *cfg) + *ptr++ = *iptr; + } + +- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " +- "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\""); ++ strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" " ++ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\""); + + argv[2] = script; + argv[3] = '\0'; +diff --git a/util/config.c b/util/config.c +index ebcdd8f5e2..f044a880a7 100644 +--- a/util/config.c ++++ b/util/config.c +@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple) + cfg->is_cryptodisk_enabled = 1; + continue; + } ++ if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=", ++ sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0) ++ { ++ ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1; ++ if (*ptr == '"' || *ptr == '\'') ++ ptr++; ++ if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0) ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ continue; ++ } + if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=", + sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) + { +diff --git a/util/grub-install.c b/util/grub-install.c +index 0fbe7f78c6..0f66f36d23 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -827,6 +827,8 @@ fill_core_services (const char *core_services) + free (sysv_plist); + } + ++extern int use_relative_path_on_btrfs; ++ + int + main (int argc, char *argv[]) + { +@@ -860,6 +862,9 @@ main (int argc, char *argv[]) + + grub_util_load_config (&config); + ++ if (config.is_suse_btrfs_snapshot_enabled) ++ use_relative_path_on_btrfs = 1; ++ + if (!bootloader_id && config.grub_distributor) + { + char *ptr; +@@ -1352,6 +1357,16 @@ main (int argc, char *argv[]) + fprintf (load_cfg_f, "set debug='%s'\n", + debug_image); + } ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ fprintf (load_cfg_f, "set btrfs_relative_path='y'\n"); ++ } ++ + char *prefix_drive = NULL; + char *install_drive = NULL; + +diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c +index 47a241a391..5db7a9a7d9 100644 +--- a/util/grub-mkrelpath.c ++++ b/util/grub-mkrelpath.c +@@ -40,9 +40,12 @@ struct arguments + }; + + static struct argp_option options[] = { ++ {"relative", 'r', 0, 0, "use relative path on btrfs", 0}, + { 0, 0, 0, 0, 0, 0 } + }; + ++extern int use_relative_path_on_btrfs; ++ + static error_t + argp_parser (int key, char *arg, struct argp_state *state) + { +@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + + switch (key) + { ++ case 'r': ++ use_relative_path_on_btrfs = 1; ++ break; + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->pathname = xstrdup (arg); +diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h +index 875d5896ce..c9a7e5f4ad 100644 +--- a/include/grub/emu/config.h ++++ b/include/grub/emu/config.h +@@ -37,6 +37,7 @@ struct grub_util_config + { + int is_cryptodisk_enabled; + char *grub_distributor; ++ int is_suse_btrfs_snapshot_enabled; + }; + + void diff --git a/0045-grub2-btrfs-04-grub2-install.patch b/0045-grub2-btrfs-04-grub2-install.patch deleted file mode 100644 index 6b2bc78..0000000 --- a/0045-grub2-btrfs-04-grub2-install.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Thu, 21 Aug 2014 03:39:11 +0000 -Subject: [PATCH] grub2-btrfs-04-grub2-install - -Signed-off-by: Michael Chang -Signed-off-by: Robbie Harwood ---- - grub-core/osdep/linux/getroot.c | 7 +++++++ - grub-core/osdep/unix/config.c | 17 +++++++++++++++-- - util/config.c | 10 ++++++++++ - util/grub-install.c | 15 +++++++++++++++ - util/grub-mkrelpath.c | 6 ++++++ - include/grub/emu/config.h | 1 + - 6 files changed, 54 insertions(+), 2 deletions(-) - -diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c -index 001b818fe5..caf9b1ccd3 100644 ---- a/grub-core/osdep/linux/getroot.c -+++ b/grub-core/osdep/linux/getroot.c -@@ -376,6 +376,7 @@ get_btrfs_fs_prefix (const char *mount_path) - return NULL; - } - -+int use_relative_path_on_btrfs = 0; - - char ** - grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) -@@ -519,6 +520,12 @@ again: - { - ret = grub_find_root_devices_from_btrfs (dir); - fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); -+ if (use_relative_path_on_btrfs) -+ { -+ if (fs_prefix) -+ free (fs_prefix); -+ fs_prefix = xstrdup ("/"); -+ } - } - else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) - { -diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c -index 7d6325138c..46a881530c 100644 ---- a/grub-core/osdep/unix/config.c -+++ b/grub-core/osdep/unix/config.c -@@ -82,6 +82,19 @@ grub_util_load_config (struct grub_util_config *cfg) - if (v) - cfg->grub_distributor = xstrdup (v); - -+ v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING"); -+ if (v) -+ { -+ if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0) -+ { -+ cfg->is_suse_btrfs_snapshot_enabled = 1; -+ } -+ else -+ { -+ cfg->is_suse_btrfs_snapshot_enabled = 0; -+ } -+ } -+ - cfgfile = grub_util_get_config_filename (); - if (!grub_util_is_regular (cfgfile)) - return; -@@ -105,8 +118,8 @@ grub_util_load_config (struct grub_util_config *cfg) - *ptr++ = *iptr; - } - -- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " -- "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\""); -+ strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" " -+ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\""); - - argv[2] = script; - argv[3] = '\0'; -diff --git a/util/config.c b/util/config.c -index ebcdd8f5e2..f044a880a7 100644 ---- a/util/config.c -+++ b/util/config.c -@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple) - cfg->is_cryptodisk_enabled = 1; - continue; - } -+ if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=", -+ sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0) -+ { -+ ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1; -+ if (*ptr == '"' || *ptr == '\'') -+ ptr++; -+ if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0) -+ cfg->is_suse_btrfs_snapshot_enabled = 1; -+ continue; -+ } - if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=", - sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) - { -diff --git a/util/grub-install.c b/util/grub-install.c -index 0fbe7f78c6..0f66f36d23 100644 ---- a/util/grub-install.c -+++ b/util/grub-install.c -@@ -827,6 +827,8 @@ fill_core_services (const char *core_services) - free (sysv_plist); - } - -+extern int use_relative_path_on_btrfs; -+ - int - main (int argc, char *argv[]) - { -@@ -860,6 +862,9 @@ main (int argc, char *argv[]) - - grub_util_load_config (&config); - -+ if (config.is_suse_btrfs_snapshot_enabled) -+ use_relative_path_on_btrfs = 1; -+ - if (!bootloader_id && config.grub_distributor) - { - char *ptr; -@@ -1352,6 +1357,16 @@ main (int argc, char *argv[]) - fprintf (load_cfg_f, "set debug='%s'\n", - debug_image); - } -+ -+ if (config.is_suse_btrfs_snapshot_enabled -+ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) -+ { -+ if (!load_cfg_f) -+ load_cfg_f = grub_util_fopen (load_cfg, "wb"); -+ have_load_cfg = 1; -+ fprintf (load_cfg_f, "set btrfs_relative_path='y'\n"); -+ } -+ - char *prefix_drive = NULL; - char *install_drive = NULL; - -diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c -index 47a241a391..5db7a9a7d9 100644 ---- a/util/grub-mkrelpath.c -+++ b/util/grub-mkrelpath.c -@@ -40,9 +40,12 @@ struct arguments - }; - - static struct argp_option options[] = { -+ {"relative", 'r', 0, 0, "use relative path on btrfs", 0}, - { 0, 0, 0, 0, 0, 0 } - }; - -+extern int use_relative_path_on_btrfs; -+ - static error_t - argp_parser (int key, char *arg, struct argp_state *state) - { -@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct argp_state *state) - - switch (key) - { -+ case 'r': -+ use_relative_path_on_btrfs = 1; -+ break; - case ARGP_KEY_ARG: - if (state->arg_num == 0) - arguments->pathname = xstrdup (arg); -diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h -index 875d5896ce..c9a7e5f4ad 100644 ---- a/include/grub/emu/config.h -+++ b/include/grub/emu/config.h -@@ -37,6 +37,7 @@ struct grub_util_config - { - int is_cryptodisk_enabled; - char *grub_distributor; -+ int is_suse_btrfs_snapshot_enabled; - }; - - void diff --git a/0045-grub2-btrfs-05-grub2-mkconfig.patch b/0045-grub2-btrfs-05-grub2-mkconfig.patch new file mode 100644 index 0000000..ca3f86b --- /dev/null +++ b/0045-grub2-btrfs-05-grub2-mkconfig.patch @@ -0,0 +1,129 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 21 Aug 2014 03:39:11 +0000 +Subject: [PATCH] grub2-btrfs-05-grub2-mkconfig + +Signed-off-by: Michael Chang +--- + util/grub-mkconfig.in | 3 ++- + util/grub-mkconfig_lib.in | 4 ++++ + util/grub.d/00_header.in | 25 ++++++++++++++++++++++++- + util/grub.d/10_linux.in | 4 ++++ + util/grub.d/20_linux_xen.in | 4 ++++ + 5 files changed, 38 insertions(+), 2 deletions(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 005f093809..535c0f0249 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -252,7 +252,8 @@ export GRUB_DEFAULT \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ + GRUB_DISABLE_SUBMENU \ +- GRUB_DEFAULT_DTB ++ GRUB_DEFAULT_DTB \ ++ SUSE_BTRFS_SNAPSHOT_BOOTING + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 0f6505bf3b..5e96f6cc5d 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -49,7 +49,11 @@ grub_warn () + + make_system_path_relative_to_its_root () + { ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then ++ "${grub_mkrelpath}" -r "$1" ++ else + "${grub_mkrelpath}" "$1" ++ fi + } + + is_path_readable_by_grub () +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index 858b526c92..de727e6ee6 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + ++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && ++ [ "x${GRUB_FS}" = "xbtrfs" ] ; then ++ cat </dev/null || true` +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index ada20775a1..e9e73b815f 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -73,10 +73,14 @@ fi + + case x"$GRUB_FS" in + xbtrfs) ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then ++ GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}" ++ else + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" ++ fi + fi;; + xzfs) + rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` diff --git a/0046-grub2-btrfs-05-grub2-mkconfig.patch b/0046-grub2-btrfs-05-grub2-mkconfig.patch deleted file mode 100644 index 06d15a7..0000000 --- a/0046-grub2-btrfs-05-grub2-mkconfig.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Thu, 21 Aug 2014 03:39:11 +0000 -Subject: [PATCH] grub2-btrfs-05-grub2-mkconfig - -Signed-off-by: Michael Chang ---- - util/grub-mkconfig.in | 3 ++- - util/grub-mkconfig_lib.in | 4 ++++ - util/grub.d/00_header.in | 25 ++++++++++++++++++++++++- - util/grub.d/10_linux.in | 4 ++++ - util/grub.d/20_linux_xen.in | 4 ++++ - 5 files changed, 38 insertions(+), 2 deletions(-) - -diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in -index 005f093809..535c0f0249 100644 ---- a/util/grub-mkconfig.in -+++ b/util/grub-mkconfig.in -@@ -252,7 +252,8 @@ export GRUB_DEFAULT \ - GRUB_BADRAM \ - GRUB_OS_PROBER_SKIP_LIST \ - GRUB_DISABLE_SUBMENU \ -- GRUB_DEFAULT_DTB -+ GRUB_DEFAULT_DTB \ -+ SUSE_BTRFS_SNAPSHOT_BOOTING - - if test "x${grub_cfg}" != "x"; then - rm -f "${grub_cfg}.new" -diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in -index 42c2ea9ba5..fafeac9506 100644 ---- a/util/grub-mkconfig_lib.in -+++ b/util/grub-mkconfig_lib.in -@@ -52,7 +52,11 @@ grub_warn () - - make_system_path_relative_to_its_root () - { -+ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then -+ "${grub_mkrelpath}" -r "$1" -+ else - "${grub_mkrelpath}" "$1" -+ fi - } - - is_path_readable_by_grub () -diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in -index 858b526c92..de727e6ee6 100644 ---- a/util/grub.d/00_header.in -+++ b/util/grub.d/00_header.in -@@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@" - - . "$pkgdatadir/grub-mkconfig_lib" - -+if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && -+ [ "x${GRUB_FS}" = "xbtrfs" ] ; then -+ cat </dev/null || true` -diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in -index ada20775a1..e9e73b815f 100644 ---- a/util/grub.d/20_linux_xen.in -+++ b/util/grub.d/20_linux_xen.in -@@ -73,10 +73,14 @@ fi - - case x"$GRUB_FS" in - xbtrfs) -+ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then -+ GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}" -+ else - rootsubvol="`make_system_path_relative_to_its_root /`" - rootsubvol="${rootsubvol#/}" - if [ "x${rootsubvol}" != x ]; then - GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" -+ fi - fi;; - xzfs) - rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` diff --git a/0046-grub2-btrfs-06-subvol-mount.patch b/0046-grub2-btrfs-06-subvol-mount.patch new file mode 100644 index 0000000..8cdf247 --- /dev/null +++ b/0046-grub2-btrfs-06-subvol-mount.patch @@ -0,0 +1,539 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 9 Jul 2019 13:56:16 +0200 +Subject: [PATCH] grub2-btrfs-06-subvol-mount + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 195 +++++++++++++++++++++++++++++++++++++++- + grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++++++++- + util/grub-install.c | 49 ++++++++++ + include/grub/emu/getroot.h | 5 ++ + 4 files changed, 392 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 113c1f746c..d323746ecf 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -266,6 +267,12 @@ static grub_err_t + grub_btrfs_read_logical (struct grub_btrfs_data *data, + grub_disk_addr_t addr, void *buf, grub_size_t size, + int recursion_depth); ++static grub_err_t ++get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol); + + static grub_err_t + read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) +@@ -1223,9 +1230,26 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path) + grub_err_t err; + grub_uint64_t tree = 0; + grub_uint8_t type; ++ grub_uint64_t saved_tree; + struct grub_btrfs_key key; + ++ if (path[0] == '\0') ++ { ++ data->fs_tree = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ err = get_root (data, &key, &tree, &type); ++ if (err) ++ return err; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ + err = find_path (data, path, &key, &tree, &type); ++ ++ data->fs_tree = saved_tree; ++ + if (err) + return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); + +@@ -2199,11 +2223,20 @@ grub_btrfs_dir (grub_device_t device, const char *path, + int r = 0; + grub_uint64_t tree; + grub_uint8_t type; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, path, &key_in, &tree, &type); ++ tree = find_mtab_subvol_tree (path, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2305,11 +2338,21 @@ grub_btrfs_open (struct grub_file *file, const char *name) + struct grub_btrfs_inode inode; + grub_uint8_t type; + struct grub_btrfs_key key_in; ++ grub_uint64_t tree; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, name, &key_in, &data->tree, &type); ++ tree = find_mtab_subvol_tree (name, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2480,6 +2523,150 @@ grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, + return 0; + } + ++struct grub_btrfs_mtab ++{ ++ struct grub_btrfs_mtab *next; ++ struct grub_btrfs_mtab **prev; ++ char *path; ++ char *subvol; ++ grub_uint64_t tree; ++}; ++ ++typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t; ++ ++static struct grub_btrfs_mtab *btrfs_mtab; ++ ++#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab) ++#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab) ++ ++static void ++add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree) ++{ ++ grub_btrfs_mtab_t m = grub_malloc (sizeof (*m)); ++ ++ m->path = grub_strdup (path); ++ m->subvol = grub_strdup (subvol); ++ m->tree = tree; ++ grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m)); ++} ++ ++static grub_err_t ++grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ char *devname, *dirname, *subvol; ++ struct grub_btrfs_key key_in; ++ grub_uint8_t type; ++ grub_uint64_t tree; ++ grub_uint64_t saved_tree; ++ grub_err_t err; ++ struct grub_btrfs_data *data = NULL; ++ grub_device_t dev = NULL; ++ ++ if (argc < 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "required and "); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ ++ if (!dev) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ dirname = argv[1]; ++ subvol = argv[2]; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ err = find_path (data, dirname, &key_in, &tree, &type); ++ if (err) ++ goto err_out; ++ ++ if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); ++ goto err_out; ++ } ++ ++ err = get_root (data, &key_in, &tree, &type); ++ ++ if (err) ++ goto err_out; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ err = find_path (data, subvol, &key_in, &tree, &type); ++ data->fs_tree = saved_tree; ++ ++ if (err) ++ goto err_out; ++ ++ if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol); ++ goto err_out; ++ } ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ add_mountpoint (dirname, subvol, tree); ++ ++ return GRUB_ERR_NONE; ++ ++err_out: ++ ++ if (data) ++ grub_btrfs_unmount (data); ++ ++ if (dev) ++ grub_device_close (dev); ++ ++ return err; ++} ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol) ++{ ++ grub_btrfs_mtab_t m, cm; ++ grub_uint64_t tree; ++ ++ if (!path || !path_in_subvol) ++ return 0; ++ ++ *path_in_subvol = NULL; ++ tree = 0; ++ cm = NULL; ++ ++ FOR_GRUB_MTAB (m) ++ { ++ if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0) ++ { ++ if (!cm) ++ cm = m; ++ else ++ if (grub_strcmp (m->path, cm->path) > 0) ++ cm = m; ++ } ++ } ++ ++ if (cm) ++ { ++ const char *s = path + grub_strlen (cm->path); ++ *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s); ++ tree = cm->tree; ++ } ++ ++ return tree; ++} ++ + static grub_err_t + get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, + grub_uint64_t objectid, grub_uint64_t offset, +@@ -2686,6 +2873,7 @@ static struct grub_fs grub_btrfs_fs = { + }; + + static grub_command_t cmd_info; ++static grub_command_t cmd_mount_subvol; + static grub_extcmd_t cmd_list_subvols; + + static char * +@@ -2749,6 +2937,9 @@ GRUB_MOD_INIT (btrfs) + cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, + "DEVICE", + "Print BtrFS info about DEVICE."); ++ cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol, ++ "DEVICE DIRECTORY SUBVOL", ++ "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL."); + cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", + grub_cmd_btrfs_list_subvols, 0, + "[-p|-n] [-o var] DEVICE", +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index caf9b1ccd3..28790307e0 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -107,6 +107,14 @@ struct btrfs_ioctl_search_key + grub_uint32_t unused[9]; + }; + ++struct btrfs_ioctl_search_header { ++ grub_uint64_t transid; ++ grub_uint64_t objectid; ++ grub_uint64_t offset; ++ grub_uint32_t type; ++ grub_uint32_t len; ++}; ++ + struct btrfs_ioctl_search_args { + struct btrfs_ioctl_search_key key; + grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key)) +@@ -378,6 +386,109 @@ get_btrfs_fs_prefix (const char *mount_path) + + int use_relative_path_on_btrfs = 0; + ++static char * ++get_btrfs_subvol (const char *path) ++{ ++ struct btrfs_ioctl_ino_lookup_args args; ++ grub_uint64_t tree_id; ++ int fd = -1; ++ char *ret = NULL; ++ ++ fd = open (path, O_RDONLY); ++ ++ if (fd < 0) ++ return NULL; ++ ++ memset (&args, 0, sizeof(args)); ++ args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ tree_id = args.treeid; ++ ++ while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ struct btrfs_ioctl_search_args sargs; ++ struct grub_btrfs_root_backref *br; ++ struct btrfs_ioctl_search_header *search_header; ++ char *old; ++ grub_uint16_t len; ++ grub_uint64_t inode_id; ++ ++ memset (&sargs, 0, sizeof(sargs)); ++ ++ sargs.key.tree_id = 1; ++ sargs.key.min_objectid = tree_id; ++ sargs.key.max_objectid = tree_id; ++ ++ sargs.key.min_offset = 0; ++ sargs.key.max_offset = ~0ULL; ++ sargs.key.min_transid = 0; ++ sargs.key.max_transid = ~0ULL; ++ sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ ++ sargs.key.nr_items = 1; ++ ++ if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0) ++ goto error; ++ ++ if (sargs.key.nr_items == 0) ++ goto error; ++ ++ search_header = (struct btrfs_ioctl_search_header *)sargs.buf; ++ br = (struct grub_btrfs_root_backref *) (search_header + 1); ++ ++ len = grub_le_to_cpu16 (br->n); ++ inode_id = grub_le_to_cpu64 (br->inode_id); ++ tree_id = search_header->offset; ++ ++ old = ret; ++ ret = malloc (len + 1); ++ memcpy (ret, br->name, len); ++ ret[len] = '\0'; ++ ++ if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID) ++ { ++ char *s; ++ ++ memset(&args, 0, sizeof(args)); ++ args.treeid = search_header->offset; ++ args.objectid = inode_id; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ s = xasprintf ("%s%s", args.name, ret); ++ free (ret); ++ ret = s; ++ } ++ ++ if (old) ++ { ++ char *s = xasprintf ("%s/%s", ret, old); ++ free (ret); ++ free (old); ++ ret = s; ++ } ++ } ++ ++ close (fd); ++ return ret; ++ ++error: ++ ++ if (fd >= 0) ++ close (fd); ++ if (ret) ++ free (ret); ++ ++ return NULL; ++} ++ ++void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path); ++ + char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) + { +@@ -519,12 +630,15 @@ again: + else if (grub_strcmp (entries[i].fstype, "btrfs") == 0) + { + ret = grub_find_root_devices_from_btrfs (dir); +- fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); + if (use_relative_path_on_btrfs) + { +- if (fs_prefix) +- free (fs_prefix); + fs_prefix = xstrdup ("/"); ++ if (grub_find_root_btrfs_mount_path_hook) ++ grub_find_root_btrfs_mount_path_hook (entries[i].enc_path); ++ } ++ else ++ { ++ fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); + } + } + else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) +@@ -1150,6 +1264,34 @@ grub_util_get_grub_dev_os (const char *os_dev) + return grub_dev; + } + ++ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path) ++{ ++ char *mp = NULL; ++ ++ if (mount_path) ++ *mount_path = NULL; ++ ++ auto void ++ mount_path_hook (const char *m) ++ { ++ mp = strdup (m); ++ } ++ ++ grub_find_root_btrfs_mount_path_hook = mount_path_hook; ++ grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); ++ grub_find_root_btrfs_mount_path_hook = NULL; ++ ++ if (!mp) ++ return NULL; ++ ++ if (mount_path) ++ *mount_path = mp; ++ ++ return get_btrfs_subvol (mp); ++} ++ + char * + grub_make_system_path_relative_to_its_root_os (const char *path) + { +diff --git a/util/grub-install.c b/util/grub-install.c +index 0f66f36d23..84ed6e88ec 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1569,6 +1569,55 @@ main (int argc, char *argv[]) + prefix_drive = xasprintf ("(%s)", grub_drives[0]); + } + ++#ifdef __linux__ ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ char *subvol = NULL; ++ char *mount_path = NULL; ++ char **rootdir_devices = NULL; ++ char *rootdir_path = grub_util_path_concat (2, "/", rootdir); ++ ++ if (grub_util_is_directory (rootdir_path)) ++ rootdir_devices = grub_guess_root_devices (rootdir_path); ++ ++ free (rootdir_path); ++ ++ if (rootdir_devices && rootdir_devices[0]) ++ if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) ++ subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); ++ ++ if (subvol && mount_path) ++ { ++ char *def_subvol; ++ ++ def_subvol = grub_util_get_btrfs_subvol ("/", NULL); ++ ++ if (def_subvol) ++ { ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ ++ if (grub_strcmp (subvol, def_subvol) != 0) ++ fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", mount_path, subvol); ++ free (def_subvol); ++ } ++ } ++ ++ for (curdev = rootdir_devices; *curdev; curdev++) ++ free (*curdev); ++ if (rootdir_devices) ++ free (rootdir_devices); ++ if (subvol) ++ free (subvol); ++ if (mount_path) ++ free (mount_path); ++ } ++ ++#endif ++ + char mkimage_target[200]; + const char *core_name = NULL; + +diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h +index 73fa2d34ab..9c642ae3fe 100644 +--- a/include/grub/emu/getroot.h ++++ b/include/grub/emu/getroot.h +@@ -53,6 +53,11 @@ char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot); + #endif + ++#ifdef __linux__ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path); ++#endif ++ + /* Devmapper functions provided by getroot_devmapper.c. */ + void + grub_util_pull_devmapper (const char *os_dev); diff --git a/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch b/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch new file mode 100644 index 0000000..a5db09a --- /dev/null +++ b/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrei Borzenkov +Date: Tue, 21 Jun 2016 16:44:17 +0000 +Subject: [PATCH] Fallback to old subvol name scheme to support old snapshot + config + +Ref: bsc#953538 +--- + grub-core/fs/btrfs.c | 32 +++++++++++++++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index d323746ecf..673ded0352 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1260,11 +1260,41 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path) + return GRUB_ERR_NONE; + } + ++static grub_err_t ++lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ struct grub_btrfs_key key; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) + { + if (btrfs_default_subvol) +- return lookup_root_by_name(data, btrfs_default_subvol); ++ { ++ grub_err_t err; ++ err = lookup_root_by_name(data, btrfs_default_subvol); ++ ++ /* Fallback to old schemes */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ err = GRUB_ERR_NONE; ++ return lookup_root_by_name_fallback(data, btrfs_default_subvol); ++ } ++ return err; ++ } + + if (btrfs_default_subvolid) + return lookup_root_by_id(data, btrfs_default_subvolid); diff --git a/0047-grub2-btrfs-06-subvol-mount.patch b/0047-grub2-btrfs-06-subvol-mount.patch deleted file mode 100644 index 8cdf247..0000000 --- a/0047-grub2-btrfs-06-subvol-mount.patch +++ /dev/null @@ -1,539 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Tue, 9 Jul 2019 13:56:16 +0200 -Subject: [PATCH] grub2-btrfs-06-subvol-mount - -Signed-off-by: Michael Chang -Signed-off-by: Robbie Harwood ---- - grub-core/fs/btrfs.c | 195 +++++++++++++++++++++++++++++++++++++++- - grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++++++++- - util/grub-install.c | 49 ++++++++++ - include/grub/emu/getroot.h | 5 ++ - 4 files changed, 392 insertions(+), 5 deletions(-) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 113c1f746c..d323746ecf 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -41,6 +41,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -266,6 +267,12 @@ static grub_err_t - grub_btrfs_read_logical (struct grub_btrfs_data *data, - grub_disk_addr_t addr, void *buf, grub_size_t size, - int recursion_depth); -+static grub_err_t -+get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, -+ grub_uint64_t *tree, grub_uint8_t *type); -+ -+grub_uint64_t -+find_mtab_subvol_tree (const char *path, char **path_in_subvol); - - static grub_err_t - read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) -@@ -1223,9 +1230,26 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path) - grub_err_t err; - grub_uint64_t tree = 0; - grub_uint8_t type; -+ grub_uint64_t saved_tree; - struct grub_btrfs_key key; - -+ if (path[0] == '\0') -+ { -+ data->fs_tree = 0; -+ return GRUB_ERR_NONE; -+ } -+ -+ err = get_root (data, &key, &tree, &type); -+ if (err) -+ return err; -+ -+ saved_tree = data->fs_tree; -+ data->fs_tree = tree; -+ - err = find_path (data, path, &key, &tree, &type); -+ -+ data->fs_tree = saved_tree; -+ - if (err) - return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); - -@@ -2199,11 +2223,20 @@ grub_btrfs_dir (grub_device_t device, const char *path, - int r = 0; - grub_uint64_t tree; - grub_uint8_t type; -+ char *new_path = NULL; - - if (!data) - return grub_errno; - -- err = find_path (data, path, &key_in, &tree, &type); -+ tree = find_mtab_subvol_tree (path, &new_path); -+ -+ if (tree) -+ data->fs_tree = tree; -+ -+ err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type); -+ if (new_path) -+ grub_free (new_path); -+ - if (err) - { - grub_btrfs_unmount (data); -@@ -2305,11 +2338,21 @@ grub_btrfs_open (struct grub_file *file, const char *name) - struct grub_btrfs_inode inode; - grub_uint8_t type; - struct grub_btrfs_key key_in; -+ grub_uint64_t tree; -+ char *new_path = NULL; - - if (!data) - return grub_errno; - -- err = find_path (data, name, &key_in, &data->tree, &type); -+ tree = find_mtab_subvol_tree (name, &new_path); -+ -+ if (tree) -+ data->fs_tree = tree; -+ -+ err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type); -+ if (new_path) -+ grub_free (new_path); -+ - if (err) - { - grub_btrfs_unmount (data); -@@ -2480,6 +2523,150 @@ grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, - return 0; - } - -+struct grub_btrfs_mtab -+{ -+ struct grub_btrfs_mtab *next; -+ struct grub_btrfs_mtab **prev; -+ char *path; -+ char *subvol; -+ grub_uint64_t tree; -+}; -+ -+typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t; -+ -+static struct grub_btrfs_mtab *btrfs_mtab; -+ -+#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab) -+#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab) -+ -+static void -+add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree) -+{ -+ grub_btrfs_mtab_t m = grub_malloc (sizeof (*m)); -+ -+ m->path = grub_strdup (path); -+ m->subvol = grub_strdup (subvol); -+ m->tree = tree; -+ grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m)); -+} -+ -+static grub_err_t -+grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc, -+ char **argv) -+{ -+ char *devname, *dirname, *subvol; -+ struct grub_btrfs_key key_in; -+ grub_uint8_t type; -+ grub_uint64_t tree; -+ grub_uint64_t saved_tree; -+ grub_err_t err; -+ struct grub_btrfs_data *data = NULL; -+ grub_device_t dev = NULL; -+ -+ if (argc < 3) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "required and "); -+ -+ devname = grub_file_get_device_name(argv[0]); -+ dev = grub_device_open (devname); -+ grub_free (devname); -+ -+ if (!dev) -+ { -+ err = grub_errno; -+ goto err_out; -+ } -+ -+ dirname = argv[1]; -+ subvol = argv[2]; -+ -+ data = grub_btrfs_mount (dev); -+ if (!data) -+ { -+ err = grub_errno; -+ goto err_out; -+ } -+ -+ err = find_path (data, dirname, &key_in, &tree, &type); -+ if (err) -+ goto err_out; -+ -+ if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) -+ { -+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); -+ goto err_out; -+ } -+ -+ err = get_root (data, &key_in, &tree, &type); -+ -+ if (err) -+ goto err_out; -+ -+ saved_tree = data->fs_tree; -+ data->fs_tree = tree; -+ err = find_path (data, subvol, &key_in, &tree, &type); -+ data->fs_tree = saved_tree; -+ -+ if (err) -+ goto err_out; -+ -+ if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) -+ { -+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol); -+ goto err_out; -+ } -+ -+ grub_btrfs_unmount (data); -+ grub_device_close (dev); -+ add_mountpoint (dirname, subvol, tree); -+ -+ return GRUB_ERR_NONE; -+ -+err_out: -+ -+ if (data) -+ grub_btrfs_unmount (data); -+ -+ if (dev) -+ grub_device_close (dev); -+ -+ return err; -+} -+ -+grub_uint64_t -+find_mtab_subvol_tree (const char *path, char **path_in_subvol) -+{ -+ grub_btrfs_mtab_t m, cm; -+ grub_uint64_t tree; -+ -+ if (!path || !path_in_subvol) -+ return 0; -+ -+ *path_in_subvol = NULL; -+ tree = 0; -+ cm = NULL; -+ -+ FOR_GRUB_MTAB (m) -+ { -+ if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0) -+ { -+ if (!cm) -+ cm = m; -+ else -+ if (grub_strcmp (m->path, cm->path) > 0) -+ cm = m; -+ } -+ } -+ -+ if (cm) -+ { -+ const char *s = path + grub_strlen (cm->path); -+ *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s); -+ tree = cm->tree; -+ } -+ -+ return tree; -+} -+ - static grub_err_t - get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, - grub_uint64_t objectid, grub_uint64_t offset, -@@ -2686,6 +2873,7 @@ static struct grub_fs grub_btrfs_fs = { - }; - - static grub_command_t cmd_info; -+static grub_command_t cmd_mount_subvol; - static grub_extcmd_t cmd_list_subvols; - - static char * -@@ -2749,6 +2937,9 @@ GRUB_MOD_INIT (btrfs) - cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, - "DEVICE", - "Print BtrFS info about DEVICE."); -+ cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol, -+ "DEVICE DIRECTORY SUBVOL", -+ "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL."); - cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", - grub_cmd_btrfs_list_subvols, 0, - "[-p|-n] [-o var] DEVICE", -diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c -index caf9b1ccd3..28790307e0 100644 ---- a/grub-core/osdep/linux/getroot.c -+++ b/grub-core/osdep/linux/getroot.c -@@ -107,6 +107,14 @@ struct btrfs_ioctl_search_key - grub_uint32_t unused[9]; - }; - -+struct btrfs_ioctl_search_header { -+ grub_uint64_t transid; -+ grub_uint64_t objectid; -+ grub_uint64_t offset; -+ grub_uint32_t type; -+ grub_uint32_t len; -+}; -+ - struct btrfs_ioctl_search_args { - struct btrfs_ioctl_search_key key; - grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key)) -@@ -378,6 +386,109 @@ get_btrfs_fs_prefix (const char *mount_path) - - int use_relative_path_on_btrfs = 0; - -+static char * -+get_btrfs_subvol (const char *path) -+{ -+ struct btrfs_ioctl_ino_lookup_args args; -+ grub_uint64_t tree_id; -+ int fd = -1; -+ char *ret = NULL; -+ -+ fd = open (path, O_RDONLY); -+ -+ if (fd < 0) -+ return NULL; -+ -+ memset (&args, 0, sizeof(args)); -+ args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID; -+ -+ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) -+ goto error; -+ -+ tree_id = args.treeid; -+ -+ while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID) -+ { -+ struct btrfs_ioctl_search_args sargs; -+ struct grub_btrfs_root_backref *br; -+ struct btrfs_ioctl_search_header *search_header; -+ char *old; -+ grub_uint16_t len; -+ grub_uint64_t inode_id; -+ -+ memset (&sargs, 0, sizeof(sargs)); -+ -+ sargs.key.tree_id = 1; -+ sargs.key.min_objectid = tree_id; -+ sargs.key.max_objectid = tree_id; -+ -+ sargs.key.min_offset = 0; -+ sargs.key.max_offset = ~0ULL; -+ sargs.key.min_transid = 0; -+ sargs.key.max_transid = ~0ULL; -+ sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; -+ sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; -+ -+ sargs.key.nr_items = 1; -+ -+ if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0) -+ goto error; -+ -+ if (sargs.key.nr_items == 0) -+ goto error; -+ -+ search_header = (struct btrfs_ioctl_search_header *)sargs.buf; -+ br = (struct grub_btrfs_root_backref *) (search_header + 1); -+ -+ len = grub_le_to_cpu16 (br->n); -+ inode_id = grub_le_to_cpu64 (br->inode_id); -+ tree_id = search_header->offset; -+ -+ old = ret; -+ ret = malloc (len + 1); -+ memcpy (ret, br->name, len); -+ ret[len] = '\0'; -+ -+ if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID) -+ { -+ char *s; -+ -+ memset(&args, 0, sizeof(args)); -+ args.treeid = search_header->offset; -+ args.objectid = inode_id; -+ -+ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) -+ goto error; -+ -+ s = xasprintf ("%s%s", args.name, ret); -+ free (ret); -+ ret = s; -+ } -+ -+ if (old) -+ { -+ char *s = xasprintf ("%s/%s", ret, old); -+ free (ret); -+ free (old); -+ ret = s; -+ } -+ } -+ -+ close (fd); -+ return ret; -+ -+error: -+ -+ if (fd >= 0) -+ close (fd); -+ if (ret) -+ free (ret); -+ -+ return NULL; -+} -+ -+void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path); -+ - char ** - grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) - { -@@ -519,12 +630,15 @@ again: - else if (grub_strcmp (entries[i].fstype, "btrfs") == 0) - { - ret = grub_find_root_devices_from_btrfs (dir); -- fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); - if (use_relative_path_on_btrfs) - { -- if (fs_prefix) -- free (fs_prefix); - fs_prefix = xstrdup ("/"); -+ if (grub_find_root_btrfs_mount_path_hook) -+ grub_find_root_btrfs_mount_path_hook (entries[i].enc_path); -+ } -+ else -+ { -+ fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); - } - } - else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) -@@ -1150,6 +1264,34 @@ grub_util_get_grub_dev_os (const char *os_dev) - return grub_dev; - } - -+ -+char * -+grub_util_get_btrfs_subvol (const char *path, char **mount_path) -+{ -+ char *mp = NULL; -+ -+ if (mount_path) -+ *mount_path = NULL; -+ -+ auto void -+ mount_path_hook (const char *m) -+ { -+ mp = strdup (m); -+ } -+ -+ grub_find_root_btrfs_mount_path_hook = mount_path_hook; -+ grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); -+ grub_find_root_btrfs_mount_path_hook = NULL; -+ -+ if (!mp) -+ return NULL; -+ -+ if (mount_path) -+ *mount_path = mp; -+ -+ return get_btrfs_subvol (mp); -+} -+ - char * - grub_make_system_path_relative_to_its_root_os (const char *path) - { -diff --git a/util/grub-install.c b/util/grub-install.c -index 0f66f36d23..84ed6e88ec 100644 ---- a/util/grub-install.c -+++ b/util/grub-install.c -@@ -1569,6 +1569,55 @@ main (int argc, char *argv[]) - prefix_drive = xasprintf ("(%s)", grub_drives[0]); - } - -+#ifdef __linux__ -+ -+ if (config.is_suse_btrfs_snapshot_enabled -+ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) -+ { -+ char *subvol = NULL; -+ char *mount_path = NULL; -+ char **rootdir_devices = NULL; -+ char *rootdir_path = grub_util_path_concat (2, "/", rootdir); -+ -+ if (grub_util_is_directory (rootdir_path)) -+ rootdir_devices = grub_guess_root_devices (rootdir_path); -+ -+ free (rootdir_path); -+ -+ if (rootdir_devices && rootdir_devices[0]) -+ if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) -+ subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); -+ -+ if (subvol && mount_path) -+ { -+ char *def_subvol; -+ -+ def_subvol = grub_util_get_btrfs_subvol ("/", NULL); -+ -+ if (def_subvol) -+ { -+ if (!load_cfg_f) -+ load_cfg_f = grub_util_fopen (load_cfg, "wb"); -+ have_load_cfg = 1; -+ -+ if (grub_strcmp (subvol, def_subvol) != 0) -+ fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", mount_path, subvol); -+ free (def_subvol); -+ } -+ } -+ -+ for (curdev = rootdir_devices; *curdev; curdev++) -+ free (*curdev); -+ if (rootdir_devices) -+ free (rootdir_devices); -+ if (subvol) -+ free (subvol); -+ if (mount_path) -+ free (mount_path); -+ } -+ -+#endif -+ - char mkimage_target[200]; - const char *core_name = NULL; - -diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h -index 73fa2d34ab..9c642ae3fe 100644 ---- a/include/grub/emu/getroot.h -+++ b/include/grub/emu/getroot.h -@@ -53,6 +53,11 @@ char ** - grub_find_root_devices_from_mountinfo (const char *dir, char **relroot); - #endif - -+#ifdef __linux__ -+char * -+grub_util_get_btrfs_subvol (const char *path, char **mount_path); -+#endif -+ - /* Devmapper functions provided by getroot_devmapper.c. */ - void - grub_util_pull_devmapper (const char *os_dev); diff --git a/0048-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch b/0048-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch deleted file mode 100644 index a5db09a..0000000 --- a/0048-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrei Borzenkov -Date: Tue, 21 Jun 2016 16:44:17 +0000 -Subject: [PATCH] Fallback to old subvol name scheme to support old snapshot - config - -Ref: bsc#953538 ---- - grub-core/fs/btrfs.c | 32 +++++++++++++++++++++++++++++++- - 1 file changed, 31 insertions(+), 1 deletion(-) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index d323746ecf..673ded0352 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -1260,11 +1260,41 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path) - return GRUB_ERR_NONE; - } - -+static grub_err_t -+lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path) -+{ -+ grub_err_t err; -+ grub_uint64_t tree = 0; -+ grub_uint8_t type; -+ struct grub_btrfs_key key; -+ -+ err = find_path (data, path, &key, &tree, &type); -+ if (err) -+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); -+ -+ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) -+ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); -+ -+ data->fs_tree = tree; -+ return GRUB_ERR_NONE; -+} -+ - static grub_err_t - btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) - { - if (btrfs_default_subvol) -- return lookup_root_by_name(data, btrfs_default_subvol); -+ { -+ grub_err_t err; -+ err = lookup_root_by_name(data, btrfs_default_subvol); -+ -+ /* Fallback to old schemes */ -+ if (err == GRUB_ERR_FILE_NOT_FOUND) -+ { -+ err = GRUB_ERR_NONE; -+ return lookup_root_by_name_fallback(data, btrfs_default_subvol); -+ } -+ return err; -+ } - - if (btrfs_default_subvolid) - return lookup_root_by_id(data, btrfs_default_subvolid); diff --git a/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch b/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch new file mode 100644 index 0000000..99c106d --- /dev/null +++ b/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch @@ -0,0 +1,274 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 11 May 2017 08:56:57 +0000 +Subject: [PATCH] Grub not working correctly with btrfs snapshots (bsc#1026511) + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 238 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 673ded0352..2b21cbaa67 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2887,6 +2887,238 @@ out: + return 0; + } + ++static grub_err_t ++grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data, ++ grub_uint64_t child_id, ++ const char *child_path, ++ grub_uint64_t *parent_id, ++ char **path_out) ++{ ++ grub_uint64_t fs_root = 0; ++ struct grub_btrfs_key key_in = { ++ .object_id = child_id, ++ .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_root_ref *ref; ++ char *buf; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_size_t elemsize; ++ grub_disk_addr_t elemaddr; ++ grub_err_t err; ++ char *parent_path; ++ ++ *parent_id = 0; ++ *path_out = 0; ++ ++ err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF) ++ { ++ free_iterator(&desc); ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs")); ++ } ++ ++ buf = grub_malloc(elemsize + 1); ++ if (!buf) ++ { ++ free_iterator(&desc); ++ return grub_errno; ++ } ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ buf[elemsize] = 0; ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset), ++ 0, &fs_root); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path); ++ ++ if (child_path) ++ { ++ *path_out = grub_xasprintf ("%s/%s", parent_path, child_path); ++ grub_free (parent_path); ++ } ++ else ++ *path_out = parent_path; ++ ++ *parent_id = grub_le_to_cpu64 (key_out.offset); ++ ++ grub_free(buf); ++ free_iterator(&desc); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id) ++{ ++ grub_err_t err; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_key key, key_out; ++ struct grub_btrfs_dir_item *direl = NULL; ++ const char *ctoken = "default"; ++ grub_size_t ctokenlen = sizeof ("default") - 1; ++ ++ *id = 0; ++ key.object_id = data->sblock.root_dir_objectid; ++ key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); ++ err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize, ++ NULL, 0); ++ if (err) ++ return err; ++ ++ if (key_cmp (&key, &key_out) != 0) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ ++ struct grub_btrfs_dir_item *cdirel; ++ direl = grub_malloc (elemsize + 1); ++ err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0); ++ if (err) ++ { ++ grub_free (direl); ++ return err; ++ } ++ for (cdirel = direl; ++ (grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ < (grub_ssize_t) elemsize; ++ cdirel = (void *) ((grub_uint8_t *) (direl + 1) ++ + grub_le_to_cpu16 (cdirel->n) ++ + grub_le_to_cpu16 (cdirel->m))) ++ { ++ if (ctokenlen == grub_le_to_cpu16 (cdirel->n) ++ && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0) ++ break; ++ } ++ if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ >= (grub_ssize_t) elemsize) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ *id = grub_le_to_cpu64 (cdirel->key.object_id); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ char *devname; ++ grub_device_t dev; ++ struct grub_btrfs_data *data; ++ grub_err_t err; ++ grub_uint64_t id; ++ char *subvol = NULL; ++ grub_uint64_t subvolid = 0; ++ char *varname = NULL; ++ char *output = NULL; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ ++ if (ctxt->state[0].set) ++ varname = ctxt->state[0].arg; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ { ++ grub_device_close (dev); ++ grub_dprintf ("btrfs", "failed to open fs\n"); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ ++ err = grub_btrfs_get_default_subvolume_id (data, &subvolid); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ id = subvolid; ++ while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ grub_uint64_t parent_id; ++ char *path_out; ++ ++ err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ if (subvol) ++ grub_free (subvol); ++ subvol = path_out; ++ id = parent_id; ++ } ++ ++ if (num_only && path_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol); ++ else if (num_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid); ++ else ++ output = grub_xasprintf ("/%s", subvol); ++ ++ if (varname) ++ grub_env_set(varname, output); ++ else ++ grub_printf ("%s\n", output); ++ ++ grub_free (output); ++ grub_free (subvol); ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ ++ return GRUB_ERR_NONE; ++} ++ + static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, +@@ -2905,6 +3137,7 @@ static struct grub_fs grub_btrfs_fs = { + static grub_command_t cmd_info; + static grub_command_t cmd_mount_subvol; + static grub_extcmd_t cmd_list_subvols; ++static grub_extcmd_t cmd_get_default_subvol; + + static char * + subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), +@@ -2975,6 +3208,11 @@ GRUB_MOD_INIT (btrfs) + "[-p|-n] [-o var] DEVICE", + "Print list of BtrFS subvolumes on " + "DEVICE.", options); ++ cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol", ++ grub_cmd_btrfs_get_default_subvol, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print default BtrFS subvolume on " ++ "DEVICE.", options); + grub_register_variable_hook ("btrfs_subvol", subvol_get_env, + subvol_set_env); + grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, diff --git a/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch b/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch new file mode 100644 index 0000000..d07dd27 --- /dev/null +++ b/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 1 Jun 2017 09:59:56 -0400 +Subject: [PATCH] Add grub_efi_allocate_pool() and grub_efi_free_pool() + wrappers. + +Signed-off-by: Peter Jones +--- + include/grub/efi/efi.h | 36 ++++++++++++++++++++++++++++++++---- + 1 file changed, 32 insertions(+), 4 deletions(-) + +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 585fa6662b..03f9a9d011 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -24,6 +24,10 @@ + #include + #include + ++/* Variables. */ ++extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); ++extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); ++ + /* Functions. */ + void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol, + void *registration); +@@ -60,6 +64,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); + void grub_efi_memory_fini (void); ++ ++static inline grub_efi_status_t ++__attribute__((__unused__)) ++grub_efi_allocate_pool (grub_efi_memory_type_t pool_type, ++ grub_efi_uintn_t buffer_size, ++ void **buffer) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_3 (b->allocate_pool, pool_type, buffer_size, buffer); ++ return status; ++} ++ ++static inline grub_efi_status_t ++__attribute__((__unused__)) ++grub_efi_free_pool (void *buffer) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_1 (b->free_pool, buffer); ++ return status; ++} ++ + grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle); + void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); + char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); +@@ -115,10 +146,7 @@ void grub_efi_init (void); + void grub_efi_fini (void); + void grub_efi_set_prefix (void); + +-/* Variables. */ +-extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); +-extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); +- ++/* More variables. */ + extern int EXPORT_VAR(grub_efi_is_finished); + + struct grub_net_card; diff --git a/0049-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch b/0049-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch deleted file mode 100644 index 99c106d..0000000 --- a/0049-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch +++ /dev/null @@ -1,274 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Thu, 11 May 2017 08:56:57 +0000 -Subject: [PATCH] Grub not working correctly with btrfs snapshots (bsc#1026511) - -Signed-off-by: Michael Chang -Signed-off-by: Robbie Harwood ---- - grub-core/fs/btrfs.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 238 insertions(+) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 673ded0352..2b21cbaa67 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -2887,6 +2887,238 @@ out: - return 0; - } - -+static grub_err_t -+grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data, -+ grub_uint64_t child_id, -+ const char *child_path, -+ grub_uint64_t *parent_id, -+ char **path_out) -+{ -+ grub_uint64_t fs_root = 0; -+ struct grub_btrfs_key key_in = { -+ .object_id = child_id, -+ .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF, -+ .offset = 0, -+ }, key_out; -+ struct grub_btrfs_root_ref *ref; -+ char *buf; -+ struct grub_btrfs_leaf_descriptor desc; -+ grub_size_t elemsize; -+ grub_disk_addr_t elemaddr; -+ grub_err_t err; -+ char *parent_path; -+ -+ *parent_id = 0; -+ *path_out = 0; -+ -+ err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree, -+ &elemaddr, &elemsize, &desc, 0); -+ if (err) -+ return err; -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0) -+ next(data, &desc, &elemaddr, &elemsize, &key_out); -+ -+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF) -+ { -+ free_iterator(&desc); -+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs")); -+ } -+ -+ buf = grub_malloc(elemsize + 1); -+ if (!buf) -+ { -+ free_iterator(&desc); -+ return grub_errno; -+ } -+ -+ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); -+ if (err) -+ { -+ grub_free(buf); -+ free_iterator(&desc); -+ return err; -+ } -+ -+ buf[elemsize] = 0; -+ ref = (struct grub_btrfs_root_ref *)buf; -+ -+ err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset), -+ 0, &fs_root); -+ if (err) -+ { -+ grub_free(buf); -+ free_iterator(&desc); -+ return err; -+ } -+ -+ find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path); -+ -+ if (child_path) -+ { -+ *path_out = grub_xasprintf ("%s/%s", parent_path, child_path); -+ grub_free (parent_path); -+ } -+ else -+ *path_out = parent_path; -+ -+ *parent_id = grub_le_to_cpu64 (key_out.offset); -+ -+ grub_free(buf); -+ free_iterator(&desc); -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id) -+{ -+ grub_err_t err; -+ grub_disk_addr_t elemaddr; -+ grub_size_t elemsize; -+ struct grub_btrfs_key key, key_out; -+ struct grub_btrfs_dir_item *direl = NULL; -+ const char *ctoken = "default"; -+ grub_size_t ctokenlen = sizeof ("default") - 1; -+ -+ *id = 0; -+ key.object_id = data->sblock.root_dir_objectid; -+ key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; -+ key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); -+ err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize, -+ NULL, 0); -+ if (err) -+ return err; -+ -+ if (key_cmp (&key, &key_out) != 0) -+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); -+ -+ struct grub_btrfs_dir_item *cdirel; -+ direl = grub_malloc (elemsize + 1); -+ err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0); -+ if (err) -+ { -+ grub_free (direl); -+ return err; -+ } -+ for (cdirel = direl; -+ (grub_uint8_t *) cdirel - (grub_uint8_t *) direl -+ < (grub_ssize_t) elemsize; -+ cdirel = (void *) ((grub_uint8_t *) (direl + 1) -+ + grub_le_to_cpu16 (cdirel->n) -+ + grub_le_to_cpu16 (cdirel->m))) -+ { -+ if (ctokenlen == grub_le_to_cpu16 (cdirel->n) -+ && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0) -+ break; -+ } -+ if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl -+ >= (grub_ssize_t) elemsize) -+ { -+ grub_free (direl); -+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); -+ return err; -+ } -+ -+ if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM) -+ { -+ grub_free (direl); -+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); -+ return err; -+ } -+ -+ *id = grub_le_to_cpu64 (cdirel->key.object_id); -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt, -+ int argc, char **argv) -+{ -+ char *devname; -+ grub_device_t dev; -+ struct grub_btrfs_data *data; -+ grub_err_t err; -+ grub_uint64_t id; -+ char *subvol = NULL; -+ grub_uint64_t subvolid = 0; -+ char *varname = NULL; -+ char *output = NULL; -+ int path_only = ctxt->state[1].set; -+ int num_only = ctxt->state[2].set; -+ -+ if (ctxt->state[0].set) -+ varname = ctxt->state[0].arg; -+ -+ if (argc < 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); -+ -+ devname = grub_file_get_device_name(argv[0]); -+ if (!devname) -+ return grub_errno; -+ -+ dev = grub_device_open (devname); -+ grub_free (devname); -+ if (!dev) -+ return grub_errno; -+ -+ data = grub_btrfs_mount(dev); -+ if (!data) -+ { -+ grub_device_close (dev); -+ grub_dprintf ("btrfs", "failed to open fs\n"); -+ grub_errno = GRUB_ERR_NONE; -+ return 0; -+ } -+ -+ err = grub_btrfs_get_default_subvolume_id (data, &subvolid); -+ if (err) -+ { -+ grub_btrfs_unmount (data); -+ grub_device_close (dev); -+ return err; -+ } -+ -+ id = subvolid; -+ while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID) -+ { -+ grub_uint64_t parent_id; -+ char *path_out; -+ -+ err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out); -+ if (err) -+ { -+ grub_btrfs_unmount (data); -+ grub_device_close (dev); -+ return err; -+ } -+ -+ if (subvol) -+ grub_free (subvol); -+ subvol = path_out; -+ id = parent_id; -+ } -+ -+ if (num_only && path_only) -+ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol); -+ else if (num_only) -+ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid); -+ else -+ output = grub_xasprintf ("/%s", subvol); -+ -+ if (varname) -+ grub_env_set(varname, output); -+ else -+ grub_printf ("%s\n", output); -+ -+ grub_free (output); -+ grub_free (subvol); -+ -+ grub_btrfs_unmount (data); -+ grub_device_close (dev); -+ -+ return GRUB_ERR_NONE; -+} -+ - static struct grub_fs grub_btrfs_fs = { - .name = "btrfs", - .fs_dir = grub_btrfs_dir, -@@ -2905,6 +3137,7 @@ static struct grub_fs grub_btrfs_fs = { - static grub_command_t cmd_info; - static grub_command_t cmd_mount_subvol; - static grub_extcmd_t cmd_list_subvols; -+static grub_extcmd_t cmd_get_default_subvol; - - static char * - subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), -@@ -2975,6 +3208,11 @@ GRUB_MOD_INIT (btrfs) - "[-p|-n] [-o var] DEVICE", - "Print list of BtrFS subvolumes on " - "DEVICE.", options); -+ cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol", -+ grub_cmd_btrfs_get_default_subvol, 0, -+ "[-p|-n] [-o var] DEVICE", -+ "Print default BtrFS subvolume on " -+ "DEVICE.", options); - grub_register_variable_hook ("btrfs_subvol", subvol_get_env, - subvol_set_env); - grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, diff --git a/0050-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch b/0050-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch deleted file mode 100644 index d07dd27..0000000 --- a/0050-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 1 Jun 2017 09:59:56 -0400 -Subject: [PATCH] Add grub_efi_allocate_pool() and grub_efi_free_pool() - wrappers. - -Signed-off-by: Peter Jones ---- - include/grub/efi/efi.h | 36 ++++++++++++++++++++++++++++++++---- - 1 file changed, 32 insertions(+), 4 deletions(-) - -diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h -index 585fa6662b..03f9a9d011 100644 ---- a/include/grub/efi/efi.h -+++ b/include/grub/efi/efi.h -@@ -24,6 +24,10 @@ - #include - #include - -+/* Variables. */ -+extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); -+extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); -+ - /* Functions. */ - void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol, - void *registration); -@@ -60,6 +64,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, - grub_efi_uintn_t *descriptor_size, - grub_efi_uint32_t *descriptor_version); - void grub_efi_memory_fini (void); -+ -+static inline grub_efi_status_t -+__attribute__((__unused__)) -+grub_efi_allocate_pool (grub_efi_memory_type_t pool_type, -+ grub_efi_uintn_t buffer_size, -+ void **buffer) -+{ -+ grub_efi_boot_services_t *b; -+ grub_efi_status_t status; -+ -+ b = grub_efi_system_table->boot_services; -+ status = efi_call_3 (b->allocate_pool, pool_type, buffer_size, buffer); -+ return status; -+} -+ -+static inline grub_efi_status_t -+__attribute__((__unused__)) -+grub_efi_free_pool (void *buffer) -+{ -+ grub_efi_boot_services_t *b; -+ grub_efi_status_t status; -+ -+ b = grub_efi_system_table->boot_services; -+ status = efi_call_1 (b->free_pool, buffer); -+ return status; -+} -+ - grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle); - void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); - char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); -@@ -115,10 +146,7 @@ void grub_efi_init (void); - void grub_efi_fini (void); - void grub_efi_set_prefix (void); - --/* Variables. */ --extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); --extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); -- -+/* More variables. */ - extern int EXPORT_VAR(grub_efi_is_finished); - - struct grub_net_card; diff --git a/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch b/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch new file mode 100644 index 0000000..2a3d27b --- /dev/null +++ b/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 1 Jun 2017 10:06:38 -0400 +Subject: [PATCH] Use grub_efi_...() memory helpers where reasonable. + +This uses grub_efi_allocate_pool(), grub_efi_free_pool(), and +grub_efi_free_pages() instead of open-coded efi_call_N() calls, so we +get more reasonable type checking. + +Signed-off-by: Peter Jones +--- + grub-core/loader/efi/chainloader.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 07c4937898..89ac84cc66 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -65,7 +65,7 @@ grub_chainloader_unload (void) + + b = grub_efi_system_table->boot_services; + efi_call_1 (b->unload_image, image_handle); +- efi_call_2 (b->free_pages, address, pages); ++ grub_efi_free_pages (address, pages); + + grub_free (file_path); + grub_free (cmdline); +@@ -108,7 +108,7 @@ grub_chainloader_boot (void) + } + + if (exit_data) +- efi_call_1 (b->free_pool, exit_data); ++ grub_efi_free_pool (exit_data); + + grub_loader_unset (); + +@@ -527,10 +527,9 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) + static grub_efi_boolean_t + handle_image (void *data, grub_efi_uint32_t datasize) + { +- grub_efi_boot_services_t *b; + grub_efi_loaded_image_t *li, li_bak; + grub_efi_status_t efi_status; +- char *buffer = NULL; ++ void *buffer = NULL; + char *buffer_aligned = NULL; + grub_efi_uint32_t i; + struct grub_pe32_section_table *section; +@@ -541,8 +540,6 @@ handle_image (void *data, grub_efi_uint32_t datasize) + int found_entry_point = 0; + int rc; + +- b = grub_efi_system_table->boot_services; +- + rc = read_header (data, datasize, &context); + if (rc < 0) + { +@@ -582,8 +579,8 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n", + context.image_size, datasize); + +- efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, +- buffer_size, &buffer); ++ efi_status = grub_efi_allocate_pool (GRUB_EFI_LOADER_DATA, buffer_size, ++ &buffer); + + if (efi_status != GRUB_EFI_SUCCESS) + { +@@ -815,14 +812,14 @@ handle_image (void *data, grub_efi_uint32_t datasize) + + grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); + grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); +- efi_status = efi_call_1 (b->free_pool, buffer); ++ efi_status = grub_efi_free_pool (buffer); + + return 1; + + error_exit: + grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno); + if (buffer) +- efi_call_1 (b->free_pool, buffer); ++ grub_efi_free_pool (buffer); + + return 0; + } +@@ -830,10 +827,7 @@ error_exit: + static grub_err_t + grub_secureboot_chainloader_unload (void) + { +- grub_efi_boot_services_t *b; +- +- b = grub_efi_system_table->boot_services; +- efi_call_2 (b->free_pages, address, pages); ++ grub_efi_free_pages (address, pages); + grub_free (file_path); + grub_free (cmdline); + cmdline = 0; +@@ -1100,7 +1094,7 @@ fail: + grub_free (file_path); + + if (address) +- efi_call_2 (b->free_pages, address, pages); ++ grub_efi_free_pages (address, pages); + + if (cmdline) + grub_free (cmdline); diff --git a/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch b/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch new file mode 100644 index 0000000..f649c8c --- /dev/null +++ b/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 1 Jun 2017 10:07:50 -0400 +Subject: [PATCH] Add PRIxGRUB_EFI_STATUS and use it. + +This avoids syntax checkers getting confused about if it's llx or lx. + +Signed-off-by: Peter Jones +--- + grub-core/loader/efi/chainloader.c | 3 ++- + include/grub/efi/api.h | 9 +++++++++ + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 89ac84cc66..ac8dfd40c6 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -810,7 +810,8 @@ handle_image (void *data, grub_efi_uint32_t datasize) + efi_status = efi_call_2 (entry_point, grub_efi_image_handle, + grub_efi_system_table); + +- grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); ++ grub_dprintf ("chain", "entry_point returned 0x%"PRIxGRUB_EFI_STATUS"\n", ++ efi_status); + grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); + efi_status = grub_efi_free_pool (buffer); + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 117469450d..9962880147 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -546,7 +546,16 @@ typedef grub_uint64_t grub_efi_uint64_t; + typedef grub_uint8_t grub_efi_char8_t; + typedef grub_uint16_t grub_efi_char16_t; + ++ + typedef grub_efi_uintn_t grub_efi_status_t; ++/* Make grub_efi_status_t reasonably printable. */ ++#if GRUB_CPU_SIZEOF_VOID_P == 8 ++#define PRIxGRUB_EFI_STATUS "lx" ++#define PRIdGRUB_EFI_STATUS "ld" ++#else ++#define PRIxGRUB_EFI_STATUS "llx" ++#define PRIdGRUB_EFI_STATUS "lld" ++#endif + + #define GRUB_EFI_ERROR_CODE(value) \ + ((((grub_efi_status_t) 1) << (sizeof (grub_efi_status_t) * 8 - 1)) | (value)) diff --git a/0051-Use-grub_efi_.-memory-helpers-where-reasonable.patch b/0051-Use-grub_efi_.-memory-helpers-where-reasonable.patch deleted file mode 100644 index 2a3d27b..0000000 --- a/0051-Use-grub_efi_.-memory-helpers-where-reasonable.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 1 Jun 2017 10:06:38 -0400 -Subject: [PATCH] Use grub_efi_...() memory helpers where reasonable. - -This uses grub_efi_allocate_pool(), grub_efi_free_pool(), and -grub_efi_free_pages() instead of open-coded efi_call_N() calls, so we -get more reasonable type checking. - -Signed-off-by: Peter Jones ---- - grub-core/loader/efi/chainloader.c | 24 +++++++++--------------- - 1 file changed, 9 insertions(+), 15 deletions(-) - -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index 07c4937898..89ac84cc66 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -65,7 +65,7 @@ grub_chainloader_unload (void) - - b = grub_efi_system_table->boot_services; - efi_call_1 (b->unload_image, image_handle); -- efi_call_2 (b->free_pages, address, pages); -+ grub_efi_free_pages (address, pages); - - grub_free (file_path); - grub_free (cmdline); -@@ -108,7 +108,7 @@ grub_chainloader_boot (void) - } - - if (exit_data) -- efi_call_1 (b->free_pool, exit_data); -+ grub_efi_free_pool (exit_data); - - grub_loader_unset (); - -@@ -527,10 +527,9 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) - static grub_efi_boolean_t - handle_image (void *data, grub_efi_uint32_t datasize) - { -- grub_efi_boot_services_t *b; - grub_efi_loaded_image_t *li, li_bak; - grub_efi_status_t efi_status; -- char *buffer = NULL; -+ void *buffer = NULL; - char *buffer_aligned = NULL; - grub_efi_uint32_t i; - struct grub_pe32_section_table *section; -@@ -541,8 +540,6 @@ handle_image (void *data, grub_efi_uint32_t datasize) - int found_entry_point = 0; - int rc; - -- b = grub_efi_system_table->boot_services; -- - rc = read_header (data, datasize, &context); - if (rc < 0) - { -@@ -582,8 +579,8 @@ handle_image (void *data, grub_efi_uint32_t datasize) - grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n", - context.image_size, datasize); - -- efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, -- buffer_size, &buffer); -+ efi_status = grub_efi_allocate_pool (GRUB_EFI_LOADER_DATA, buffer_size, -+ &buffer); - - if (efi_status != GRUB_EFI_SUCCESS) - { -@@ -815,14 +812,14 @@ handle_image (void *data, grub_efi_uint32_t datasize) - - grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); - grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); -- efi_status = efi_call_1 (b->free_pool, buffer); -+ efi_status = grub_efi_free_pool (buffer); - - return 1; - - error_exit: - grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno); - if (buffer) -- efi_call_1 (b->free_pool, buffer); -+ grub_efi_free_pool (buffer); - - return 0; - } -@@ -830,10 +827,7 @@ error_exit: - static grub_err_t - grub_secureboot_chainloader_unload (void) - { -- grub_efi_boot_services_t *b; -- -- b = grub_efi_system_table->boot_services; -- efi_call_2 (b->free_pages, address, pages); -+ grub_efi_free_pages (address, pages); - grub_free (file_path); - grub_free (cmdline); - cmdline = 0; -@@ -1100,7 +1094,7 @@ fail: - grub_free (file_path); - - if (address) -- efi_call_2 (b->free_pages, address, pages); -+ grub_efi_free_pages (address, pages); - - if (cmdline) - grub_free (cmdline); diff --git a/0052-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch b/0052-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch deleted file mode 100644 index f649c8c..0000000 --- a/0052-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 1 Jun 2017 10:07:50 -0400 -Subject: [PATCH] Add PRIxGRUB_EFI_STATUS and use it. - -This avoids syntax checkers getting confused about if it's llx or lx. - -Signed-off-by: Peter Jones ---- - grub-core/loader/efi/chainloader.c | 3 ++- - include/grub/efi/api.h | 9 +++++++++ - 2 files changed, 11 insertions(+), 1 deletion(-) - -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index 89ac84cc66..ac8dfd40c6 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -810,7 +810,8 @@ handle_image (void *data, grub_efi_uint32_t datasize) - efi_status = efi_call_2 (entry_point, grub_efi_image_handle, - grub_efi_system_table); - -- grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); -+ grub_dprintf ("chain", "entry_point returned 0x%"PRIxGRUB_EFI_STATUS"\n", -+ efi_status); - grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); - efi_status = grub_efi_free_pool (buffer); - -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index 117469450d..9962880147 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -546,7 +546,16 @@ typedef grub_uint64_t grub_efi_uint64_t; - typedef grub_uint8_t grub_efi_char8_t; - typedef grub_uint16_t grub_efi_char16_t; - -+ - typedef grub_efi_uintn_t grub_efi_status_t; -+/* Make grub_efi_status_t reasonably printable. */ -+#if GRUB_CPU_SIZEOF_VOID_P == 8 -+#define PRIxGRUB_EFI_STATUS "lx" -+#define PRIdGRUB_EFI_STATUS "ld" -+#else -+#define PRIxGRUB_EFI_STATUS "llx" -+#define PRIdGRUB_EFI_STATUS "lld" -+#endif - - #define GRUB_EFI_ERROR_CODE(value) \ - ((((grub_efi_status_t) 1) << (sizeof (grub_efi_status_t) * 8 - 1)) | (value)) diff --git a/0052-don-t-use-int-for-efi-status.patch b/0052-don-t-use-int-for-efi-status.patch new file mode 100644 index 0000000..4d48e37 --- /dev/null +++ b/0052-don-t-use-int-for-efi-status.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 26 Jun 2017 12:44:59 -0400 +Subject: [PATCH] don't use int for efi status + +--- + grub-core/kern/efi/efi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 05d8237a9b..ae9885edb8 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -167,7 +167,7 @@ grub_reboot (void) + void + grub_exit (int retval) + { +- int rc = GRUB_EFI_LOAD_ERROR; ++ grub_efi_status_t rc = GRUB_EFI_LOAD_ERROR; + + if (retval == 0) + rc = GRUB_EFI_SUCCESS; diff --git a/0053-don-t-use-int-for-efi-status.patch b/0053-don-t-use-int-for-efi-status.patch deleted file mode 100644 index 4d48e37..0000000 --- a/0053-don-t-use-int-for-efi-status.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 26 Jun 2017 12:44:59 -0400 -Subject: [PATCH] don't use int for efi status - ---- - grub-core/kern/efi/efi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c -index 05d8237a9b..ae9885edb8 100644 ---- a/grub-core/kern/efi/efi.c -+++ b/grub-core/kern/efi/efi.c -@@ -167,7 +167,7 @@ grub_reboot (void) - void - grub_exit (int retval) - { -- int rc = GRUB_EFI_LOAD_ERROR; -+ grub_efi_status_t rc = GRUB_EFI_LOAD_ERROR; - - if (retval == 0) - rc = GRUB_EFI_SUCCESS; diff --git a/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch b/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch new file mode 100644 index 0000000..fb71ea5 --- /dev/null +++ b/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 26 Jun 2017 12:46:23 -0400 +Subject: [PATCH] make GRUB_MOD_INIT() declare its function prototypes. + +--- + include/grub/dl.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index b3753c9ca2..91933b85f2 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -54,6 +54,7 @@ grub_mod_fini (void) + + #define GRUB_MOD_INIT(name) \ + static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ ++extern void grub_##name##_init (void); \ + void \ + grub_##name##_init (void) { grub_mod_init (0); } \ + static void \ +@@ -61,6 +62,7 @@ grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + + #define GRUB_MOD_FINI(name) \ + static void grub_mod_fini (void) __attribute__ ((used)); \ ++extern void grub_##name##_fini (void); \ + void \ + grub_##name##_fini (void) { grub_mod_fini (); } \ + static void \ diff --git a/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch b/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch new file mode 100644 index 0000000..ae8a8c6 --- /dev/null +++ b/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 20 Apr 2017 13:29:06 -0400 +Subject: [PATCH] Don't guess /boot/efi/ as HFS+ on ppc machines in + grub-install + +This should never be trying this, and since we've consolidated the +grubenv to always be on /boot/efi/EFI/fedora/, this code causes it to +always make the wrong decision. + +Resolves: rhbz#1484474 + +Signed-off-by: Peter Jones +--- + util/grub-install.c | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 84ed6e88ec..a2bec7446c 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1190,18 +1190,8 @@ main (int argc, char *argv[]) + char *d; + + is_guess = 1; +- d = grub_util_path_concat (2, bootdir, "macppc"); +- if (!grub_util_is_directory (d)) +- { +- free (d); +- d = grub_util_path_concat (2, bootdir, "efi"); +- } + /* Find the Mac HFS(+) System Partition. */ +- if (!grub_util_is_directory (d)) +- { +- free (d); +- d = grub_util_path_concat (2, bootdir, "EFI"); +- } ++ d = grub_util_path_concat (2, bootdir, "macppc"); + if (!grub_util_is_directory (d)) + { + free (d); diff --git a/0054-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch b/0054-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch deleted file mode 100644 index fb71ea5..0000000 --- a/0054-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 26 Jun 2017 12:46:23 -0400 -Subject: [PATCH] make GRUB_MOD_INIT() declare its function prototypes. - ---- - include/grub/dl.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/include/grub/dl.h b/include/grub/dl.h -index b3753c9ca2..91933b85f2 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -54,6 +54,7 @@ grub_mod_fini (void) - - #define GRUB_MOD_INIT(name) \ - static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ -+extern void grub_##name##_init (void); \ - void \ - grub_##name##_init (void) { grub_mod_init (0); } \ - static void \ -@@ -61,6 +62,7 @@ grub_mod_init (grub_dl_t mod __attribute__ ((unused))) - - #define GRUB_MOD_FINI(name) \ - static void grub_mod_fini (void) __attribute__ ((used)); \ -+extern void grub_##name##_fini (void); \ - void \ - grub_##name##_fini (void) { grub_mod_fini (); } \ - static void \ diff --git a/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch b/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch new file mode 100644 index 0000000..cd58ff4 --- /dev/null +++ b/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 14:31:19 +0200 +Subject: [PATCH] 20_linux_xen: load xen or multiboot{,2} modules as needed. + +Signed-off-by: Peter Jones +--- + util/grub.d/20_linux_xen.in | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index e9e73b815f..c23b064be6 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -153,6 +153,7 @@ linux_entry_xsm () + else + xen_rm_opts="no-real-mode edd=off" + fi ++ insmod ${xen_module} + ${xen_loader} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts} + echo '$(echo "$lmessage" | grub_quote)' + ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} +@@ -166,6 +167,7 @@ EOF + done + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' ++ insmod ${xen_module} + ${module_loader} --nounzip $(echo $initrd_path) + EOF + fi +@@ -253,13 +255,16 @@ while [ "x${xen_list}" != "x" ] ; do + echo " submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {" + fi + if ($grub_file --is-arm64-efi $current_xen); then ++ xen_module="xen_boot" + xen_loader="xen_hypervisor" + module_loader="xen_module" + else + if ($grub_file --is-x86-multiboot2 $current_xen); then ++ xen_module="multiboot2" + xen_loader="multiboot2" + module_loader="module2" + else ++ xen_module="multiboot" + xen_loader="multiboot" + module_loader="module" + fi diff --git a/0055-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch b/0055-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch deleted file mode 100644 index ae8a8c6..0000000 --- a/0055-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 20 Apr 2017 13:29:06 -0400 -Subject: [PATCH] Don't guess /boot/efi/ as HFS+ on ppc machines in - grub-install - -This should never be trying this, and since we've consolidated the -grubenv to always be on /boot/efi/EFI/fedora/, this code causes it to -always make the wrong decision. - -Resolves: rhbz#1484474 - -Signed-off-by: Peter Jones ---- - util/grub-install.c | 12 +----------- - 1 file changed, 1 insertion(+), 11 deletions(-) - -diff --git a/util/grub-install.c b/util/grub-install.c -index 84ed6e88ec..a2bec7446c 100644 ---- a/util/grub-install.c -+++ b/util/grub-install.c -@@ -1190,18 +1190,8 @@ main (int argc, char *argv[]) - char *d; - - is_guess = 1; -- d = grub_util_path_concat (2, bootdir, "macppc"); -- if (!grub_util_is_directory (d)) -- { -- free (d); -- d = grub_util_path_concat (2, bootdir, "efi"); -- } - /* Find the Mac HFS(+) System Partition. */ -- if (!grub_util_is_directory (d)) -- { -- free (d); -- d = grub_util_path_concat (2, bootdir, "EFI"); -- } -+ d = grub_util_path_concat (2, bootdir, "macppc"); - if (!grub_util_is_directory (d)) - { - free (d); diff --git a/0056-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch b/0056-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch deleted file mode 100644 index cd58ff4..0000000 --- a/0056-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 9 Jul 2019 14:31:19 +0200 -Subject: [PATCH] 20_linux_xen: load xen or multiboot{,2} modules as needed. - -Signed-off-by: Peter Jones ---- - util/grub.d/20_linux_xen.in | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in -index e9e73b815f..c23b064be6 100644 ---- a/util/grub.d/20_linux_xen.in -+++ b/util/grub.d/20_linux_xen.in -@@ -153,6 +153,7 @@ linux_entry_xsm () - else - xen_rm_opts="no-real-mode edd=off" - fi -+ insmod ${xen_module} - ${xen_loader} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts} - echo '$(echo "$lmessage" | grub_quote)' - ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} -@@ -166,6 +167,7 @@ EOF - done - sed "s/^/$submenu_indentation/" << EOF - echo '$(echo "$message" | grub_quote)' -+ insmod ${xen_module} - ${module_loader} --nounzip $(echo $initrd_path) - EOF - fi -@@ -253,13 +255,16 @@ while [ "x${xen_list}" != "x" ] ; do - echo " submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {" - fi - if ($grub_file --is-arm64-efi $current_xen); then -+ xen_module="xen_boot" - xen_loader="xen_hypervisor" - module_loader="xen_module" - else - if ($grub_file --is-x86-multiboot2 $current_xen); then -+ xen_module="multiboot2" - xen_loader="multiboot2" - module_loader="module2" - else -+ xen_module="multiboot" - xen_loader="multiboot" - module_loader="module" - fi diff --git a/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch b/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch new file mode 100644 index 0000000..beef0f3 --- /dev/null +++ b/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch @@ -0,0 +1,211 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 7 Nov 2017 17:12:17 -0500 +Subject: [PATCH] Make pmtimer tsc calibration not take 51 seconds to fail. + +On my laptop running at 2.4GHz, if I run a VM where tsc calibration +using pmtimer will fail presuming a broken pmtimer, it takes ~51 seconds +to do so (as measured with the stopwatch on my phone), with a tsc delta +of 0x1cd1c85300, or around 125 billion cycles. + +If instead of trying to wait for 5-200ms to show up on the pmtimer, we try +to wait for 5-200us, it decides it's broken in ~0x2626aa0 TSCs, aka ~2.4 +million cycles, or more or less instantly. + +Additionally, this reading the pmtimer was returning 0xffffffff anyway, +and that's obviously an invalid return. I've added a check for that and +0 so we don't bother waiting for the test if what we're seeing is dead +pins with no response at all. + +If "debug" is includes "pmtimer", you will see one of the following +three outcomes. If pmtimer gives all 0 or all 1 bits, you will see: + +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 1 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 2 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 3 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 4 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 5 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 6 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 7 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 8 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 9 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 10 +kern/i386/tsc_pmtimer.c:78: timer is broken; giving up. + +This outcome was tested using qemu+kvm with UEFI (OVMF) firmware and +these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX + +If pmtimer gives any other bit patterns but is not actually marching +forward fast enough to use for clock calibration, you will see: + +kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations) +kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0 + +This outcome was tested using grub compiled with GRUB_PMTIMER_IGNORE_BAD_READS +defined (so as not to trip the bad read test) using qemu+kvm with UEFI +(OVMF) firmware, and these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX + +If pmtimer actually works, you'll see something like: + +kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations) +kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0 + +This outcome was tested using qemu+kvm with UEFI (OVMF) firmware, and +these options: -machine pc-i440fx-2.4 -cpu Broadwell-noTSX + +I've also tested this outcome on a real Intel Xeon E3-1275v3 on an Intel +Server Board S1200V3RPS using the SDV.RP.B8 "Release" build here: +https://firmware.intel.com/sites/default/files/UEFIDevKit_S1200RP_vB8.zip + +Signed-off-by: Peter Jones +--- + grub-core/kern/i386/tsc_pmtimer.c | 109 +++++++++++++++++++++++++++++++------- + 1 file changed, 89 insertions(+), 20 deletions(-) + +diff --git a/grub-core/kern/i386/tsc_pmtimer.c b/grub-core/kern/i386/tsc_pmtimer.c +index c9c3616997..ca15c3aacd 100644 +--- a/grub-core/kern/i386/tsc_pmtimer.c ++++ b/grub-core/kern/i386/tsc_pmtimer.c +@@ -28,40 +28,101 @@ + #include + #include + ++/* ++ * Define GRUB_PMTIMER_IGNORE_BAD_READS if you're trying to test a timer that's ++ * present but doesn't keep time well. ++ */ ++// #define GRUB_PMTIMER_IGNORE_BAD_READS ++ + grub_uint64_t + grub_pmtimer_wait_count_tsc (grub_port_t pmtimer, + grub_uint16_t num_pm_ticks) + { + grub_uint32_t start; +- grub_uint32_t last; +- grub_uint32_t cur, end; ++ grub_uint64_t cur, end; + grub_uint64_t start_tsc; + grub_uint64_t end_tsc; +- int num_iter = 0; ++ unsigned int num_iter = 0; ++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS ++ int bad_reads = 0; ++#endif + +- start = grub_inl (pmtimer) & 0xffffff; +- last = start; ++ /* ++ * Some timers are 24-bit and some are 32-bit, but it doesn't make much ++ * difference to us. Caring which one we have isn't really worth it since ++ * the low-order digits will give us enough data to calibrate TSC. So just ++ * mask the top-order byte off. ++ */ ++ cur = start = grub_inl (pmtimer) & 0xffffffUL; + end = start + num_pm_ticks; + start_tsc = grub_get_tsc (); + while (1) + { +- cur = grub_inl (pmtimer) & 0xffffff; +- if (cur < last) +- cur |= 0x1000000; +- num_iter++; ++ cur &= 0xffffffffff000000ULL; ++ cur |= grub_inl (pmtimer) & 0xffffffUL; ++ ++ end_tsc = grub_get_tsc(); ++ ++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS ++ /* ++ * If we get 10 reads in a row that are obviously dead pins, there's no ++ * reason to do this thousands of times. ++ */ ++ if (cur == 0xffffffUL || cur == 0) ++ { ++ bad_reads++; ++ grub_dprintf ("pmtimer", ++ "pmtimer: 0x%"PRIxGRUB_UINT64_T" bad_reads: %d\n", ++ cur, bad_reads); ++ grub_dprintf ("pmtimer", "timer is broken; giving up.\n"); ++ ++ if (bad_reads == 10) ++ return 0; ++ } ++#endif ++ ++ if (cur < start) ++ cur += 0x1000000; ++ + if (cur >= end) + { +- end_tsc = grub_get_tsc (); ++ grub_dprintf ("pmtimer", "pmtimer delta is 0x%"PRIxGRUB_UINT64_T"\n", ++ cur - start); ++ grub_dprintf ("pmtimer", "tsc delta is 0x%"PRIxGRUB_UINT64_T"\n", ++ end_tsc - start_tsc); + return end_tsc - start_tsc; + } +- /* Check for broken PM timer. +- 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz) +- if after this time we still don't have 1 ms on pmtimer, then +- pmtimer is broken. ++ ++ /* ++ * Check for broken PM timer. 1ms at 10GHz should be 1E+7 TSCs; at ++ * 250MHz it should be 2.5E6. So if after 4E+7 TSCs on a 10GHz machine, ++ * we should have seen pmtimer show 4ms of change (i.e. cur =~ ++ * start+14320); on a 250MHz machine that should be 16ms (start+57280). ++ * If after this a time we still don't have 1ms on pmtimer, then pmtimer ++ * is broken. ++ * ++ * Likewise, if our code is perfectly efficient and introduces no delays ++ * whatsoever, on a 10GHz system we should see a TSC delta of 3580 in ++ * ~3580 iterations. On a 250MHz machine that should be ~900 iterations. ++ * ++ * With those factors in mind, there are two limits here. There's a hard ++ * limit here at 8x our desired pm timer delta, picked as an arbitrarily ++ * large value that's still not a lot of time to humans, because if we ++ * get that far this is either an implausibly fast machine or the pmtimer ++ * is not running. And there's another limit on 4x our 10GHz tsc delta ++ * without seeing cur converge on our target value. + */ +- if ((num_iter & 0xffffff) == 0 && grub_get_tsc () - start_tsc > 5000000) { +- return 0; +- } ++ if ((++num_iter > (grub_uint32_t)num_pm_ticks << 3UL) || ++ end_tsc - start_tsc > 40000000) ++ { ++ grub_dprintf ("pmtimer", ++ "pmtimer delta is 0x%"PRIxGRUB_UINT64_T" (%u iterations)\n", ++ cur - start, num_iter); ++ grub_dprintf ("pmtimer", ++ "tsc delta is implausible: 0x%"PRIxGRUB_UINT64_T"\n", ++ end_tsc - start_tsc); ++ return 0; ++ } + } + } + +@@ -74,12 +135,20 @@ grub_tsc_calibrate_from_pmtimer (void) + + fadt = grub_acpi_find_fadt (); + if (!fadt) +- return 0; ++ { ++ grub_dprintf ("pmtimer", "No FADT found; not using pmtimer.\n"); ++ return 0; ++ } + pmtimer = fadt->pmtimer; + if (!pmtimer) +- return 0; ++ { ++ grub_dprintf ("pmtimer", "FADT does not specify pmtimer; skipping.\n"); ++ return 0; ++ } + +- /* It's 3.579545 MHz clock. Wait 1 ms. */ ++ /* ++ * It's 3.579545 MHz clock. Wait 1 ms. ++ */ + tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer, 3580); + if (tsc_diff == 0) + return 0; diff --git a/0057-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch b/0057-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch deleted file mode 100644 index beef0f3..0000000 --- a/0057-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch +++ /dev/null @@ -1,211 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 7 Nov 2017 17:12:17 -0500 -Subject: [PATCH] Make pmtimer tsc calibration not take 51 seconds to fail. - -On my laptop running at 2.4GHz, if I run a VM where tsc calibration -using pmtimer will fail presuming a broken pmtimer, it takes ~51 seconds -to do so (as measured with the stopwatch on my phone), with a tsc delta -of 0x1cd1c85300, or around 125 billion cycles. - -If instead of trying to wait for 5-200ms to show up on the pmtimer, we try -to wait for 5-200us, it decides it's broken in ~0x2626aa0 TSCs, aka ~2.4 -million cycles, or more or less instantly. - -Additionally, this reading the pmtimer was returning 0xffffffff anyway, -and that's obviously an invalid return. I've added a check for that and -0 so we don't bother waiting for the test if what we're seeing is dead -pins with no response at all. - -If "debug" is includes "pmtimer", you will see one of the following -three outcomes. If pmtimer gives all 0 or all 1 bits, you will see: - -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 1 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 2 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 3 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 4 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 5 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 6 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 7 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 8 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 9 -kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 10 -kern/i386/tsc_pmtimer.c:78: timer is broken; giving up. - -This outcome was tested using qemu+kvm with UEFI (OVMF) firmware and -these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX - -If pmtimer gives any other bit patterns but is not actually marching -forward fast enough to use for clock calibration, you will see: - -kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations) -kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0 - -This outcome was tested using grub compiled with GRUB_PMTIMER_IGNORE_BAD_READS -defined (so as not to trip the bad read test) using qemu+kvm with UEFI -(OVMF) firmware, and these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX - -If pmtimer actually works, you'll see something like: - -kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations) -kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0 - -This outcome was tested using qemu+kvm with UEFI (OVMF) firmware, and -these options: -machine pc-i440fx-2.4 -cpu Broadwell-noTSX - -I've also tested this outcome on a real Intel Xeon E3-1275v3 on an Intel -Server Board S1200V3RPS using the SDV.RP.B8 "Release" build here: -https://firmware.intel.com/sites/default/files/UEFIDevKit_S1200RP_vB8.zip - -Signed-off-by: Peter Jones ---- - grub-core/kern/i386/tsc_pmtimer.c | 109 +++++++++++++++++++++++++++++++------- - 1 file changed, 89 insertions(+), 20 deletions(-) - -diff --git a/grub-core/kern/i386/tsc_pmtimer.c b/grub-core/kern/i386/tsc_pmtimer.c -index c9c3616997..ca15c3aacd 100644 ---- a/grub-core/kern/i386/tsc_pmtimer.c -+++ b/grub-core/kern/i386/tsc_pmtimer.c -@@ -28,40 +28,101 @@ - #include - #include - -+/* -+ * Define GRUB_PMTIMER_IGNORE_BAD_READS if you're trying to test a timer that's -+ * present but doesn't keep time well. -+ */ -+// #define GRUB_PMTIMER_IGNORE_BAD_READS -+ - grub_uint64_t - grub_pmtimer_wait_count_tsc (grub_port_t pmtimer, - grub_uint16_t num_pm_ticks) - { - grub_uint32_t start; -- grub_uint32_t last; -- grub_uint32_t cur, end; -+ grub_uint64_t cur, end; - grub_uint64_t start_tsc; - grub_uint64_t end_tsc; -- int num_iter = 0; -+ unsigned int num_iter = 0; -+#ifndef GRUB_PMTIMER_IGNORE_BAD_READS -+ int bad_reads = 0; -+#endif - -- start = grub_inl (pmtimer) & 0xffffff; -- last = start; -+ /* -+ * Some timers are 24-bit and some are 32-bit, but it doesn't make much -+ * difference to us. Caring which one we have isn't really worth it since -+ * the low-order digits will give us enough data to calibrate TSC. So just -+ * mask the top-order byte off. -+ */ -+ cur = start = grub_inl (pmtimer) & 0xffffffUL; - end = start + num_pm_ticks; - start_tsc = grub_get_tsc (); - while (1) - { -- cur = grub_inl (pmtimer) & 0xffffff; -- if (cur < last) -- cur |= 0x1000000; -- num_iter++; -+ cur &= 0xffffffffff000000ULL; -+ cur |= grub_inl (pmtimer) & 0xffffffUL; -+ -+ end_tsc = grub_get_tsc(); -+ -+#ifndef GRUB_PMTIMER_IGNORE_BAD_READS -+ /* -+ * If we get 10 reads in a row that are obviously dead pins, there's no -+ * reason to do this thousands of times. -+ */ -+ if (cur == 0xffffffUL || cur == 0) -+ { -+ bad_reads++; -+ grub_dprintf ("pmtimer", -+ "pmtimer: 0x%"PRIxGRUB_UINT64_T" bad_reads: %d\n", -+ cur, bad_reads); -+ grub_dprintf ("pmtimer", "timer is broken; giving up.\n"); -+ -+ if (bad_reads == 10) -+ return 0; -+ } -+#endif -+ -+ if (cur < start) -+ cur += 0x1000000; -+ - if (cur >= end) - { -- end_tsc = grub_get_tsc (); -+ grub_dprintf ("pmtimer", "pmtimer delta is 0x%"PRIxGRUB_UINT64_T"\n", -+ cur - start); -+ grub_dprintf ("pmtimer", "tsc delta is 0x%"PRIxGRUB_UINT64_T"\n", -+ end_tsc - start_tsc); - return end_tsc - start_tsc; - } -- /* Check for broken PM timer. -- 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz) -- if after this time we still don't have 1 ms on pmtimer, then -- pmtimer is broken. -+ -+ /* -+ * Check for broken PM timer. 1ms at 10GHz should be 1E+7 TSCs; at -+ * 250MHz it should be 2.5E6. So if after 4E+7 TSCs on a 10GHz machine, -+ * we should have seen pmtimer show 4ms of change (i.e. cur =~ -+ * start+14320); on a 250MHz machine that should be 16ms (start+57280). -+ * If after this a time we still don't have 1ms on pmtimer, then pmtimer -+ * is broken. -+ * -+ * Likewise, if our code is perfectly efficient and introduces no delays -+ * whatsoever, on a 10GHz system we should see a TSC delta of 3580 in -+ * ~3580 iterations. On a 250MHz machine that should be ~900 iterations. -+ * -+ * With those factors in mind, there are two limits here. There's a hard -+ * limit here at 8x our desired pm timer delta, picked as an arbitrarily -+ * large value that's still not a lot of time to humans, because if we -+ * get that far this is either an implausibly fast machine or the pmtimer -+ * is not running. And there's another limit on 4x our 10GHz tsc delta -+ * without seeing cur converge on our target value. - */ -- if ((num_iter & 0xffffff) == 0 && grub_get_tsc () - start_tsc > 5000000) { -- return 0; -- } -+ if ((++num_iter > (grub_uint32_t)num_pm_ticks << 3UL) || -+ end_tsc - start_tsc > 40000000) -+ { -+ grub_dprintf ("pmtimer", -+ "pmtimer delta is 0x%"PRIxGRUB_UINT64_T" (%u iterations)\n", -+ cur - start, num_iter); -+ grub_dprintf ("pmtimer", -+ "tsc delta is implausible: 0x%"PRIxGRUB_UINT64_T"\n", -+ end_tsc - start_tsc); -+ return 0; -+ } - } - } - -@@ -74,12 +135,20 @@ grub_tsc_calibrate_from_pmtimer (void) - - fadt = grub_acpi_find_fadt (); - if (!fadt) -- return 0; -+ { -+ grub_dprintf ("pmtimer", "No FADT found; not using pmtimer.\n"); -+ return 0; -+ } - pmtimer = fadt->pmtimer; - if (!pmtimer) -- return 0; -+ { -+ grub_dprintf ("pmtimer", "FADT does not specify pmtimer; skipping.\n"); -+ return 0; -+ } - -- /* It's 3.579545 MHz clock. Wait 1 ms. */ -+ /* -+ * It's 3.579545 MHz clock. Wait 1 ms. -+ */ - tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer, 3580); - if (tsc_diff == 0) - return 0; diff --git a/0057-align-struct-efi_variable-better.patch b/0057-align-struct-efi_variable-better.patch new file mode 100644 index 0000000..361cb13 --- /dev/null +++ b/0057-align-struct-efi_variable-better.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 27 Feb 2018 13:55:35 -0500 +Subject: [PATCH] align struct efi_variable better... + +--- + include/grub/efiemu/runtime.h | 2 +- + include/grub/types.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h +index 36d2dedf47..9d93ba88ba 100644 +--- a/include/grub/efiemu/runtime.h ++++ b/include/grub/efiemu/runtime.h +@@ -33,5 +33,5 @@ struct efi_variable + grub_uint32_t namelen; + grub_uint32_t size; + grub_efi_uint32_t attributes; +-} GRUB_PACKED; ++} GRUB_PACKED GRUB_ALIGNED(8); + #endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */ +diff --git a/include/grub/types.h b/include/grub/types.h +index 0a3ff15913..ba446d9904 100644 +--- a/include/grub/types.h ++++ b/include/grub/types.h +@@ -29,6 +29,7 @@ + #else + #define GRUB_PACKED __attribute__ ((packed)) + #endif ++#define GRUB_ALIGNED(x) __attribute__((aligned (x))) + + #ifdef GRUB_BUILD + # define GRUB_CPU_SIZEOF_VOID_P BUILD_SIZEOF_VOID_P diff --git a/0058-Add-BLS-support-to-grub-mkconfig.patch b/0058-Add-BLS-support-to-grub-mkconfig.patch new file mode 100644 index 0000000..3e5b230 --- /dev/null +++ b/0058-Add-BLS-support-to-grub-mkconfig.patch @@ -0,0 +1,382 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 9 Dec 2016 15:40:29 -0500 +Subject: [PATCH] Add BLS support to grub-mkconfig + +GRUB now has BootLoaderSpec support, the user can choose to use this by +setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup, +the boot menu entries are not added to the grub.cfg, instead BLS config +files are parsed by blscfg command and the entries created dynamically. + +A 10_linux_bls grub.d snippet to generate menu entries from BLS files +is also added that can be used on platforms where the bootloader doesn't +have BLS support and only can parse a normal grub configuration file. + +Portions of the 10_linux_bls were taken from the ostree-grub-generator +script that's included in the OSTree project. + +Fixes to support multi-devices and generate a BLS section even if no +kernels are found in the boot directory were proposed by Yclept Nemo +and Tom Gundersen respectively. + +Signed-off-by: Peter Jones +[javierm: remove outdated URL for BLS document] +Signed-off-by: Javier Martinez Canillas +[iwienand@redhat.com: skip machine ID check when updating entries] +Signed-off-by: Ian Wienand +[rharwood: use sort(1), commit message composits, drop man pages] +Signed-off-by: Robbie Harwood +--- + util/grub-mkconfig.in | 9 +- + util/grub-mkconfig_lib.in | 22 ++++- + util/grub.d/10_linux.in | 218 +++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 243 insertions(+), 6 deletions(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 535c0f0249..f55339a3f6 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -50,6 +50,8 @@ grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + ++export GRUB_GRUBENV_UPDATE="yes" ++ + . "${pkgdatadir}/grub-mkconfig_lib" + + # Usage: usage +@@ -59,6 +61,7 @@ usage () { + gettext "Generate a grub config file"; echo + echo + print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")" ++ print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")" + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + echo +@@ -94,6 +97,9 @@ do + --output=*) + grub_cfg=`echo "$option" | sed 's/--output=//'` + ;; ++ --no-grubenv-update) ++ GRUB_GRUBENV_UPDATE="no" ++ ;; + -*) + gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 + usage +@@ -253,7 +259,8 @@ export GRUB_DEFAULT \ + GRUB_OS_PROBER_SKIP_LIST \ + GRUB_DISABLE_SUBMENU \ + GRUB_DEFAULT_DTB \ +- SUSE_BTRFS_SNAPSHOT_BOOTING ++ SUSE_BTRFS_SNAPSHOT_BOOTING \ ++ GRUB_ENABLE_BLSCFG + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 5e96f6cc5d..301d8a8a1e 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -30,6 +30,9 @@ fi + if test "x$grub_file" = x; then + grub_file="${bindir}/@grub_file@" + fi ++if test "x$grub_editenv" = x; then ++ grub_editenv="${bindir}/@grub_editenv@" ++fi + if test "x$grub_mkrelpath" = x; then + grub_mkrelpath="${bindir}/@grub_mkrelpath@" + fi +@@ -122,8 +125,19 @@ EOF + fi + } + ++prepare_grub_to_access_device_with_variable () ++{ ++ device_variable="$1" ++ shift ++ prepare_grub_to_access_device "$@" ++ unset "device_variable" ++} ++ + prepare_grub_to_access_device () + { ++ if [ -z "$device_variable" ]; then ++ device_variable="root" ++ fi + old_ifs="$IFS" + IFS=' + ' +@@ -158,18 +172,18 @@ prepare_grub_to_access_device () + # otherwise set root as per value in device.map. + fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`" + if [ "x$fs_hint" != x ]; then +- echo "set root='$fs_hint'" ++ echo "set ${device_variable}='$fs_hint'" + fi + if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then + hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints= + if [ "x$hints" != x ]; then + echo "if [ x\$feature_platform_search_hint = xy ]; then" +- echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" ++ echo " search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}" + echo "else" +- echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" ++ echo " search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" + echo "fi" + else +- echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" ++ echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" + fi + fi + IFS="$old_ifs" +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 7bb3a211a7..2851952659 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -82,6 +82,218 @@ case x"$GRUB_FS" in + ;; + esac + ++populate_header_warn() ++{ ++if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then ++ bls_parser="10_linux script" ++else ++ bls_parser="blscfg command" ++fi ++cat </dev/null)) || : ++ ++ echo "${files[@]}" ++} ++ ++update_bls_cmdline() ++{ ++ local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ local -a files=($(get_sorted_bls)) ++ ++ for bls in "${files[@]}"; do ++ local options="${cmdline}" ++ if [ -z "${bls##*debug*}" ]; then ++ options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi ++ options="$(echo "${options}" | sed -e 's/\//\\\//g')" ++ sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf" ++ done ++} ++ ++populate_menu() ++{ ++ local -a files=($(get_sorted_bls)) ++ ++ gettext_printf "Generating boot entries from BLS files...\n" >&2 ++ ++ for bls in "${files[@]}"; do ++ read_config "${blsdir}/${bls}.conf" ++ ++ menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n" ++ menu="${menu}\t linux ${linux} ${options}\n" ++ if [ -n "${initrd}" ] ; then ++ menu="${menu}\t initrd ${boot_prefix}${initrd}\n" ++ fi ++ menu="${menu}}\n\n" ++ done ++ # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation ++ printf "$menu" ++} ++ ++# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed. ++if [ -z "${GRUB_ENABLE_BLSCFG}" ] && ! command -v new-kernel-pkg >/dev/null; then ++ GRUB_ENABLE_BLSCFG="true" ++fi ++ ++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then ++ if [ x$dirname = x/ ]; then ++ if [ -z "${prepare_root_cache}" ]; then ++ prepare_grub_to_access_device ${GRUB_DEVICE} ++ fi ++ else ++ if [ -z "${prepare_boot_cache}" ]; then ++ prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} ++ fi ++ fi ++ ++ if [ -d /sys/firmware/efi ]; then ++ bootefi_device="`${grub_probe} --target=device /boot/efi/`" ++ prepare_grub_to_access_device_with_variable boot ${bootefi_device} ++ else ++ boot_device="`${grub_probe} --target=device /boot/`" ++ prepare_grub_to_access_device_with_variable boot ${boot_device} ++ fi ++ ++ arch="$(uname -m)" ++ if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then ++ ++ BLS_POPULATE_MENU="true" ++ petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot" ++ ++ if test -e ${petitboot_path}; then ++ read -r -d '' petitboot_version < ${petitboot_path} ++ petitboot_version="$(echo ${petitboot_version//v})" ++ ++ if test -n ${petitboot_version}; then ++ major_version="$(echo ${petitboot_version} | cut -d . -f1)" ++ minor_version="$(echo ${petitboot_version} | cut -d . -f2)" ++ ++ re='^[0-9]+$' ++ if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] && ++ ([[ ${major_version} -gt 1 ]] || ++ [[ ${major_version} -eq 1 && ++ ${minor_version} -ge 8 ]]); then ++ BLS_POPULATE_MENU="false" ++ fi ++ fi ++ fi ++ fi ++ ++ populate_header_warn ++ ++ cat << EOF ++# The kernelopts variable should be defined in the grubenv file. But to ensure that menu ++# entries populated from BootLoaderSpec files that use this variable work correctly even ++# without a grubenv file, define a fallback kernelopts variable if this has not been set. ++# ++# The kernelopts variable in the grubenv file can be modified using the grubby tool or by ++# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX ++# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both ++# the kernelopts variable in the grubenv file and the fallback kernelopts variable. ++if [ -z "\${kernelopts}" ]; then ++ set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++fi ++EOF ++ ++ update_bls_cmdline ++ ++ if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then ++ populate_menu ++ else ++ cat << EOF ++ ++insmod blscfg ++blscfg ++EOF ++ fi ++ ++ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ++ blsdir="/boot/loader/entries" ++ [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})" ++ if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then ++ blsdir=$(make_system_path_relative_to_its_root "${blsdir}") ++ if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then ++ ${grub_editenv} - set blsdir="${blsdir}" ++ fi ++ fi ++ ++ if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then ++ ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ++ fi ++ ++ if [ -n "${GRUB_DEFAULT_DTB}" ]; then ++ ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}" ++ fi ++ ++ if [ -n "${GRUB_SAVEDEFAULT}" ]; then ++ ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}" ++ fi ++ fi ++ ++ exit 0 ++fi ++ + mktitle () + { + local title_type +@@ -121,6 +333,7 @@ linux_entry () + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi ++ + if [ x$type != xsimple ] ; then + title=$(mktitle "$type" "$version") + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then +@@ -231,6 +444,7 @@ is_top_level=true + while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` + gettext_printf "Found linux image: %s\n" "$linux" >&2 ++ + basename=`basename $linux` + dirname=`dirname $linux` + rel_dirname=`make_system_path_relative_to_its_root $dirname` +@@ -269,7 +483,9 @@ while [ "x$list" != "x" ] ; do + for i in ${initrd}; do + initrd_display="${initrd_display} ${dirname}/${i}" + done +- gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 ++ if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then ++ gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 ++ fi + fi + + fdt= diff --git a/0058-align-struct-efi_variable-better.patch b/0058-align-struct-efi_variable-better.patch deleted file mode 100644 index 361cb13..0000000 --- a/0058-align-struct-efi_variable-better.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 27 Feb 2018 13:55:35 -0500 -Subject: [PATCH] align struct efi_variable better... - ---- - include/grub/efiemu/runtime.h | 2 +- - include/grub/types.h | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h -index 36d2dedf47..9d93ba88ba 100644 ---- a/include/grub/efiemu/runtime.h -+++ b/include/grub/efiemu/runtime.h -@@ -33,5 +33,5 @@ struct efi_variable - grub_uint32_t namelen; - grub_uint32_t size; - grub_efi_uint32_t attributes; --} GRUB_PACKED; -+} GRUB_PACKED GRUB_ALIGNED(8); - #endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */ -diff --git a/include/grub/types.h b/include/grub/types.h -index 0a3ff15913..ba446d9904 100644 ---- a/include/grub/types.h -+++ b/include/grub/types.h -@@ -29,6 +29,7 @@ - #else - #define GRUB_PACKED __attribute__ ((packed)) - #endif -+#define GRUB_ALIGNED(x) __attribute__((aligned (x))) - - #ifdef GRUB_BUILD - # define GRUB_CPU_SIZEOF_VOID_P BUILD_SIZEOF_VOID_P diff --git a/0059-Add-BLS-support-to-grub-mkconfig.patch b/0059-Add-BLS-support-to-grub-mkconfig.patch deleted file mode 100644 index 4c3f56f..0000000 --- a/0059-Add-BLS-support-to-grub-mkconfig.patch +++ /dev/null @@ -1,382 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 9 Dec 2016 15:40:29 -0500 -Subject: [PATCH] Add BLS support to grub-mkconfig - -GRUB now has BootLoaderSpec support, the user can choose to use this by -setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup, -the boot menu entries are not added to the grub.cfg, instead BLS config -files are parsed by blscfg command and the entries created dynamically. - -A 10_linux_bls grub.d snippet to generate menu entries from BLS files -is also added that can be used on platforms where the bootloader doesn't -have BLS support and only can parse a normal grub configuration file. - -Portions of the 10_linux_bls were taken from the ostree-grub-generator -script that's included in the OSTree project. - -Fixes to support multi-devices and generate a BLS section even if no -kernels are found in the boot directory were proposed by Yclept Nemo -and Tom Gundersen respectively. - -Signed-off-by: Peter Jones -[javierm: remove outdated URL for BLS document] -Signed-off-by: Javier Martinez Canillas -[iwienand@redhat.com: skip machine ID check when updating entries] -Signed-off-by: Ian Wienand -[rharwood: commit message composits, drop man pages] -Signed-off-by: Robbie Harwood ---- - util/grub-mkconfig.in | 9 +- - util/grub-mkconfig_lib.in | 22 ++++- - util/grub.d/10_linux.in | 218 +++++++++++++++++++++++++++++++++++++++++++++- - 3 files changed, 243 insertions(+), 6 deletions(-) - -diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in -index 535c0f0249..f55339a3f6 100644 ---- a/util/grub-mkconfig.in -+++ b/util/grub-mkconfig.in -@@ -50,6 +50,8 @@ grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" - export TEXTDOMAIN=@PACKAGE@ - export TEXTDOMAINDIR="@localedir@" - -+export GRUB_GRUBENV_UPDATE="yes" -+ - . "${pkgdatadir}/grub-mkconfig_lib" - - # Usage: usage -@@ -59,6 +61,7 @@ usage () { - gettext "Generate a grub config file"; echo - echo - print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")" -+ print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")" - print_option_help "-h, --help" "$(gettext "print this message and exit")" - print_option_help "-V, --version" "$(gettext "print the version information and exit")" - echo -@@ -94,6 +97,9 @@ do - --output=*) - grub_cfg=`echo "$option" | sed 's/--output=//'` - ;; -+ --no-grubenv-update) -+ GRUB_GRUBENV_UPDATE="no" -+ ;; - -*) - gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 - usage -@@ -253,7 +259,8 @@ export GRUB_DEFAULT \ - GRUB_OS_PROBER_SKIP_LIST \ - GRUB_DISABLE_SUBMENU \ - GRUB_DEFAULT_DTB \ -- SUSE_BTRFS_SNAPSHOT_BOOTING -+ SUSE_BTRFS_SNAPSHOT_BOOTING \ -+ GRUB_ENABLE_BLSCFG - - if test "x${grub_cfg}" != "x"; then - rm -f "${grub_cfg}.new" -diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in -index fafeac9506..d8bb406936 100644 ---- a/util/grub-mkconfig_lib.in -+++ b/util/grub-mkconfig_lib.in -@@ -30,6 +30,9 @@ fi - if test "x$grub_file" = x; then - grub_file="${bindir}/@grub_file@" - fi -+if test "x$grub_editenv" = x; then -+ grub_editenv="${bindir}/@grub_editenv@" -+fi - if test "x$grub_mkrelpath" = x; then - grub_mkrelpath="${bindir}/@grub_mkrelpath@" - fi -@@ -125,8 +128,19 @@ EOF - fi - } - -+prepare_grub_to_access_device_with_variable () -+{ -+ device_variable="$1" -+ shift -+ prepare_grub_to_access_device "$@" -+ unset "device_variable" -+} -+ - prepare_grub_to_access_device () - { -+ if [ -z "$device_variable" ]; then -+ device_variable="root" -+ fi - old_ifs="$IFS" - IFS=' - ' -@@ -161,18 +175,18 @@ prepare_grub_to_access_device () - # otherwise set root as per value in device.map. - fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`" - if [ "x$fs_hint" != x ]; then -- echo "set root='$fs_hint'" -+ echo "set ${device_variable}='$fs_hint'" - fi - if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then - hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints= - if [ "x$hints" != x ]; then - echo "if [ x\$feature_platform_search_hint = xy ]; then" -- echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" -+ echo " search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}" - echo "else" -- echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" -+ echo " search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" - echo "fi" - else -- echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" -+ echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" - fi - fi - IFS="$old_ifs" -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index 7bb3a211a7..f1548a2605 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -82,6 +82,218 @@ case x"$GRUB_FS" in - ;; - esac - -+populate_header_warn() -+{ -+if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then -+ bls_parser="10_linux script" -+else -+ bls_parser="blscfg command" -+fi -+cat </dev/null | tac)) || : -+ -+ echo "${files[@]}" -+} -+ -+update_bls_cmdline() -+{ -+ local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" -+ local -a files=($(get_sorted_bls)) -+ -+ for bls in "${files[@]}"; do -+ local options="${cmdline}" -+ if [ -z "${bls##*debug*}" ]; then -+ options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}" -+ fi -+ options="$(echo "${options}" | sed -e 's/\//\\\//g')" -+ sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf" -+ done -+} -+ -+populate_menu() -+{ -+ local -a files=($(get_sorted_bls)) -+ -+ gettext_printf "Generating boot entries from BLS files...\n" >&2 -+ -+ for bls in "${files[@]}"; do -+ read_config "${blsdir}/${bls}.conf" -+ -+ menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n" -+ menu="${menu}\t linux ${linux} ${options}\n" -+ if [ -n "${initrd}" ] ; then -+ menu="${menu}\t initrd ${boot_prefix}${initrd}\n" -+ fi -+ menu="${menu}}\n\n" -+ done -+ # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation -+ printf "$menu" -+} -+ -+# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed. -+if [ -z "${GRUB_ENABLE_BLSCFG}" ] && ! command -v new-kernel-pkg >/dev/null; then -+ GRUB_ENABLE_BLSCFG="true" -+fi -+ -+if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then -+ if [ x$dirname = x/ ]; then -+ if [ -z "${prepare_root_cache}" ]; then -+ prepare_grub_to_access_device ${GRUB_DEVICE} -+ fi -+ else -+ if [ -z "${prepare_boot_cache}" ]; then -+ prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} -+ fi -+ fi -+ -+ if [ -d /sys/firmware/efi ]; then -+ bootefi_device="`${grub_probe} --target=device /boot/efi/`" -+ prepare_grub_to_access_device_with_variable boot ${bootefi_device} -+ else -+ boot_device="`${grub_probe} --target=device /boot/`" -+ prepare_grub_to_access_device_with_variable boot ${boot_device} -+ fi -+ -+ arch="$(uname -m)" -+ if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then -+ -+ BLS_POPULATE_MENU="true" -+ petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot" -+ -+ if test -e ${petitboot_path}; then -+ read -r -d '' petitboot_version < ${petitboot_path} -+ petitboot_version="$(echo ${petitboot_version//v})" -+ -+ if test -n ${petitboot_version}; then -+ major_version="$(echo ${petitboot_version} | cut -d . -f1)" -+ minor_version="$(echo ${petitboot_version} | cut -d . -f2)" -+ -+ re='^[0-9]+$' -+ if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] && -+ ([[ ${major_version} -gt 1 ]] || -+ [[ ${major_version} -eq 1 && -+ ${minor_version} -ge 8 ]]); then -+ BLS_POPULATE_MENU="false" -+ fi -+ fi -+ fi -+ fi -+ -+ populate_header_warn -+ -+ cat << EOF -+# The kernelopts variable should be defined in the grubenv file. But to ensure that menu -+# entries populated from BootLoaderSpec files that use this variable work correctly even -+# without a grubenv file, define a fallback kernelopts variable if this has not been set. -+# -+# The kernelopts variable in the grubenv file can be modified using the grubby tool or by -+# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX -+# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both -+# the kernelopts variable in the grubenv file and the fallback kernelopts variable. -+if [ -z "\${kernelopts}" ]; then -+ set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" -+fi -+EOF -+ -+ update_bls_cmdline -+ -+ if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then -+ populate_menu -+ else -+ cat << EOF -+ -+insmod blscfg -+blscfg -+EOF -+ fi -+ -+ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then -+ blsdir="/boot/loader/entries" -+ [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})" -+ if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then -+ blsdir=$(make_system_path_relative_to_its_root "${blsdir}") -+ if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then -+ ${grub_editenv} - set blsdir="${blsdir}" -+ fi -+ fi -+ -+ if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then -+ ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}" -+ fi -+ -+ if [ -n "${GRUB_DEFAULT_DTB}" ]; then -+ ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}" -+ fi -+ -+ if [ -n "${GRUB_SAVEDEFAULT}" ]; then -+ ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}" -+ fi -+ fi -+ -+ exit 0 -+fi -+ - mktitle () - { - local title_type -@@ -121,6 +333,7 @@ linux_entry () - if [ -z "$boot_device_id" ]; then - boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" - fi -+ - if [ x$type != xsimple ] ; then - title=$(mktitle "$type" "$version") - if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then -@@ -231,6 +444,7 @@ is_top_level=true - while [ "x$list" != "x" ] ; do - linux=`version_find_latest $list` - gettext_printf "Found linux image: %s\n" "$linux" >&2 -+ - basename=`basename $linux` - dirname=`dirname $linux` - rel_dirname=`make_system_path_relative_to_its_root $dirname` -@@ -269,7 +483,9 @@ while [ "x$list" != "x" ] ; do - for i in ${initrd}; do - initrd_display="${initrd_display} ${dirname}/${i}" - done -- gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 -+ if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then -+ gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 -+ fi - fi - - fdt= diff --git a/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch b/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch new file mode 100644 index 0000000..1ac900c --- /dev/null +++ b/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 6 Feb 2018 11:16:28 +0100 +Subject: [PATCH] Don't attempt to backtrace on grub_abort() for grub-emu + +The emu platform doesn't have a grub_backtrace() implementation, so this +causes a build error. Don't attempt to call this when building grub-emu. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/kern/misc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index a3e215155b..c60601b699 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1201,7 +1201,7 @@ static void __attribute__ ((noreturn)) + grub_abort (void) + { + #ifndef GRUB_UTIL +-#if defined(__i386__) || defined(__x86_64__) ++#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU) + grub_backtrace(); + #endif + #endif diff --git a/0060-Add-linux-and-initrd-commands-for-grub-emu.patch b/0060-Add-linux-and-initrd-commands-for-grub-emu.patch new file mode 100644 index 0000000..419fde3 --- /dev/null +++ b/0060-Add-linux-and-initrd-commands-for-grub-emu.patch @@ -0,0 +1,350 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Raymund Will +Date: Tue, 6 Feb 2018 09:09:00 +0100 +Subject: [PATCH] Add linux and initrd commands for grub-emu + +When using grub-emu, the linux and initrd commands are used as arguments +to the kexec command line tool, to allow booting the selected menu entry. + +Signed-off-by: Raymund Will +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 1 - + grub-core/kern/emu/main.c | 4 + + grub-core/kern/emu/misc.c | 18 ++++- + grub-core/loader/emu/linux.c | 172 +++++++++++++++++++++++++++++++++++++++++++ + include/grub/emu/exec.h | 4 +- + include/grub/emu/hostfile.h | 3 +- + include/grub/emu/misc.h | 3 + + grub-core/Makefile.am | 1 + + 8 files changed, 202 insertions(+), 4 deletions(-) + create mode 100644 grub-core/loader/emu/linux.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 058c88ac3a..5354f9613d 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1826,7 +1826,6 @@ module = { + + common = loader/linux.c; + common = lib/cmdline.c; +- enable = noemu; + + efi = loader/efi/linux.c; + }; +diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c +index 55ea5a11cc..846fe9715e 100644 +--- a/grub-core/kern/emu/main.c ++++ b/grub-core/kern/emu/main.c +@@ -107,6 +107,7 @@ static struct argp_option options[] = { + N_("use GRUB files in the directory DIR [default=%s]"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0}, ++ {"kexec", 'X', 0, 0, N_("try the untryable."), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -164,6 +165,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + case 'v': + verbosity++; + break; ++ case 'X': ++ grub_util_set_kexecute(); ++ break; + + case ARGP_KEY_ARG: + { +diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c +index 0ff13bcaf8..eeea092752 100644 +--- a/grub-core/kern/emu/misc.c ++++ b/grub-core/kern/emu/misc.c +@@ -39,6 +39,7 @@ + #include + + int verbosity; ++int kexecute; + + void + grub_util_warn (const char *fmt, ...) +@@ -82,7 +83,7 @@ grub_util_error (const char *fmt, ...) + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, ".\n"); +- exit (1); ++ grub_exit (1); + } + + void * +@@ -154,6 +155,9 @@ void + __attribute__ ((noreturn)) + grub_exit (int rc) + { ++#if defined (GRUB_KERNEL) ++ grub_reboot(); ++#endif + exit (rc < 0 ? 1 : rc); + } + #endif +@@ -215,3 +219,15 @@ grub_util_load_image (const char *path, char *buf) + + fclose (fp); + } ++ ++void ++grub_util_set_kexecute(void) ++{ ++ kexecute++; ++} ++ ++int ++grub_util_get_kexecute(void) ++{ ++ return kexecute; ++} +diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c +new file mode 100644 +index 0000000000..fda9e00d24 +--- /dev/null ++++ b/grub-core/loader/emu/linux.c +@@ -0,0 +1,172 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++ ++static char *kernel_path; ++static char *initrd_path; ++static char *boot_cmdline; ++ ++static grub_err_t ++grub_linux_boot (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ char *initrd_param; ++ const char *kexec[] = { "kexec", "-l", kernel_path, boot_cmdline, NULL, NULL }; ++ const char *systemctl[] = { "systemctl", "kexec", NULL }; ++ int kexecute = grub_util_get_kexecute(); ++ ++ if (initrd_path) { ++ initrd_param = grub_xasprintf("--initrd=%s", initrd_path); ++ kexec[3] = initrd_param; ++ kexec[4] = boot_cmdline; ++ } else { ++ initrd_param = grub_xasprintf("%s", ""); ++ } ++ ++ grub_printf("%serforming 'kexec -l %s %s %s'\n", ++ (kexecute) ? "P" : "Not p", ++ kernel_path, initrd_param, boot_cmdline); ++ ++ if (kexecute) ++ rc = grub_util_exec(kexec); ++ ++ grub_free(initrd_param); ++ ++ if (rc != GRUB_ERR_NONE) { ++ grub_error (rc, N_("Error trying to perform kexec load operation.")); ++ grub_sleep (3); ++ return rc; ++ } ++ if (kexecute < 1) ++ grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart.")); ++ ++ grub_printf("Performing 'systemctl kexec' (%s) ", ++ (kexecute==1) ? "do-or-die" : "just-in-case"); ++ rc = grub_util_exec (systemctl); ++ ++ if (kexecute == 1) ++ grub_fatal (N_("Error trying to perform 'systemctl kexec'")); ++ ++ /* need to check read-only root before resetting hard!? */ ++ grub_printf("Performing 'kexec -e'"); ++ kexec[1] = "-e"; ++ kexec[2] = NULL; ++ rc = grub_util_exec(kexec); ++ if ( rc != GRUB_ERR_NONE ) ++ grub_fatal (N_("Error trying to directly perform 'kexec -e'.")); ++ ++ return rc; ++} ++ ++static grub_err_t ++grub_linux_unload (void) ++{ ++ grub_dl_unref (my_mod); ++ if ( boot_cmdline != NULL ) ++ grub_free (boot_cmdline); ++ boot_cmdline = NULL; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) ++{ ++ int i; ++ char *tempstr; ++ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if ( !grub_util_is_regular(argv[0]) ) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find kernel file %s"), argv[0]); ++ ++ if ( kernel_path != NULL ) ++ grub_free(kernel_path); ++ ++ kernel_path = grub_xasprintf("%s", argv[0]); ++ ++ if ( boot_cmdline != NULL ) { ++ grub_free(boot_cmdline); ++ boot_cmdline = NULL; ++ } ++ ++ if ( argc > 1 ) ++ { ++ boot_cmdline = grub_xasprintf("--command-line=%s", argv[1]); ++ for ( i = 2; i < argc; i++ ) { ++ tempstr = grub_xasprintf("%s %s", boot_cmdline, argv[i]); ++ grub_free(boot_cmdline); ++ boot_cmdline = tempstr; ++ } ++ } ++ ++ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) ++{ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if ( !grub_util_is_regular(argv[0]) ) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find initrd file %s"), argv[0]); ++ ++ if ( initrd_path != NULL ) ++ grub_free(initrd_path); ++ ++ initrd_path = grub_xasprintf("%s", argv[0]); ++ ++ grub_dl_unref (my_mod); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT(linux) ++{ ++ cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, N_("Load Linux.")); ++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, N_("Load initrd.")); ++ my_mod = mod; ++ kernel_path = NULL; ++ initrd_path = NULL; ++ boot_cmdline = NULL; ++} ++ ++GRUB_MOD_FINI(linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h +index d1073ef86a..1b61b4a2e5 100644 +--- a/include/grub/emu/exec.h ++++ b/include/grub/emu/exec.h +@@ -23,6 +23,8 @@ + #include + + #include ++#include ++ + pid_t + grub_util_exec_pipe (const char *const *argv, int *fd); + pid_t +@@ -32,7 +34,7 @@ int + grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file, + const char *stdout_file, const char *stderr_file); + int +-grub_util_exec (const char *const *argv); ++EXPORT_FUNC(grub_util_exec) (const char *const *argv); + int + grub_util_exec_redirect (const char *const *argv, const char *stdin_file, + const char *stdout_file); +diff --git a/include/grub/emu/hostfile.h b/include/grub/emu/hostfile.h +index cfb1e2b566..a61568e36e 100644 +--- a/include/grub/emu/hostfile.h ++++ b/include/grub/emu/hostfile.h +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + + int +@@ -29,7 +30,7 @@ grub_util_is_directory (const char *path); + int + grub_util_is_special_file (const char *path); + int +-grub_util_is_regular (const char *path); ++EXPORT_FUNC(grub_util_is_regular) (const char *path); + + char * + grub_util_path_concat (size_t n, ...); +diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h +index ff9c48a649..01056954b9 100644 +--- a/include/grub/emu/misc.h ++++ b/include/grub/emu/misc.h +@@ -57,6 +57,9 @@ void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...) __attribute__ ((format ( + void EXPORT_FUNC(grub_util_info) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); + void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2), noreturn)); + ++void EXPORT_FUNC(grub_util_set_kexecute) (void); ++int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT; ++ + grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void); + + #ifdef HAVE_DEVICE_MAPPER +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index ee88e44e97..80e7a83edf 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -307,6 +307,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/net.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/exec.h + if COND_GRUB_EMU_SDL + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h + endif diff --git a/0060-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch b/0060-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch deleted file mode 100644 index 1ac900c..0000000 --- a/0060-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 6 Feb 2018 11:16:28 +0100 -Subject: [PATCH] Don't attempt to backtrace on grub_abort() for grub-emu - -The emu platform doesn't have a grub_backtrace() implementation, so this -causes a build error. Don't attempt to call this when building grub-emu. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/kern/misc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index a3e215155b..c60601b699 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -1201,7 +1201,7 @@ static void __attribute__ ((noreturn)) - grub_abort (void) - { - #ifndef GRUB_UTIL --#if defined(__i386__) || defined(__x86_64__) -+#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU) - grub_backtrace(); - #endif - #endif diff --git a/0061-Add-grub2-switch-to-blscfg.patch b/0061-Add-grub2-switch-to-blscfg.patch new file mode 100644 index 0000000..e316116 --- /dev/null +++ b/0061-Add-grub2-switch-to-blscfg.patch @@ -0,0 +1,395 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 15 Mar 2018 14:12:40 -0400 +Subject: [PATCH] Add grub2-switch-to-blscfg + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +[jhlavac: Use ${etcdefaultgrub} instead of /etc/default/grub] +Signed-off-by: Jan Hlavac +[rharwood: skip on ostree installations, migrate man to h2m] +Signed-off-by: Robbie Harwood +--- + Makefile.util.def | 7 + + docs/man/grub-switch-to-blscfg.h2m | 2 + + util/grub-set-password.in | 2 +- + util/grub-switch-to-blscfg.in | 317 +++++++++++++++++++++++++++++++++++++ + util/grub.d/10_linux.in | 2 +- + 5 files changed, 328 insertions(+), 2 deletions(-) + create mode 100644 docs/man/grub-switch-to-blscfg.h2m + create mode 100644 util/grub-switch-to-blscfg.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index 18a9242776..88f55e35c4 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1348,6 +1348,13 @@ program = { + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; + ++script = { ++ name = grub-switch-to-blscfg; ++ common = util/grub-switch-to-blscfg.in; ++ mansection = 8; ++ installdir = sbin; ++}; ++ + program = { + name = grub-glue-efi; + mansection = 1; +diff --git a/docs/man/grub-switch-to-blscfg.h2m b/docs/man/grub-switch-to-blscfg.h2m +new file mode 100644 +index 0000000000..fa341426a5 +--- /dev/null ++++ b/docs/man/grub-switch-to-blscfg.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-switch-to-blscfg \- switch to using BLS config files +diff --git a/util/grub-set-password.in b/util/grub-set-password.in +index 5ebf50576d..c0b5ebbfdc 100644 +--- a/util/grub-set-password.in ++++ b/util/grub-set-password.in +@@ -1,6 +1,6 @@ + #!/bin/sh -e + +-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/') ++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') + if [ -d /sys/firmware/efi/efivars/ ]; then + grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` + else +diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in +new file mode 100644 +index 0000000000..a851424beb +--- /dev/null ++++ b/util/grub-switch-to-blscfg.in +@@ -0,0 +1,317 @@ ++#! /bin/sh ++# ++# Set a default boot entry for GRUB. ++# Copyright (C) 2004,2009 Free Software Foundation, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++#set -eu ++ ++# Initialize some variables. ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++sbindir=@sbindir@ ++bindir=@bindir@ ++sysconfdir="@sysconfdir@" ++PACKAGE_NAME=@PACKAGE_NAME@ ++PACKAGE_VERSION=@PACKAGE_VERSION@ ++datarootdir="@datarootdir@" ++datadir="@datadir@" ++if [ ! -v pkgdatadir ]; then ++ pkgdatadir="${datadir}/@PACKAGE@" ++fi ++ ++self=`basename $0` ++ ++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" ++grub_editenv=${bindir}/@grub_editenv@ ++etcdefaultgrub=/etc/default/grub ++ ++eval "$("${grub_get_kernel_settings}")" || true ++ ++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') ++if [ -d /sys/firmware/efi/efivars/ ]; then ++ startlink=/etc/grub2-efi.cfg ++ grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` ++else ++ startlink=/etc/grub2.cfg ++ grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` ++fi ++ ++blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'` ++ ++backupsuffix=.bak ++ ++arch="$(uname -m)" ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR="@localedir@" ++ ++. "${pkgdatadir}/grub-mkconfig_lib" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ gettext_printf "Usage: %s\n" "$self" ++ gettext "Switch to BLS config files.\n"; echo ++ echo ++ print_option_help "-h, --help" "$(gettext "print this message and exit")" ++ print_option_help "-V, --version" "$(gettext "print the version information and exit")" ++ echo ++ print_option_help "--backup-suffix=$(gettext "SUFFIX")" "$backupsuffix" ++ print_option_help "--bls-directory=$(gettext "DIR")" "$blsdir" ++ print_option_help "--config-file=$(gettext "FILE")" "$startlink" ++ print_option_help "--grub-defaults=$(gettext "FILE")" "$etcdefaultgrub" ++ print_option_help "--grub-directory=$(gettext "DIR")" "$grubdir" ++ # echo ++ # gettext "Report bugs to ."; echo ++} ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -V | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ ++ --backup-suffix) ++ backupsuffix=`argument $option "$@"` ++ shift ++ ;; ++ --backup-suffix=*) ++ backupsuffix=`echo "$option" | sed 's/--backup-suffix=//'` ++ ;; ++ ++ --bls-directory) ++ blsdir=`argument $option "$@"` ++ shift ++ ;; ++ --bls-directory=*) ++ blsdir=`echo "$option" | sed 's/--bls-directory=//'` ++ ;; ++ ++ --config-file) ++ startlink=`argument $option "$@"` ++ shift ++ ;; ++ --config-file=*) ++ startlink=`echo "$option" | sed 's/--config-file=//'` ++ ;; ++ ++ --grub-defaults) ++ etcdefaultgrub=`argument $option "$@"` ++ shift ++ ;; ++ --grub-defaults=*) ++ etcdefaultgrub=`echo "$option" | sed 's/--grub-defaults=//'` ++ ;; ++ ++ --grub-directory) ++ grubdir=`argument $option "$@"` ++ shift ++ ;; ++ --grub-directory=*) ++ grubdir=`echo "$option" | sed 's/--grub-directory=//'` ++ ;; ++ ++ *) ++ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 ++ usage ++ exit 1 ++ ;; ++ esac ++done ++ ++find_grub_cfg() { ++ local candidate="" ++ while [ -e "${candidate}" -o $# -gt 0 ] ++ do ++ if [ ! -e "${candidate}" ] ; then ++ candidate="$1" ++ shift ++ fi ++ ++ if [ -L "${candidate}" ]; then ++ candidate="$(realpath "${candidate}")" ++ fi ++ ++ if [ -f "${candidate}" ]; then ++ export GRUB_CONFIG_FILE="${candidate}" ++ return 0 ++ fi ++ done ++ return 1 ++} ++ ++if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then ++ gettext_printf "Couldn't find config file\n" 1>&2 ++ exit 1 ++fi ++ ++if [ ! -d "${blsdir}" ]; then ++ install -m 700 -d "${blsdir}" ++fi ++ ++if [ -f /etc/machine-id ]; then ++ MACHINE_ID=$(cat /etc/machine-id) ++else ++ MACHINE_ID=$(dmesg | sha256sum) ++fi ++ ++mkbls() { ++ local kernelver=$1 && shift ++ local datetime=$1 && shift ++ local kernelopts=$1 && shift ++ ++ local debugname="" ++ local debugid="" ++ local flavor="" ++ ++ if [ "$kernelver" == *\+* ] ; then ++ local flavor=-"${kernelver##*+}" ++ if [ "${flavor}" == "-debug" ]; then ++ local debugname=" with debugging" ++ local debugid="-debug" ++ fi ++ fi ++ ( ++ source /etc/os-release ++ ++ cat <"${bls_target}" ++ ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")" ++ cp -aT "${bls_target}" "${bls_debug}" ++ title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')" ++ options="$(echo "${cmdline} ${GRUB_CMDLINE_LINUX_DEBUG}" | sed -e 's/\//\\\//g')" ++ sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}" ++ sed -i -e "s/^options.*/options ${options}/" "${bls_debug}" ++ fi ++ done ++ ++ if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then ++ mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf" ++ fi ++} ++ ++# The grub2 EFI binary is not copied to the ESP as a part of an ostree ++# transaction. Make sure a grub2 version with BLS support is installed ++# but only do this if the blsdir is not set, to make sure that the BLS ++# parsing module will search for the BLS snippets in the default path. ++if test -f /run/ostree-booted && test -d /sys/firmware/efi/efivars && \ ++ ! ${grub_editenv} - list | grep -q blsdir && \ ++ mountpoint -q /boot; then ++ grub_binary="$(find /usr/lib/ostree-boot/efi/EFI/${EFIDIR}/ -name grub*.efi)" ++ install -m 700 ${grub_binary} ${grubdir} || exit 1 ++ # Create a hidden file to indicate that grub2 now has BLS support. ++ touch /boot/grub2/.grub2-blscfg-supported ++fi ++ ++GENERATE=0 ++if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \ ++ | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then ++ if ! sed -i"${backupsuffix}" \ ++ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=true,' \ ++ "${etcdefaultgrub}" ; then ++ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" ++ exit 1 ++ fi ++ GENERATE=1 ++elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then ++ if ! echo 'GRUB_ENABLE_BLSCFG=true' >> "${etcdefaultgrub}" ; then ++ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" ++ exit 1 ++ fi ++ GENERATE=1 ++fi ++ ++if [ "${GENERATE}" -eq 1 ] ; then ++ copy_bls ++ ++ if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then ++ mod_dir="i386-pc" ++ elif [ $arch = "ppc64" -o $arch = "ppc64le" ] && [ ! -d /sys/firmware/opal ]; then ++ mod_dir="powerpc-ieee1275" ++ fi ++ ++ if [ -n "${mod_dir}" ]; then ++ for mod in blscfg increment; do ++ install -m 700 ${prefix}/lib/grub/${mod_dir}/${mod}.mod ${grubdir}/$mod_dir/ || exit 1 ++ done ++ fi ++ ++ cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}" ++ if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then ++ install -m 700 "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}" ++ sed -i"${backupsuffix}" \ ++ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \ ++ "${etcdefaultgrub}" ++ gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}" ++ exit 1 ++ fi ++fi ++ ++# Bye. ++exit 0 +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 2851952659..e490e1a43a 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -138,7 +138,7 @@ blsdir="/boot/loader/entries" + + get_sorted_bls() + { +- if ! [ -d "${blsdir}" ]; then ++ if ! [ -d "${blsdir}" ] || [ -f /run/ostree-booted ] || [ -d /ostree/repo ]; then + return + fi + diff --git a/0061-Add-linux-and-initrd-commands-for-grub-emu.patch b/0061-Add-linux-and-initrd-commands-for-grub-emu.patch deleted file mode 100644 index 419fde3..0000000 --- a/0061-Add-linux-and-initrd-commands-for-grub-emu.patch +++ /dev/null @@ -1,350 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Raymund Will -Date: Tue, 6 Feb 2018 09:09:00 +0100 -Subject: [PATCH] Add linux and initrd commands for grub-emu - -When using grub-emu, the linux and initrd commands are used as arguments -to the kexec command line tool, to allow booting the selected menu entry. - -Signed-off-by: Raymund Will -Signed-off-by: Robbie Harwood ---- - grub-core/Makefile.core.def | 1 - - grub-core/kern/emu/main.c | 4 + - grub-core/kern/emu/misc.c | 18 ++++- - grub-core/loader/emu/linux.c | 172 +++++++++++++++++++++++++++++++++++++++++++ - include/grub/emu/exec.h | 4 +- - include/grub/emu/hostfile.h | 3 +- - include/grub/emu/misc.h | 3 + - grub-core/Makefile.am | 1 + - 8 files changed, 202 insertions(+), 4 deletions(-) - create mode 100644 grub-core/loader/emu/linux.c - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 058c88ac3a..5354f9613d 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1826,7 +1826,6 @@ module = { - - common = loader/linux.c; - common = lib/cmdline.c; -- enable = noemu; - - efi = loader/efi/linux.c; - }; -diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c -index 55ea5a11cc..846fe9715e 100644 ---- a/grub-core/kern/emu/main.c -+++ b/grub-core/kern/emu/main.c -@@ -107,6 +107,7 @@ static struct argp_option options[] = { - N_("use GRUB files in the directory DIR [default=%s]"), 0}, - {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, - {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0}, -+ {"kexec", 'X', 0, 0, N_("try the untryable."), 0}, - { 0, 0, 0, 0, 0, 0 } - }; - -@@ -164,6 +165,9 @@ argp_parser (int key, char *arg, struct argp_state *state) - case 'v': - verbosity++; - break; -+ case 'X': -+ grub_util_set_kexecute(); -+ break; - - case ARGP_KEY_ARG: - { -diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c -index 0ff13bcaf8..eeea092752 100644 ---- a/grub-core/kern/emu/misc.c -+++ b/grub-core/kern/emu/misc.c -@@ -39,6 +39,7 @@ - #include - - int verbosity; -+int kexecute; - - void - grub_util_warn (const char *fmt, ...) -@@ -82,7 +83,7 @@ grub_util_error (const char *fmt, ...) - vfprintf (stderr, fmt, ap); - va_end (ap); - fprintf (stderr, ".\n"); -- exit (1); -+ grub_exit (1); - } - - void * -@@ -154,6 +155,9 @@ void - __attribute__ ((noreturn)) - grub_exit (int rc) - { -+#if defined (GRUB_KERNEL) -+ grub_reboot(); -+#endif - exit (rc < 0 ? 1 : rc); - } - #endif -@@ -215,3 +219,15 @@ grub_util_load_image (const char *path, char *buf) - - fclose (fp); - } -+ -+void -+grub_util_set_kexecute(void) -+{ -+ kexecute++; -+} -+ -+int -+grub_util_get_kexecute(void) -+{ -+ return kexecute; -+} -diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c -new file mode 100644 -index 0000000000..fda9e00d24 ---- /dev/null -+++ b/grub-core/loader/emu/linux.c -@@ -0,0 +1,172 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static grub_dl_t my_mod; -+ -+static char *kernel_path; -+static char *initrd_path; -+static char *boot_cmdline; -+ -+static grub_err_t -+grub_linux_boot (void) -+{ -+ grub_err_t rc = GRUB_ERR_NONE; -+ char *initrd_param; -+ const char *kexec[] = { "kexec", "-l", kernel_path, boot_cmdline, NULL, NULL }; -+ const char *systemctl[] = { "systemctl", "kexec", NULL }; -+ int kexecute = grub_util_get_kexecute(); -+ -+ if (initrd_path) { -+ initrd_param = grub_xasprintf("--initrd=%s", initrd_path); -+ kexec[3] = initrd_param; -+ kexec[4] = boot_cmdline; -+ } else { -+ initrd_param = grub_xasprintf("%s", ""); -+ } -+ -+ grub_printf("%serforming 'kexec -l %s %s %s'\n", -+ (kexecute) ? "P" : "Not p", -+ kernel_path, initrd_param, boot_cmdline); -+ -+ if (kexecute) -+ rc = grub_util_exec(kexec); -+ -+ grub_free(initrd_param); -+ -+ if (rc != GRUB_ERR_NONE) { -+ grub_error (rc, N_("Error trying to perform kexec load operation.")); -+ grub_sleep (3); -+ return rc; -+ } -+ if (kexecute < 1) -+ grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart.")); -+ -+ grub_printf("Performing 'systemctl kexec' (%s) ", -+ (kexecute==1) ? "do-or-die" : "just-in-case"); -+ rc = grub_util_exec (systemctl); -+ -+ if (kexecute == 1) -+ grub_fatal (N_("Error trying to perform 'systemctl kexec'")); -+ -+ /* need to check read-only root before resetting hard!? */ -+ grub_printf("Performing 'kexec -e'"); -+ kexec[1] = "-e"; -+ kexec[2] = NULL; -+ rc = grub_util_exec(kexec); -+ if ( rc != GRUB_ERR_NONE ) -+ grub_fatal (N_("Error trying to directly perform 'kexec -e'.")); -+ -+ return rc; -+} -+ -+static grub_err_t -+grub_linux_unload (void) -+{ -+ grub_dl_unref (my_mod); -+ if ( boot_cmdline != NULL ) -+ grub_free (boot_cmdline); -+ boot_cmdline = NULL; -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) -+{ -+ int i; -+ char *tempstr; -+ -+ grub_dl_ref (my_mod); -+ -+ if (argc == 0) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); -+ -+ if ( !grub_util_is_regular(argv[0]) ) -+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find kernel file %s"), argv[0]); -+ -+ if ( kernel_path != NULL ) -+ grub_free(kernel_path); -+ -+ kernel_path = grub_xasprintf("%s", argv[0]); -+ -+ if ( boot_cmdline != NULL ) { -+ grub_free(boot_cmdline); -+ boot_cmdline = NULL; -+ } -+ -+ if ( argc > 1 ) -+ { -+ boot_cmdline = grub_xasprintf("--command-line=%s", argv[1]); -+ for ( i = 2; i < argc; i++ ) { -+ tempstr = grub_xasprintf("%s %s", boot_cmdline, argv[i]); -+ grub_free(boot_cmdline); -+ boot_cmdline = tempstr; -+ } -+ } -+ -+ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) -+{ -+ if (argc == 0) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); -+ -+ if ( !grub_util_is_regular(argv[0]) ) -+ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find initrd file %s"), argv[0]); -+ -+ if ( initrd_path != NULL ) -+ grub_free(initrd_path); -+ -+ initrd_path = grub_xasprintf("%s", argv[0]); -+ -+ grub_dl_unref (my_mod); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_command_t cmd_linux, cmd_initrd; -+ -+GRUB_MOD_INIT(linux) -+{ -+ cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, N_("Load Linux.")); -+ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, N_("Load initrd.")); -+ my_mod = mod; -+ kernel_path = NULL; -+ initrd_path = NULL; -+ boot_cmdline = NULL; -+} -+ -+GRUB_MOD_FINI(linux) -+{ -+ grub_unregister_command (cmd_linux); -+ grub_unregister_command (cmd_initrd); -+} -diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h -index d1073ef86a..1b61b4a2e5 100644 ---- a/include/grub/emu/exec.h -+++ b/include/grub/emu/exec.h -@@ -23,6 +23,8 @@ - #include - - #include -+#include -+ - pid_t - grub_util_exec_pipe (const char *const *argv, int *fd); - pid_t -@@ -32,7 +34,7 @@ int - grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file, - const char *stdout_file, const char *stderr_file); - int --grub_util_exec (const char *const *argv); -+EXPORT_FUNC(grub_util_exec) (const char *const *argv); - int - grub_util_exec_redirect (const char *const *argv, const char *stdin_file, - const char *stdout_file); -diff --git a/include/grub/emu/hostfile.h b/include/grub/emu/hostfile.h -index cfb1e2b566..a61568e36e 100644 ---- a/include/grub/emu/hostfile.h -+++ b/include/grub/emu/hostfile.h -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - #include - - int -@@ -29,7 +30,7 @@ grub_util_is_directory (const char *path); - int - grub_util_is_special_file (const char *path); - int --grub_util_is_regular (const char *path); -+EXPORT_FUNC(grub_util_is_regular) (const char *path); - - char * - grub_util_path_concat (size_t n, ...); -diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h -index ff9c48a649..01056954b9 100644 ---- a/include/grub/emu/misc.h -+++ b/include/grub/emu/misc.h -@@ -57,6 +57,9 @@ void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...) __attribute__ ((format ( - void EXPORT_FUNC(grub_util_info) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); - void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2), noreturn)); - -+void EXPORT_FUNC(grub_util_set_kexecute) (void); -+int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT; -+ - grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void); - - #ifdef HAVE_DEVICE_MAPPER -diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am -index ee88e44e97..80e7a83edf 100644 ---- a/grub-core/Makefile.am -+++ b/grub-core/Makefile.am -@@ -307,6 +307,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/net.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h -+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/exec.h - if COND_GRUB_EMU_SDL - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h - endif diff --git a/0062-Add-grub2-switch-to-blscfg.patch b/0062-Add-grub2-switch-to-blscfg.patch deleted file mode 100644 index e3144df..0000000 --- a/0062-Add-grub2-switch-to-blscfg.patch +++ /dev/null @@ -1,395 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 15 Mar 2018 14:12:40 -0400 -Subject: [PATCH] Add grub2-switch-to-blscfg - -Signed-off-by: Peter Jones -Signed-off-by: Javier Martinez Canillas -[jhlavac: Use ${etcdefaultgrub} instead of /etc/default/grub] -Signed-off-by: Jan Hlavac -[rharwood: skip on ostree installations, migrate man to h2m] -Signed-off-by: Robbie Harwood ---- - Makefile.util.def | 7 + - docs/man/grub-switch-to-blscfg.h2m | 2 + - util/grub-set-password.in | 2 +- - util/grub-switch-to-blscfg.in | 317 +++++++++++++++++++++++++++++++++++++ - util/grub.d/10_linux.in | 2 +- - 5 files changed, 328 insertions(+), 2 deletions(-) - create mode 100644 docs/man/grub-switch-to-blscfg.h2m - create mode 100644 util/grub-switch-to-blscfg.in - -diff --git a/Makefile.util.def b/Makefile.util.def -index 43a1c7453b..a90879fa9b 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -1365,6 +1365,13 @@ program = { - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; - }; - -+script = { -+ name = grub-switch-to-blscfg; -+ common = util/grub-switch-to-blscfg.in; -+ mansection = 8; -+ installdir = sbin; -+}; -+ - program = { - name = grub-glue-efi; - mansection = 1; -diff --git a/docs/man/grub-switch-to-blscfg.h2m b/docs/man/grub-switch-to-blscfg.h2m -new file mode 100644 -index 0000000000..fa341426a5 ---- /dev/null -+++ b/docs/man/grub-switch-to-blscfg.h2m -@@ -0,0 +1,2 @@ -+[NAME] -+grub-switch-to-blscfg \- switch to using BLS config files -diff --git a/util/grub-set-password.in b/util/grub-set-password.in -index 5ebf50576d..c0b5ebbfdc 100644 ---- a/util/grub-set-password.in -+++ b/util/grub-set-password.in -@@ -1,6 +1,6 @@ - #!/bin/sh -e - --EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/') -+EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') - if [ -d /sys/firmware/efi/efivars/ ]; then - grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` - else -diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in -new file mode 100644 -index 0000000000..a851424beb ---- /dev/null -+++ b/util/grub-switch-to-blscfg.in -@@ -0,0 +1,317 @@ -+#! /bin/sh -+# -+# Set a default boot entry for GRUB. -+# Copyright (C) 2004,2009 Free Software Foundation, Inc. -+# -+# GRUB is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# GRUB is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with GRUB. If not, see . -+ -+#set -eu -+ -+# Initialize some variables. -+prefix=@prefix@ -+exec_prefix=@exec_prefix@ -+sbindir=@sbindir@ -+bindir=@bindir@ -+sysconfdir="@sysconfdir@" -+PACKAGE_NAME=@PACKAGE_NAME@ -+PACKAGE_VERSION=@PACKAGE_VERSION@ -+datarootdir="@datarootdir@" -+datadir="@datadir@" -+if [ ! -v pkgdatadir ]; then -+ pkgdatadir="${datadir}/@PACKAGE@" -+fi -+ -+self=`basename $0` -+ -+grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" -+grub_editenv=${bindir}/@grub_editenv@ -+etcdefaultgrub=/etc/default/grub -+ -+eval "$("${grub_get_kernel_settings}")" || true -+ -+EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') -+if [ -d /sys/firmware/efi/efivars/ ]; then -+ startlink=/etc/grub2-efi.cfg -+ grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` -+else -+ startlink=/etc/grub2.cfg -+ grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` -+fi -+ -+blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'` -+ -+backupsuffix=.bak -+ -+arch="$(uname -m)" -+ -+export TEXTDOMAIN=@PACKAGE@ -+export TEXTDOMAINDIR="@localedir@" -+ -+. "${pkgdatadir}/grub-mkconfig_lib" -+ -+# Usage: usage -+# Print the usage. -+usage () { -+ gettext_printf "Usage: %s\n" "$self" -+ gettext "Switch to BLS config files.\n"; echo -+ echo -+ print_option_help "-h, --help" "$(gettext "print this message and exit")" -+ print_option_help "-V, --version" "$(gettext "print the version information and exit")" -+ echo -+ print_option_help "--backup-suffix=$(gettext "SUFFIX")" "$backupsuffix" -+ print_option_help "--bls-directory=$(gettext "DIR")" "$blsdir" -+ print_option_help "--config-file=$(gettext "FILE")" "$startlink" -+ print_option_help "--grub-defaults=$(gettext "FILE")" "$etcdefaultgrub" -+ print_option_help "--grub-directory=$(gettext "DIR")" "$grubdir" -+ # echo -+ # gettext "Report bugs to ."; echo -+} -+ -+argument () { -+ opt=$1 -+ shift -+ -+ if test $# -eq 0; then -+ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 -+ exit 1 -+ fi -+ echo $1 -+} -+ -+# Check the arguments. -+while test $# -gt 0 -+do -+ option=$1 -+ shift -+ -+ case "$option" in -+ -h | --help) -+ usage -+ exit 0 ;; -+ -V | --version) -+ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" -+ exit 0 ;; -+ -+ --backup-suffix) -+ backupsuffix=`argument $option "$@"` -+ shift -+ ;; -+ --backup-suffix=*) -+ backupsuffix=`echo "$option" | sed 's/--backup-suffix=//'` -+ ;; -+ -+ --bls-directory) -+ blsdir=`argument $option "$@"` -+ shift -+ ;; -+ --bls-directory=*) -+ blsdir=`echo "$option" | sed 's/--bls-directory=//'` -+ ;; -+ -+ --config-file) -+ startlink=`argument $option "$@"` -+ shift -+ ;; -+ --config-file=*) -+ startlink=`echo "$option" | sed 's/--config-file=//'` -+ ;; -+ -+ --grub-defaults) -+ etcdefaultgrub=`argument $option "$@"` -+ shift -+ ;; -+ --grub-defaults=*) -+ etcdefaultgrub=`echo "$option" | sed 's/--grub-defaults=//'` -+ ;; -+ -+ --grub-directory) -+ grubdir=`argument $option "$@"` -+ shift -+ ;; -+ --grub-directory=*) -+ grubdir=`echo "$option" | sed 's/--grub-directory=//'` -+ ;; -+ -+ *) -+ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 -+ usage -+ exit 1 -+ ;; -+ esac -+done -+ -+find_grub_cfg() { -+ local candidate="" -+ while [ -e "${candidate}" -o $# -gt 0 ] -+ do -+ if [ ! -e "${candidate}" ] ; then -+ candidate="$1" -+ shift -+ fi -+ -+ if [ -L "${candidate}" ]; then -+ candidate="$(realpath "${candidate}")" -+ fi -+ -+ if [ -f "${candidate}" ]; then -+ export GRUB_CONFIG_FILE="${candidate}" -+ return 0 -+ fi -+ done -+ return 1 -+} -+ -+if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then -+ gettext_printf "Couldn't find config file\n" 1>&2 -+ exit 1 -+fi -+ -+if [ ! -d "${blsdir}" ]; then -+ install -m 700 -d "${blsdir}" -+fi -+ -+if [ -f /etc/machine-id ]; then -+ MACHINE_ID=$(cat /etc/machine-id) -+else -+ MACHINE_ID=$(dmesg | sha256sum) -+fi -+ -+mkbls() { -+ local kernelver=$1 && shift -+ local datetime=$1 && shift -+ local kernelopts=$1 && shift -+ -+ local debugname="" -+ local debugid="" -+ local flavor="" -+ -+ if [ "$kernelver" == *\+* ] ; then -+ local flavor=-"${kernelver##*+}" -+ if [ "${flavor}" == "-debug" ]; then -+ local debugname=" with debugging" -+ local debugid="-debug" -+ fi -+ fi -+ ( -+ source /etc/os-release -+ -+ cat <"${bls_target}" -+ -+ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then -+ bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")" -+ cp -aT "${bls_target}" "${bls_debug}" -+ title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')" -+ options="$(echo "${cmdline} ${GRUB_CMDLINE_LINUX_DEBUG}" | sed -e 's/\//\\\//g')" -+ sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}" -+ sed -i -e "s/^options.*/options ${options}/" "${bls_debug}" -+ fi -+ done -+ -+ if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then -+ mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf" -+ fi -+} -+ -+# The grub2 EFI binary is not copied to the ESP as a part of an ostree -+# transaction. Make sure a grub2 version with BLS support is installed -+# but only do this if the blsdir is not set, to make sure that the BLS -+# parsing module will search for the BLS snippets in the default path. -+if test -f /run/ostree-booted && test -d /sys/firmware/efi/efivars && \ -+ ! ${grub_editenv} - list | grep -q blsdir && \ -+ mountpoint -q /boot; then -+ grub_binary="$(find /usr/lib/ostree-boot/efi/EFI/${EFIDIR}/ -name grub*.efi)" -+ install -m 700 ${grub_binary} ${grubdir} || exit 1 -+ # Create a hidden file to indicate that grub2 now has BLS support. -+ touch /boot/grub2/.grub2-blscfg-supported -+fi -+ -+GENERATE=0 -+if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \ -+ | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then -+ if ! sed -i"${backupsuffix}" \ -+ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=true,' \ -+ "${etcdefaultgrub}" ; then -+ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" -+ exit 1 -+ fi -+ GENERATE=1 -+elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then -+ if ! echo 'GRUB_ENABLE_BLSCFG=true' >> "${etcdefaultgrub}" ; then -+ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" -+ exit 1 -+ fi -+ GENERATE=1 -+fi -+ -+if [ "${GENERATE}" -eq 1 ] ; then -+ copy_bls -+ -+ if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then -+ mod_dir="i386-pc" -+ elif [ $arch = "ppc64" -o $arch = "ppc64le" ] && [ ! -d /sys/firmware/opal ]; then -+ mod_dir="powerpc-ieee1275" -+ fi -+ -+ if [ -n "${mod_dir}" ]; then -+ for mod in blscfg increment; do -+ install -m 700 ${prefix}/lib/grub/${mod_dir}/${mod}.mod ${grubdir}/$mod_dir/ || exit 1 -+ done -+ fi -+ -+ cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}" -+ if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then -+ install -m 700 "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}" -+ sed -i"${backupsuffix}" \ -+ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \ -+ "${etcdefaultgrub}" -+ gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}" -+ exit 1 -+ fi -+fi -+ -+# Bye. -+exit 0 -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index f1548a2605..c02c1f0820 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -138,7 +138,7 @@ blsdir="/boot/loader/entries" - - get_sorted_bls() - { -- if ! [ -d "${blsdir}" ]; then -+ if ! [ -d "${blsdir}" ] || [ -f /run/ostree-booted ] || [ -d /ostree/repo ]; then - return - fi - diff --git a/0062-make-better-backtraces.patch b/0062-make-better-backtraces.patch new file mode 100644 index 0000000..e6ae4e9 --- /dev/null +++ b/0062-make-better-backtraces.patch @@ -0,0 +1,910 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 17:05:03 +0200 +Subject: [PATCH] make better backtraces + +Signed-off-by: Peter Jones +--- + Makefile.util.def | 6 ++ + grub-core/Makefile.core.def | 16 ++-- + grub-core/{lib => commands}/backtrace.c | 2 +- + grub-core/gdb/cstub.c | 1 - + grub-core/kern/arm64/backtrace.c | 94 ++++++++++++++++++++++++ + grub-core/kern/backtrace.c | 97 +++++++++++++++++++++++++ + grub-core/kern/dl.c | 45 ++++++++++++ + grub-core/kern/i386/backtrace.c | 125 ++++++++++++++++++++++++++++++++ + grub-core/kern/i386/pc/init.c | 4 +- + grub-core/kern/ieee1275/init.c | 1 - + grub-core/kern/misc.c | 13 ++-- + grub-core/kern/mm.c | 6 +- + grub-core/lib/arm64/backtrace.c | 62 ---------------- + grub-core/lib/i386/backtrace.c | 78 -------------------- + include/grub/backtrace.h | 10 ++- + include/grub/dl.h | 2 + + include/grub/kernel.h | 3 + + grub-core/kern/arm/efi/startup.S | 2 + + grub-core/kern/arm/startup.S | 2 + + grub-core/kern/arm64/efi/startup.S | 2 + + grub-core/kern/i386/qemu/startup.S | 3 +- + grub-core/kern/ia64/efi/startup.S | 3 +- + grub-core/kern/sparc64/ieee1275/crt0.S | 3 +- + grub-core/Makefile.am | 1 + + 24 files changed, 414 insertions(+), 167 deletions(-) + rename grub-core/{lib => commands}/backtrace.c (98%) + create mode 100644 grub-core/kern/arm64/backtrace.c + create mode 100644 grub-core/kern/backtrace.c + create mode 100644 grub-core/kern/i386/backtrace.c + delete mode 100644 grub-core/lib/arm64/backtrace.c + delete mode 100644 grub-core/lib/i386/backtrace.c + +diff --git a/Makefile.util.def b/Makefile.util.def +index 88f55e35c4..bda9fd1211 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -51,6 +51,12 @@ library = { + common = grub-core/partmap/msdos.c; + common = grub-core/fs/proc.c; + common = grub-core/fs/archelp.c; ++ common = grub-core/kern/backtrace.c; ++ ++ x86 = grub-core/kern/i386/backtrace.c; ++ i386_xen = grub-core/kern/i386/backtrace.c; ++ x86_64_xen = grub-core/kern/i386/backtrace.c; ++ arm64 = grub-core/kern/arm64/backtrace.c; + }; + + library = { +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 5354f9613d..4b7c45a7b0 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -142,6 +142,12 @@ kernel = { + common = kern/rescue_reader.c; + common = kern/term.c; + common = kern/verifiers.c; ++ common = kern/backtrace.c; ++ ++ x86 = kern/i386/backtrace.c; ++ i386_xen = kern/i386/backtrace.c; ++ x86_64_xen = kern/i386/backtrace.c; ++ arm64 = kern/arm64/backtrace.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; +@@ -188,9 +194,6 @@ kernel = { + + softdiv = lib/division.c; + +- x86 = lib/i386/backtrace.c; +- x86 = lib/backtrace.c; +- + i386 = kern/i386/dl.c; + i386_xen = kern/i386/dl.c; + i386_xen_pvh = kern/i386/dl.c; +@@ -2398,15 +2401,12 @@ module = { + + module = { + name = backtrace; +- x86 = lib/i386/backtrace.c; +- i386_xen_pvh = lib/i386/backtrace.c; +- i386_xen = lib/i386/backtrace.c; +- x86_64_xen = lib/i386/backtrace.c; +- common = lib/backtrace.c; ++ common = commands/backtrace.c; + enable = x86; + enable = i386_xen_pvh; + enable = i386_xen; + enable = x86_64_xen; ++ enable = arm64; + }; + + module = { +diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c +similarity index 98% +rename from grub-core/lib/backtrace.c +rename to grub-core/commands/backtrace.c +index c0ad6ab8be..8b5ec3913b 100644 +--- a/grub-core/lib/backtrace.c ++++ b/grub-core/commands/backtrace.c +@@ -54,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) + { +- grub_backtrace (); ++ grub_backtrace (1); + return 0; + } + +diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c +index b64acd70fe..99281472d3 100644 +--- a/grub-core/gdb/cstub.c ++++ b/grub-core/gdb/cstub.c +@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no) + grub_printf ("Unhandled exception 0x%x at ", trap_no); + grub_backtrace_print_address ((void *) grub_gdb_regs[PC]); + grub_printf ("\n"); +- grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]); + grub_fatal ("Unhandled exception"); + } + +diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c +new file mode 100644 +index 0000000000..019c6fdfef +--- /dev/null ++++ b/grub-core/kern/arm64/backtrace.c +@@ -0,0 +1,94 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++struct fplr ++{ ++ void *lr; ++ struct fplr *fp; ++}; ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++{ ++ unsigned int x = 0; ++ struct fplr *fplr = (struct fplr *)frame; ++ ++ while (fplr) ++ { ++ const char *name = NULL; ++ char *addr = NULL; ++ ++ grub_dprintf("backtrace", "fp is %p next_fp is %p\n", ++ fplr, fplr->fp); ++ ++ if (x >= skip) ++ { ++ name = grub_get_symbol_by_addr (fplr->lr, 1); ++ if (name) ++ addr = grub_resolve_symbol (name); ++ grub_backtrace_print_address (fplr->lr); ++ ++ if (addr && addr != fplr->lr) ++ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, ++ (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr)); ++ else ++ grub_printf(" %s() %p \n", name ? name : "unknown", addr); ++ ++ } ++ ++ x += 1; ++ ++ if (fplr->fp < fplr || ++ (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME || ++ fplr->fp == fplr) ++ { ++ break; ++ } ++ fplr = fplr->fp; ++ } ++} ++ ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.quad .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.quad .data\n" ++ ); ++ ++extern grub_uint64_t _text; ++extern grub_uint64_t _data; ++ ++void ++grub_backtrace_arch (unsigned int skip) ++{ ++ grub_printf ("Backtrace (.text %p .data %p):\n", ++ (void *)_text, (void *)_data); ++ skip += 1; ++ grub_backtrace_pointer(__builtin_frame_address(0), skip); ++} +diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c +new file mode 100644 +index 0000000000..4a82e865cc +--- /dev/null ++++ b/grub-core/kern/backtrace.c +@@ -0,0 +1,97 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static void ++grub_backtrace_print_address_default (void *addr) ++{ ++#ifndef GRUB_UTIL ++ grub_dl_t mod; ++ void *start_addr; ++ ++ FOR_DL_MODULES (mod) ++ { ++ grub_dl_segment_t segment; ++ for (segment = mod->segment; segment; segment = segment->next) ++ if (segment->addr <= addr && (grub_uint8_t *) segment->addr ++ + segment->size > (grub_uint8_t *) addr) ++ { ++ grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name, ++ segment->section, ++ (grub_size_t) ++ ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr)); ++ return; ++ } ++ } ++ ++ start_addr = grub_resolve_symbol ("_start"); ++ if (start_addr && start_addr < addr) ++ grub_printf ("kernel+%" PRIxGRUB_SIZE, ++ (grub_size_t) ++ ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr)); ++ else ++#endif ++ grub_printf ("%p", addr); ++} ++ ++static void ++grub_backtrace_pointer_default (void *frame __attribute__((__unused__)), ++ unsigned int skip __attribute__((__unused__))) ++{ ++ return; ++} ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++ __attribute__((__weak__, ++ __alias__(("grub_backtrace_pointer_default")))); ++ ++void ++grub_backtrace_print_address (void *addr) ++ __attribute__((__weak__, ++ __alias__(("grub_backtrace_print_address_default")))); ++ ++static void ++grub_backtrace_arch_default(unsigned int skip) ++{ ++ grub_backtrace_pointer(__builtin_frame_address(0), skip + 1); ++} ++ ++void grub_backtrace_arch (unsigned int skip) ++ __attribute__((__weak__, __alias__(("grub_backtrace_arch_default")))); ++ ++void grub_backtrace (unsigned int skip) ++{ ++ grub_backtrace_arch(skip + 1); ++} ++ ++void grub_debug_backtrace (const char * const debug, ++ unsigned int skip) ++{ ++ if (grub_debug_enabled (debug)) ++ grub_backtrace (skip + 1); ++} +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 7afb9e6f72..88d2077709 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -124,6 +124,50 @@ grub_dl_resolve_symbol (const char *name) + return 0; + } + ++void * ++grub_resolve_symbol (const char *name) ++{ ++ grub_symbol_t sym; ++ ++ sym = grub_dl_resolve_symbol (name); ++ if (sym) ++ return sym->addr; ++ return NULL; ++} ++ ++const char * ++grub_get_symbol_by_addr(const void *addr, int isfunc) ++{ ++ unsigned int i; ++ grub_symbol_t before = NULL, after = NULL; ++ for (i = 0; i < GRUB_SYMTAB_SIZE; i++) ++ { ++ grub_symbol_t sym; ++ for (sym = grub_symtab[i]; sym; sym = sym->next) ++ { ++ //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name); ++ if (sym->addr > addr) ++ { ++ if (!after || sym->addr > after->addr) ++ after = sym; ++ } ++ ++ if (isfunc != sym->isfunc) ++ continue; ++ if (sym->addr > addr) ++ continue; ++ ++ if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr)) ++ before = sym; ++ } ++ } ++ ++ if (before && addr < after->addr) ++ return before->name; ++ ++ return NULL; ++} ++ + /* Register a symbol with the name NAME and the address ADDR. */ + grub_err_t + grub_dl_register_symbol (const char *name, void *addr, int isfunc, +@@ -336,6 +380,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) + const char *str; + Elf_Word size, entsize; + ++ grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name); + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c +new file mode 100644 +index 0000000000..2413f9a57d +--- /dev/null ++++ b/grub-core/kern/i386/backtrace.c +@@ -0,0 +1,125 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++{ ++ void **ebp = (void **)frame; ++ unsigned long x = 0; ++ ++ while (ebp) ++ { ++ void **next_ebp = (void **)ebp[0]; ++ const char *name = NULL; ++ char *addr = NULL; ++ ++ grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp); ++ ++ if (x >= skip) ++ { ++ name = grub_get_symbol_by_addr (ebp[1], 1); ++ if (name) ++ addr = grub_resolve_symbol (name); ++ grub_backtrace_print_address (ebp[1]); ++ ++ if (addr && addr != ebp[1]) ++ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, ++ (char *)((char *)ebp[1] - addr)); ++ else ++ grub_printf(" %s() %p \n", name ? name : "unknown", addr); ++ ++#if 0 ++ grub_printf ("("); ++ for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++) ++ grub_printf ("%p,", arg); ++ grub_printf (")\n"); ++#endif ++ } ++ ++ x += 1; ++ ++ if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp) ++ { ++ //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp); ++ break; ++ } ++ ebp = next_ebp; ++ } ++} ++ ++#if defined (__x86_64__) ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.quad .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.quad .data\n" ++ ); ++#elif defined(__i386__) ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.long .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.long .data\n" ++ ); ++#else ++#warning I dunno... ++#endif ++ ++extern unsigned long _text; ++extern unsigned long _data; ++ ++#ifdef GRUB_UTIL ++#define EXT_C(x) x ++#endif ++ ++void ++grub_backtrace_arch (unsigned int skip) ++{ ++ grub_printf ("Backtrace (.text %p .data %p):\n", ++ (void *)_text, (void *)_data); ++ skip += 1; ++#if defined (__x86_64__) ++ asm volatile ("movq %%rbp, %%rdi\n" ++ "movq 0, %%rsi\n" ++ "movl %0, %%esi\n" ++ "call " EXT_C("grub_backtrace_pointer") ++ : ++ : "r" (skip)); ++#elif defined(__i386__) ++ asm volatile ("addl $8, %%esp\n" ++ "pushl %0\n" ++ "pushl %%ebp\n" ++ "call " EXT_C("grub_backtrace_pointer") ++ : ++ : "r" (skip)); ++#else ++ grub_backtrace_pointer(__builtin_frame_address(0), skip); ++#endif ++} +diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c +index 27bc68b8a5..b51d0abfa6 100644 +--- a/grub-core/kern/i386/pc/init.c ++++ b/grub-core/kern/i386/pc/init.c +@@ -153,7 +153,7 @@ compact_mem_regions (void) + } + + grub_addr_t grub_modbase; +-extern grub_uint8_t _start[], _edata[]; ++extern grub_uint8_t _edata[]; + + /* Helper for grub_machine_init. */ + static int +@@ -217,7 +217,7 @@ grub_machine_init (void) + /* This has to happen before any BIOS calls. */ + grub_via_workaround_init (); + +- grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start); ++ grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start); + + /* Initialize the console as early as possible. */ + grub_console_init (); +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 0cd2a62723..937c1bc44c 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -63,7 +63,6 @@ + #define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) + #endif + +-extern char _start[]; + extern char _end[]; + + #ifdef __sparc__ +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index c60601b699..a432a6be54 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1197,15 +1197,15 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) + + + /* Abort GRUB. This function does not return. */ +-static void __attribute__ ((noreturn)) ++static inline void __attribute__ ((noreturn)) + grub_abort (void) + { +-#ifndef GRUB_UTIL +-#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU) +- grub_backtrace(); ++#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL) ++ grub_backtrace (1); ++#else ++ grub_printf ("\n"); + #endif +-#endif +- grub_printf ("\nAborted."); ++ grub_printf ("Aborted."); + + #ifndef GRUB_UTIL + if (grub_term_inputs) +@@ -1232,6 +1232,7 @@ grub_fatal (const char *fmt, ...) + { + va_list ap; + ++ grub_printf ("\n"); + va_start (ap, fmt); + grub_vprintf (_(fmt), ap); + va_end (ap); +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index c070afc621..d8c8377578 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -97,13 +97,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r) + break; + + if (! *r) +- grub_fatal ("out of range pointer %p", ptr); ++ grub_fatal ("out of range pointer %p\n", ptr); + + *p = (grub_mm_header_t) ptr - 1; + if ((*p)->magic == GRUB_MM_FREE_MAGIC) +- grub_fatal ("double free at %p", *p); ++ grub_fatal ("double free at %p\n", *p); + if ((*p)->magic != GRUB_MM_ALLOC_MAGIC) +- grub_fatal ("alloc magic is broken at %p: %lx", *p, ++ grub_fatal ("alloc magic is broken at %p: %lx\n", *p, + (unsigned long) (*p)->magic); + } + +diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c +deleted file mode 100644 +index 1079b5380e..0000000000 +--- a/grub-core/lib/arm64/backtrace.c ++++ /dev/null +@@ -1,62 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2009 Free Software Foundation, Inc. +- * +- * GRUB is free software: you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation, either version 3 of the License, or +- * (at your option) any later version. +- * +- * GRUB is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with GRUB. If not, see . +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define MAX_STACK_FRAME 102400 +- +-void +-grub_backtrace_pointer (int frame) +-{ +- while (1) +- { +- void *lp = __builtin_return_address (frame); +- if (!lp) +- break; +- +- lp = __builtin_extract_return_addr (lp); +- +- grub_printf ("%p: ", lp); +- grub_backtrace_print_address (lp); +- grub_printf (" ("); +- for (i = 0; i < 2; i++) +- grub_printf ("%p,", ((void **)ptr) [i + 2]); +- grub_printf ("%p)\n", ((void **)ptr) [i + 2]); +- nptr = *(void **)ptr; +- if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME +- || nptr == ptr) +- { +- grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); +- break; +- } +- ptr = nptr; +- } +-} +- +-void +-grub_backtrace (void) +-{ +- grub_backtrace_pointer (1); +-} +- +diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c +deleted file mode 100644 +index c67273db3a..0000000000 +--- a/grub-core/lib/i386/backtrace.c ++++ /dev/null +@@ -1,78 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2009 Free Software Foundation, Inc. +- * +- * GRUB is free software: you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation, either version 3 of the License, or +- * (at your option) any later version. +- * +- * GRUB is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with GRUB. If not, see . +- */ +-#include +-#ifdef GRUB_UTIL +-#define REALLY_GRUB_UTIL GRUB_UTIL +-#undef GRUB_UTIL +-#endif +- +-#include +-#include +- +-#ifdef REALLY_GRUB_UTIL +-#define GRUB_UTIL REALLY_GRUB_UTIL +-#undef REALLY_GRUB_UTIL +-#endif +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define MAX_STACK_FRAME 102400 +- +-void +-grub_backtrace_pointer (void *ebp) +-{ +- void *ptr, *nptr; +- unsigned i; +- +- ptr = ebp; +- while (1) +- { +- grub_printf ("%p: ", ptr); +- grub_backtrace_print_address (((void **) ptr)[1]); +- grub_printf (" ("); +- for (i = 0; i < 2; i++) +- grub_printf ("%p,", ((void **)ptr) [i + 2]); +- grub_printf ("%p)\n", ((void **)ptr) [i + 2]); +- nptr = *(void **)ptr; +- if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME +- || nptr == ptr) +- { +- grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); +- break; +- } +- ptr = nptr; +- } +-} +- +-void +-grub_backtrace (void) +-{ +-#ifdef __x86_64__ +- asm volatile ("movq %%rbp, %%rdi\n" +- "callq *%%rax": :"a"(grub_backtrace_pointer)); +-#else +- asm volatile ("movl %%ebp, %%eax\n" +- "calll *%%ecx": :"c"(grub_backtrace_pointer)); +-#endif +-} +- +diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h +index 395519762f..275cf85e2d 100644 +--- a/include/grub/backtrace.h ++++ b/include/grub/backtrace.h +@@ -19,8 +19,14 @@ + #ifndef GRUB_BACKTRACE_HEADER + #define GRUB_BACKTRACE_HEADER 1 + +-void grub_backtrace (void); +-void grub_backtrace_pointer (void *ptr); ++#include ++#include ++ ++void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug, ++ unsigned int skip); ++void EXPORT_FUNC(grub_backtrace) (unsigned int skip); ++void grub_backtrace_arch (unsigned int skip); ++void grub_backtrace_pointer (void *ptr, unsigned int skip); + void grub_backtrace_print_address (void *addr); + + #endif +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 91933b85f2..2f76e6b043 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -259,6 +259,8 @@ grub_dl_is_persistent (grub_dl_t mod) + + #endif + ++void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); ++const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc); + grub_err_t grub_dl_register_symbol (const char *name, void *addr, + int isfunc, grub_dl_t mod); + +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index abbca5ea33..300a9766cd 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -111,6 +111,9 @@ grub_addr_t grub_modules_get_end (void); + + #endif + ++void EXPORT_FUNC(start) (void); ++void EXPORT_FUNC(_start) (void); ++ + /* The start point of the C code. */ + void grub_main (void) __attribute__ ((noreturn)); + +diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S +index 9f8265315a..f3bc41f9d0 100644 +--- a/grub-core/kern/arm/efi/startup.S ++++ b/grub-core/kern/arm/efi/startup.S +@@ -23,6 +23,8 @@ + .file "startup.S" + .text + .arm ++ .globl start, _start ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0. +diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S +index 3946fe8e18..5679a1d00a 100644 +--- a/grub-core/kern/arm/startup.S ++++ b/grub-core/kern/arm/startup.S +@@ -48,6 +48,8 @@ + + .text + .arm ++ .globl start, _start ++FUNCTION(start) + FUNCTION(_start) + b codestart + +diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S +index 666a7ee3c9..41676bdb2b 100644 +--- a/grub-core/kern/arm64/efi/startup.S ++++ b/grub-core/kern/arm64/efi/startup.S +@@ -19,7 +19,9 @@ + #include + + .file "startup.S" ++ .globl start, _start + .text ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0. +diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S +index 0d89858d9b..939f182fc7 100644 +--- a/grub-core/kern/i386/qemu/startup.S ++++ b/grub-core/kern/i386/qemu/startup.S +@@ -24,7 +24,8 @@ + + .text + .code32 +- .globl _start ++ .globl start, _start ++start: + _start: + jmp codestart + +diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S +index d75c6d7cc7..8f2a593e52 100644 +--- a/grub-core/kern/ia64/efi/startup.S ++++ b/grub-core/kern/ia64/efi/startup.S +@@ -24,8 +24,9 @@ + .psr lsb + .lsb + +- .global _start ++ .global start, _start + .proc _start ++start: + _start: + alloc loc0=ar.pfs,2,4,0,0 + mov loc1=rp +diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S +index 03b916f053..701bf63abc 100644 +--- a/grub-core/kern/sparc64/ieee1275/crt0.S ++++ b/grub-core/kern/sparc64/ieee1275/crt0.S +@@ -22,7 +22,8 @@ + + .text + .align 4 +- .globl _start ++ .globl start, _start ++start: + _start: + ba codestart + mov %o4, %o0 +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index 80e7a83edf..f512573c0d 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h + + include $(srcdir)/Makefile.core.am + ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h diff --git a/0063-make-better-backtraces.patch b/0063-make-better-backtraces.patch deleted file mode 100644 index ffdb895..0000000 --- a/0063-make-better-backtraces.patch +++ /dev/null @@ -1,910 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 9 Jul 2019 17:05:03 +0200 -Subject: [PATCH] make better backtraces - -Signed-off-by: Peter Jones ---- - Makefile.util.def | 6 ++ - grub-core/Makefile.core.def | 16 ++-- - grub-core/{lib => commands}/backtrace.c | 2 +- - grub-core/gdb/cstub.c | 1 - - grub-core/kern/arm64/backtrace.c | 94 ++++++++++++++++++++++++ - grub-core/kern/backtrace.c | 97 +++++++++++++++++++++++++ - grub-core/kern/dl.c | 45 ++++++++++++ - grub-core/kern/i386/backtrace.c | 125 ++++++++++++++++++++++++++++++++ - grub-core/kern/i386/pc/init.c | 4 +- - grub-core/kern/ieee1275/init.c | 1 - - grub-core/kern/misc.c | 13 ++-- - grub-core/kern/mm.c | 6 +- - grub-core/lib/arm64/backtrace.c | 62 ---------------- - grub-core/lib/i386/backtrace.c | 78 -------------------- - include/grub/backtrace.h | 10 ++- - include/grub/dl.h | 2 + - include/grub/kernel.h | 3 + - grub-core/kern/arm/efi/startup.S | 2 + - grub-core/kern/arm/startup.S | 2 + - grub-core/kern/arm64/efi/startup.S | 2 + - grub-core/kern/i386/qemu/startup.S | 3 +- - grub-core/kern/ia64/efi/startup.S | 3 +- - grub-core/kern/sparc64/ieee1275/crt0.S | 3 +- - grub-core/Makefile.am | 1 + - 24 files changed, 414 insertions(+), 167 deletions(-) - rename grub-core/{lib => commands}/backtrace.c (98%) - create mode 100644 grub-core/kern/arm64/backtrace.c - create mode 100644 grub-core/kern/backtrace.c - create mode 100644 grub-core/kern/i386/backtrace.c - delete mode 100644 grub-core/lib/arm64/backtrace.c - delete mode 100644 grub-core/lib/i386/backtrace.c - -diff --git a/Makefile.util.def b/Makefile.util.def -index a90879fa9b..48512bc631 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -51,6 +51,12 @@ library = { - common = grub-core/partmap/msdos.c; - common = grub-core/fs/proc.c; - common = grub-core/fs/archelp.c; -+ common = grub-core/kern/backtrace.c; -+ -+ x86 = grub-core/kern/i386/backtrace.c; -+ i386_xen = grub-core/kern/i386/backtrace.c; -+ x86_64_xen = grub-core/kern/i386/backtrace.c; -+ arm64 = grub-core/kern/arm64/backtrace.c; - }; - - library = { -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 5354f9613d..4b7c45a7b0 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -142,6 +142,12 @@ kernel = { - common = kern/rescue_reader.c; - common = kern/term.c; - common = kern/verifiers.c; -+ common = kern/backtrace.c; -+ -+ x86 = kern/i386/backtrace.c; -+ i386_xen = kern/i386/backtrace.c; -+ x86_64_xen = kern/i386/backtrace.c; -+ arm64 = kern/arm64/backtrace.c; - - noemu = kern/compiler-rt.c; - noemu = kern/mm.c; -@@ -188,9 +194,6 @@ kernel = { - - softdiv = lib/division.c; - -- x86 = lib/i386/backtrace.c; -- x86 = lib/backtrace.c; -- - i386 = kern/i386/dl.c; - i386_xen = kern/i386/dl.c; - i386_xen_pvh = kern/i386/dl.c; -@@ -2398,15 +2401,12 @@ module = { - - module = { - name = backtrace; -- x86 = lib/i386/backtrace.c; -- i386_xen_pvh = lib/i386/backtrace.c; -- i386_xen = lib/i386/backtrace.c; -- x86_64_xen = lib/i386/backtrace.c; -- common = lib/backtrace.c; -+ common = commands/backtrace.c; - enable = x86; - enable = i386_xen_pvh; - enable = i386_xen; - enable = x86_64_xen; -+ enable = arm64; - }; - - module = { -diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c -similarity index 98% -rename from grub-core/lib/backtrace.c -rename to grub-core/commands/backtrace.c -index c0ad6ab8be..8b5ec3913b 100644 ---- a/grub-core/lib/backtrace.c -+++ b/grub-core/commands/backtrace.c -@@ -54,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) - { -- grub_backtrace (); -+ grub_backtrace (1); - return 0; - } - -diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c -index b64acd70fe..99281472d3 100644 ---- a/grub-core/gdb/cstub.c -+++ b/grub-core/gdb/cstub.c -@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no) - grub_printf ("Unhandled exception 0x%x at ", trap_no); - grub_backtrace_print_address ((void *) grub_gdb_regs[PC]); - grub_printf ("\n"); -- grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]); - grub_fatal ("Unhandled exception"); - } - -diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c -new file mode 100644 -index 0000000000..019c6fdfef ---- /dev/null -+++ b/grub-core/kern/arm64/backtrace.c -@@ -0,0 +1,94 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MAX_STACK_FRAME 102400 -+ -+struct fplr -+{ -+ void *lr; -+ struct fplr *fp; -+}; -+ -+void -+grub_backtrace_pointer (void *frame, unsigned int skip) -+{ -+ unsigned int x = 0; -+ struct fplr *fplr = (struct fplr *)frame; -+ -+ while (fplr) -+ { -+ const char *name = NULL; -+ char *addr = NULL; -+ -+ grub_dprintf("backtrace", "fp is %p next_fp is %p\n", -+ fplr, fplr->fp); -+ -+ if (x >= skip) -+ { -+ name = grub_get_symbol_by_addr (fplr->lr, 1); -+ if (name) -+ addr = grub_resolve_symbol (name); -+ grub_backtrace_print_address (fplr->lr); -+ -+ if (addr && addr != fplr->lr) -+ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, -+ (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr)); -+ else -+ grub_printf(" %s() %p \n", name ? name : "unknown", addr); -+ -+ } -+ -+ x += 1; -+ -+ if (fplr->fp < fplr || -+ (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME || -+ fplr->fp == fplr) -+ { -+ break; -+ } -+ fplr = fplr->fp; -+ } -+} -+ -+asm ("\t.global \"_text\"\n" -+ "_text:\n" -+ "\t.quad .text\n" -+ "\t.global \"_data\"\n" -+ "_data:\n" -+ "\t.quad .data\n" -+ ); -+ -+extern grub_uint64_t _text; -+extern grub_uint64_t _data; -+ -+void -+grub_backtrace_arch (unsigned int skip) -+{ -+ grub_printf ("Backtrace (.text %p .data %p):\n", -+ (void *)_text, (void *)_data); -+ skip += 1; -+ grub_backtrace_pointer(__builtin_frame_address(0), skip); -+} -diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c -new file mode 100644 -index 0000000000..4a82e865cc ---- /dev/null -+++ b/grub-core/kern/backtrace.c -@@ -0,0 +1,97 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static void -+grub_backtrace_print_address_default (void *addr) -+{ -+#ifndef GRUB_UTIL -+ grub_dl_t mod; -+ void *start_addr; -+ -+ FOR_DL_MODULES (mod) -+ { -+ grub_dl_segment_t segment; -+ for (segment = mod->segment; segment; segment = segment->next) -+ if (segment->addr <= addr && (grub_uint8_t *) segment->addr -+ + segment->size > (grub_uint8_t *) addr) -+ { -+ grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name, -+ segment->section, -+ (grub_size_t) -+ ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr)); -+ return; -+ } -+ } -+ -+ start_addr = grub_resolve_symbol ("_start"); -+ if (start_addr && start_addr < addr) -+ grub_printf ("kernel+%" PRIxGRUB_SIZE, -+ (grub_size_t) -+ ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr)); -+ else -+#endif -+ grub_printf ("%p", addr); -+} -+ -+static void -+grub_backtrace_pointer_default (void *frame __attribute__((__unused__)), -+ unsigned int skip __attribute__((__unused__))) -+{ -+ return; -+} -+ -+void -+grub_backtrace_pointer (void *frame, unsigned int skip) -+ __attribute__((__weak__, -+ __alias__(("grub_backtrace_pointer_default")))); -+ -+void -+grub_backtrace_print_address (void *addr) -+ __attribute__((__weak__, -+ __alias__(("grub_backtrace_print_address_default")))); -+ -+static void -+grub_backtrace_arch_default(unsigned int skip) -+{ -+ grub_backtrace_pointer(__builtin_frame_address(0), skip + 1); -+} -+ -+void grub_backtrace_arch (unsigned int skip) -+ __attribute__((__weak__, __alias__(("grub_backtrace_arch_default")))); -+ -+void grub_backtrace (unsigned int skip) -+{ -+ grub_backtrace_arch(skip + 1); -+} -+ -+void grub_debug_backtrace (const char * const debug, -+ unsigned int skip) -+{ -+ if (grub_debug_enabled (debug)) -+ grub_backtrace (skip + 1); -+} -diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c -index 7afb9e6f72..88d2077709 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -124,6 +124,50 @@ grub_dl_resolve_symbol (const char *name) - return 0; - } - -+void * -+grub_resolve_symbol (const char *name) -+{ -+ grub_symbol_t sym; -+ -+ sym = grub_dl_resolve_symbol (name); -+ if (sym) -+ return sym->addr; -+ return NULL; -+} -+ -+const char * -+grub_get_symbol_by_addr(const void *addr, int isfunc) -+{ -+ unsigned int i; -+ grub_symbol_t before = NULL, after = NULL; -+ for (i = 0; i < GRUB_SYMTAB_SIZE; i++) -+ { -+ grub_symbol_t sym; -+ for (sym = grub_symtab[i]; sym; sym = sym->next) -+ { -+ //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name); -+ if (sym->addr > addr) -+ { -+ if (!after || sym->addr > after->addr) -+ after = sym; -+ } -+ -+ if (isfunc != sym->isfunc) -+ continue; -+ if (sym->addr > addr) -+ continue; -+ -+ if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr)) -+ before = sym; -+ } -+ } -+ -+ if (before && addr < after->addr) -+ return before->name; -+ -+ return NULL; -+} -+ - /* Register a symbol with the name NAME and the address ADDR. */ - grub_err_t - grub_dl_register_symbol (const char *name, void *addr, int isfunc, -@@ -336,6 +380,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) - const char *str; - Elf_Word size, entsize; - -+ grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name); - for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); - i < e->e_shnum; - i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) -diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c -new file mode 100644 -index 0000000000..2413f9a57d ---- /dev/null -+++ b/grub-core/kern/i386/backtrace.c -@@ -0,0 +1,125 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MAX_STACK_FRAME 102400 -+ -+void -+grub_backtrace_pointer (void *frame, unsigned int skip) -+{ -+ void **ebp = (void **)frame; -+ unsigned long x = 0; -+ -+ while (ebp) -+ { -+ void **next_ebp = (void **)ebp[0]; -+ const char *name = NULL; -+ char *addr = NULL; -+ -+ grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp); -+ -+ if (x >= skip) -+ { -+ name = grub_get_symbol_by_addr (ebp[1], 1); -+ if (name) -+ addr = grub_resolve_symbol (name); -+ grub_backtrace_print_address (ebp[1]); -+ -+ if (addr && addr != ebp[1]) -+ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, -+ (char *)((char *)ebp[1] - addr)); -+ else -+ grub_printf(" %s() %p \n", name ? name : "unknown", addr); -+ -+#if 0 -+ grub_printf ("("); -+ for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++) -+ grub_printf ("%p,", arg); -+ grub_printf (")\n"); -+#endif -+ } -+ -+ x += 1; -+ -+ if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp) -+ { -+ //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp); -+ break; -+ } -+ ebp = next_ebp; -+ } -+} -+ -+#if defined (__x86_64__) -+asm ("\t.global \"_text\"\n" -+ "_text:\n" -+ "\t.quad .text\n" -+ "\t.global \"_data\"\n" -+ "_data:\n" -+ "\t.quad .data\n" -+ ); -+#elif defined(__i386__) -+asm ("\t.global \"_text\"\n" -+ "_text:\n" -+ "\t.long .text\n" -+ "\t.global \"_data\"\n" -+ "_data:\n" -+ "\t.long .data\n" -+ ); -+#else -+#warning I dunno... -+#endif -+ -+extern unsigned long _text; -+extern unsigned long _data; -+ -+#ifdef GRUB_UTIL -+#define EXT_C(x) x -+#endif -+ -+void -+grub_backtrace_arch (unsigned int skip) -+{ -+ grub_printf ("Backtrace (.text %p .data %p):\n", -+ (void *)_text, (void *)_data); -+ skip += 1; -+#if defined (__x86_64__) -+ asm volatile ("movq %%rbp, %%rdi\n" -+ "movq 0, %%rsi\n" -+ "movl %0, %%esi\n" -+ "call " EXT_C("grub_backtrace_pointer") -+ : -+ : "r" (skip)); -+#elif defined(__i386__) -+ asm volatile ("addl $8, %%esp\n" -+ "pushl %0\n" -+ "pushl %%ebp\n" -+ "call " EXT_C("grub_backtrace_pointer") -+ : -+ : "r" (skip)); -+#else -+ grub_backtrace_pointer(__builtin_frame_address(0), skip); -+#endif -+} -diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c -index 27bc68b8a5..b51d0abfa6 100644 ---- a/grub-core/kern/i386/pc/init.c -+++ b/grub-core/kern/i386/pc/init.c -@@ -153,7 +153,7 @@ compact_mem_regions (void) - } - - grub_addr_t grub_modbase; --extern grub_uint8_t _start[], _edata[]; -+extern grub_uint8_t _edata[]; - - /* Helper for grub_machine_init. */ - static int -@@ -217,7 +217,7 @@ grub_machine_init (void) - /* This has to happen before any BIOS calls. */ - grub_via_workaround_init (); - -- grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start); -+ grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start); - - /* Initialize the console as early as possible. */ - grub_console_init (); -diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index 0cd2a62723..937c1bc44c 100644 ---- a/grub-core/kern/ieee1275/init.c -+++ b/grub-core/kern/ieee1275/init.c -@@ -63,7 +63,6 @@ - #define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) - #endif - --extern char _start[]; - extern char _end[]; - - #ifdef __sparc__ -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index c60601b699..a432a6be54 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -1197,15 +1197,15 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) - - - /* Abort GRUB. This function does not return. */ --static void __attribute__ ((noreturn)) -+static inline void __attribute__ ((noreturn)) - grub_abort (void) - { --#ifndef GRUB_UTIL --#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU) -- grub_backtrace(); -+#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL) -+ grub_backtrace (1); -+#else -+ grub_printf ("\n"); - #endif --#endif -- grub_printf ("\nAborted."); -+ grub_printf ("Aborted."); - - #ifndef GRUB_UTIL - if (grub_term_inputs) -@@ -1232,6 +1232,7 @@ grub_fatal (const char *fmt, ...) - { - va_list ap; - -+ grub_printf ("\n"); - va_start (ap, fmt); - grub_vprintf (_(fmt), ap); - va_end (ap); -diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c -index c070afc621..d8c8377578 100644 ---- a/grub-core/kern/mm.c -+++ b/grub-core/kern/mm.c -@@ -97,13 +97,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r) - break; - - if (! *r) -- grub_fatal ("out of range pointer %p", ptr); -+ grub_fatal ("out of range pointer %p\n", ptr); - - *p = (grub_mm_header_t) ptr - 1; - if ((*p)->magic == GRUB_MM_FREE_MAGIC) -- grub_fatal ("double free at %p", *p); -+ grub_fatal ("double free at %p\n", *p); - if ((*p)->magic != GRUB_MM_ALLOC_MAGIC) -- grub_fatal ("alloc magic is broken at %p: %lx", *p, -+ grub_fatal ("alloc magic is broken at %p: %lx\n", *p, - (unsigned long) (*p)->magic); - } - -diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c -deleted file mode 100644 -index 1079b5380e..0000000000 ---- a/grub-core/lib/arm64/backtrace.c -+++ /dev/null -@@ -1,62 +0,0 @@ --/* -- * GRUB -- GRand Unified Bootloader -- * Copyright (C) 2009 Free Software Foundation, Inc. -- * -- * GRUB is free software: you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * GRUB is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with GRUB. If not, see . -- */ -- --#include --#include --#include --#include --#include --#include --#include -- --#define MAX_STACK_FRAME 102400 -- --void --grub_backtrace_pointer (int frame) --{ -- while (1) -- { -- void *lp = __builtin_return_address (frame); -- if (!lp) -- break; -- -- lp = __builtin_extract_return_addr (lp); -- -- grub_printf ("%p: ", lp); -- grub_backtrace_print_address (lp); -- grub_printf (" ("); -- for (i = 0; i < 2; i++) -- grub_printf ("%p,", ((void **)ptr) [i + 2]); -- grub_printf ("%p)\n", ((void **)ptr) [i + 2]); -- nptr = *(void **)ptr; -- if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME -- || nptr == ptr) -- { -- grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); -- break; -- } -- ptr = nptr; -- } --} -- --void --grub_backtrace (void) --{ -- grub_backtrace_pointer (1); --} -- -diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c -deleted file mode 100644 -index c67273db3a..0000000000 ---- a/grub-core/lib/i386/backtrace.c -+++ /dev/null -@@ -1,78 +0,0 @@ --/* -- * GRUB -- GRand Unified Bootloader -- * Copyright (C) 2009 Free Software Foundation, Inc. -- * -- * GRUB is free software: you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * GRUB is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with GRUB. If not, see . -- */ --#include --#ifdef GRUB_UTIL --#define REALLY_GRUB_UTIL GRUB_UTIL --#undef GRUB_UTIL --#endif -- --#include --#include -- --#ifdef REALLY_GRUB_UTIL --#define GRUB_UTIL REALLY_GRUB_UTIL --#undef REALLY_GRUB_UTIL --#endif -- --#include --#include --#include --#include --#include --#include -- --#define MAX_STACK_FRAME 102400 -- --void --grub_backtrace_pointer (void *ebp) --{ -- void *ptr, *nptr; -- unsigned i; -- -- ptr = ebp; -- while (1) -- { -- grub_printf ("%p: ", ptr); -- grub_backtrace_print_address (((void **) ptr)[1]); -- grub_printf (" ("); -- for (i = 0; i < 2; i++) -- grub_printf ("%p,", ((void **)ptr) [i + 2]); -- grub_printf ("%p)\n", ((void **)ptr) [i + 2]); -- nptr = *(void **)ptr; -- if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME -- || nptr == ptr) -- { -- grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); -- break; -- } -- ptr = nptr; -- } --} -- --void --grub_backtrace (void) --{ --#ifdef __x86_64__ -- asm volatile ("movq %%rbp, %%rdi\n" -- "callq *%%rax": :"a"(grub_backtrace_pointer)); --#else -- asm volatile ("movl %%ebp, %%eax\n" -- "calll *%%ecx": :"c"(grub_backtrace_pointer)); --#endif --} -- -diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h -index 395519762f..275cf85e2d 100644 ---- a/include/grub/backtrace.h -+++ b/include/grub/backtrace.h -@@ -19,8 +19,14 @@ - #ifndef GRUB_BACKTRACE_HEADER - #define GRUB_BACKTRACE_HEADER 1 - --void grub_backtrace (void); --void grub_backtrace_pointer (void *ptr); -+#include -+#include -+ -+void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug, -+ unsigned int skip); -+void EXPORT_FUNC(grub_backtrace) (unsigned int skip); -+void grub_backtrace_arch (unsigned int skip); -+void grub_backtrace_pointer (void *ptr, unsigned int skip); - void grub_backtrace_print_address (void *addr); - - #endif -diff --git a/include/grub/dl.h b/include/grub/dl.h -index 91933b85f2..2f76e6b043 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -259,6 +259,8 @@ grub_dl_is_persistent (grub_dl_t mod) - - #endif - -+void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); -+const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc); - grub_err_t grub_dl_register_symbol (const char *name, void *addr, - int isfunc, grub_dl_t mod); - -diff --git a/include/grub/kernel.h b/include/grub/kernel.h -index abbca5ea33..300a9766cd 100644 ---- a/include/grub/kernel.h -+++ b/include/grub/kernel.h -@@ -111,6 +111,9 @@ grub_addr_t grub_modules_get_end (void); - - #endif - -+void EXPORT_FUNC(start) (void); -+void EXPORT_FUNC(_start) (void); -+ - /* The start point of the C code. */ - void grub_main (void) __attribute__ ((noreturn)); - -diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S -index 9f8265315a..f3bc41f9d0 100644 ---- a/grub-core/kern/arm/efi/startup.S -+++ b/grub-core/kern/arm/efi/startup.S -@@ -23,6 +23,8 @@ - .file "startup.S" - .text - .arm -+ .globl start, _start -+FUNCTION(start) - FUNCTION(_start) - /* - * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0. -diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S -index 3946fe8e18..5679a1d00a 100644 ---- a/grub-core/kern/arm/startup.S -+++ b/grub-core/kern/arm/startup.S -@@ -48,6 +48,8 @@ - - .text - .arm -+ .globl start, _start -+FUNCTION(start) - FUNCTION(_start) - b codestart - -diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S -index 666a7ee3c9..41676bdb2b 100644 ---- a/grub-core/kern/arm64/efi/startup.S -+++ b/grub-core/kern/arm64/efi/startup.S -@@ -19,7 +19,9 @@ - #include - - .file "startup.S" -+ .globl start, _start - .text -+FUNCTION(start) - FUNCTION(_start) - /* - * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0. -diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S -index 0d89858d9b..939f182fc7 100644 ---- a/grub-core/kern/i386/qemu/startup.S -+++ b/grub-core/kern/i386/qemu/startup.S -@@ -24,7 +24,8 @@ - - .text - .code32 -- .globl _start -+ .globl start, _start -+start: - _start: - jmp codestart - -diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S -index d75c6d7cc7..8f2a593e52 100644 ---- a/grub-core/kern/ia64/efi/startup.S -+++ b/grub-core/kern/ia64/efi/startup.S -@@ -24,8 +24,9 @@ - .psr lsb - .lsb - -- .global _start -+ .global start, _start - .proc _start -+start: - _start: - alloc loc0=ar.pfs,2,4,0,0 - mov loc1=rp -diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S -index 03b916f053..701bf63abc 100644 ---- a/grub-core/kern/sparc64/ieee1275/crt0.S -+++ b/grub-core/kern/sparc64/ieee1275/crt0.S -@@ -22,7 +22,8 @@ - - .text - .align 4 -- .globl _start -+ .globl start, _start -+start: - _start: - ba codestart - mov %o4, %o0 -diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am -index 80e7a83edf..f512573c0d 100644 ---- a/grub-core/Makefile.am -+++ b/grub-core/Makefile.am -@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h - - include $(srcdir)/Makefile.core.am - -+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h diff --git a/0063-normal-don-t-draw-our-startup-message-if-debug-is-se.patch b/0063-normal-don-t-draw-our-startup-message-if-debug-is-se.patch new file mode 100644 index 0000000..a916299 --- /dev/null +++ b/0063-normal-don-t-draw-our-startup-message-if-debug-is-se.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 9 Nov 2017 15:58:52 -0500 +Subject: [PATCH] normal: don't draw our startup message if debug is set + +--- + grub-core/normal/main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 55558cc0b9..af9792c963 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -430,6 +430,9 @@ grub_normal_reader_init (int nested) + const char *msg_esc = _("ESC at any time exits."); + char *msg_formatted; + ++ if (grub_env_get ("debug") != NULL) ++ return 0; ++ + msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For " + "the first word, TAB lists possible command completions. Anywhere " + "else TAB lists possible device or file completions. %s"), diff --git a/0064-Work-around-some-minor-include-path-weirdnesses.patch b/0064-Work-around-some-minor-include-path-weirdnesses.patch new file mode 100644 index 0000000..c7ae8d0 --- /dev/null +++ b/0064-Work-around-some-minor-include-path-weirdnesses.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 16 Mar 2018 13:28:57 -0400 +Subject: [PATCH] Work around some minor include path weirdnesses + +Signed-off-by: Peter Jones +--- + include/grub/arm/efi/console.h | 24 ++++++++++++++++++++++++ + include/grub/arm64/efi/console.h | 24 ++++++++++++++++++++++++ + include/grub/i386/efi/console.h | 24 ++++++++++++++++++++++++ + include/grub/x86_64/efi/console.h | 24 ++++++++++++++++++++++++ + 4 files changed, 96 insertions(+) + create mode 100644 include/grub/arm/efi/console.h + create mode 100644 include/grub/arm64/efi/console.h + create mode 100644 include/grub/i386/efi/console.h + create mode 100644 include/grub/x86_64/efi/console.h + +diff --git a/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h +new file mode 100644 +index 0000000000..1592f6f76b +--- /dev/null ++++ b/include/grub/arm/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_ARM_EFI_CONSOLE_H ++#define GRUB_ARM_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_ARM_EFI_CONSOLE_H */ +diff --git a/include/grub/arm64/efi/console.h b/include/grub/arm64/efi/console.h +new file mode 100644 +index 0000000000..9568933938 +--- /dev/null ++++ b/include/grub/arm64/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_ARM64_EFI_CONSOLE_H ++#define GRUB_ARM64_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_ARM64_EFI_CONSOLE_H */ +diff --git a/include/grub/i386/efi/console.h b/include/grub/i386/efi/console.h +new file mode 100644 +index 0000000000..9231375cb0 +--- /dev/null ++++ b/include/grub/i386/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_I386_EFI_CONSOLE_H ++#define GRUB_I386_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_I386_EFI_CONSOLE_H */ +diff --git a/include/grub/x86_64/efi/console.h b/include/grub/x86_64/efi/console.h +new file mode 100644 +index 0000000000..dba9d8678d +--- /dev/null ++++ b/include/grub/x86_64/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_X86_64_EFI_CONSOLE_H ++#define GRUB_X86_64_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_X86_64_EFI_CONSOLE_H */ diff --git a/0064-normal-don-t-draw-our-startup-message-if-debug-is-se.patch b/0064-normal-don-t-draw-our-startup-message-if-debug-is-se.patch deleted file mode 100644 index a916299..0000000 --- a/0064-normal-don-t-draw-our-startup-message-if-debug-is-se.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 9 Nov 2017 15:58:52 -0500 -Subject: [PATCH] normal: don't draw our startup message if debug is set - ---- - grub-core/normal/main.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c -index 55558cc0b9..af9792c963 100644 ---- a/grub-core/normal/main.c -+++ b/grub-core/normal/main.c -@@ -430,6 +430,9 @@ grub_normal_reader_init (int nested) - const char *msg_esc = _("ESC at any time exits."); - char *msg_formatted; - -+ if (grub_env_get ("debug") != NULL) -+ return 0; -+ - msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For " - "the first word, TAB lists possible command completions. Anywhere " - "else TAB lists possible device or file completions. %s"), diff --git a/0065-Make-it-possible-to-enabled-build-id-sha1.patch b/0065-Make-it-possible-to-enabled-build-id-sha1.patch new file mode 100644 index 0000000..99d8055 --- /dev/null +++ b/0065-Make-it-possible-to-enabled-build-id-sha1.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 25 Jun 2015 15:41:06 -0400 +Subject: [PATCH] Make it possible to enabled --build-id=sha1 + +Signed-off-by: Peter Jones +--- + configure.ac | 8 ++++++++ + acinclude.m4 | 19 +++++++++++++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 0d0e6782a1..302300711f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1442,7 +1442,15 @@ grub_PROG_TARGET_CC + if test "x$TARGET_APPLE_LINKER" != x1 ; then + grub_PROG_OBJCOPY_ABSOLUTE + fi ++ ++AC_ARG_ENABLE([build-id], ++ [AS_HELP_STRING([--enable-build-id], ++ [ask the linker to supply build-id notes (default=no)])]) ++if test x$enable_build_id = xyes; then ++grub_PROG_LD_BUILD_ID_SHA1 ++else + grub_PROG_LD_BUILD_ID_NONE ++fi + if test "x$target_cpu" = xi386; then + if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then + if test ! -z "$TARGET_IMG_LDSCRIPT"; then +diff --git a/acinclude.m4 b/acinclude.m4 +index 6e14bb553c..21238fcfd0 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -136,6 +136,25 @@ if test "x$grub_cv_prog_ld_build_id_none" = xyes; then + fi + ]) + ++dnl Supply --build-id=sha1 to ld if building modules. ++dnl This suppresses warnings from ld on some systems ++AC_DEFUN([grub_PROG_LD_BUILD_ID_SHA1], ++[AC_MSG_CHECKING([whether linker accepts --build-id=sha1]) ++AC_CACHE_VAL(grub_cv_prog_ld_build_id_sha1, ++[save_LDFLAGS="$LDFLAGS" ++LDFLAGS="$LDFLAGS -Wl,--build-id=sha1" ++AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_prog_ld_build_id_sha1=yes], ++ [grub_cv_prog_ld_build_id_sha1=no]) ++LDFLAGS="$save_LDFLAGS" ++]) ++AC_MSG_RESULT([$grub_cv_prog_ld_build_id_sha1]) ++ ++if test "x$grub_cv_prog_ld_build_id_sha1" = xyes; then ++ TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,--build-id=sha1" ++fi ++]) ++ + dnl Check nm + AC_DEFUN([grub_PROG_NM_WORKS], + [AC_MSG_CHECKING([whether nm works]) diff --git a/0065-Work-around-some-minor-include-path-weirdnesses.patch b/0065-Work-around-some-minor-include-path-weirdnesses.patch deleted file mode 100644 index c7ae8d0..0000000 --- a/0065-Work-around-some-minor-include-path-weirdnesses.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 16 Mar 2018 13:28:57 -0400 -Subject: [PATCH] Work around some minor include path weirdnesses - -Signed-off-by: Peter Jones ---- - include/grub/arm/efi/console.h | 24 ++++++++++++++++++++++++ - include/grub/arm64/efi/console.h | 24 ++++++++++++++++++++++++ - include/grub/i386/efi/console.h | 24 ++++++++++++++++++++++++ - include/grub/x86_64/efi/console.h | 24 ++++++++++++++++++++++++ - 4 files changed, 96 insertions(+) - create mode 100644 include/grub/arm/efi/console.h - create mode 100644 include/grub/arm64/efi/console.h - create mode 100644 include/grub/i386/efi/console.h - create mode 100644 include/grub/x86_64/efi/console.h - -diff --git a/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h -new file mode 100644 -index 0000000000..1592f6f76b ---- /dev/null -+++ b/include/grub/arm/efi/console.h -@@ -0,0 +1,24 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_ARM_EFI_CONSOLE_H -+#define GRUB_ARM_EFI_CONSOLE_H -+ -+#include -+ -+#endif /* ! GRUB_ARM_EFI_CONSOLE_H */ -diff --git a/include/grub/arm64/efi/console.h b/include/grub/arm64/efi/console.h -new file mode 100644 -index 0000000000..9568933938 ---- /dev/null -+++ b/include/grub/arm64/efi/console.h -@@ -0,0 +1,24 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_ARM64_EFI_CONSOLE_H -+#define GRUB_ARM64_EFI_CONSOLE_H -+ -+#include -+ -+#endif /* ! GRUB_ARM64_EFI_CONSOLE_H */ -diff --git a/include/grub/i386/efi/console.h b/include/grub/i386/efi/console.h -new file mode 100644 -index 0000000000..9231375cb0 ---- /dev/null -+++ b/include/grub/i386/efi/console.h -@@ -0,0 +1,24 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_I386_EFI_CONSOLE_H -+#define GRUB_I386_EFI_CONSOLE_H -+ -+#include -+ -+#endif /* ! GRUB_I386_EFI_CONSOLE_H */ -diff --git a/include/grub/x86_64/efi/console.h b/include/grub/x86_64/efi/console.h -new file mode 100644 -index 0000000000..dba9d8678d ---- /dev/null -+++ b/include/grub/x86_64/efi/console.h -@@ -0,0 +1,24 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_X86_64_EFI_CONSOLE_H -+#define GRUB_X86_64_EFI_CONSOLE_H -+ -+#include -+ -+#endif /* ! GRUB_X86_64_EFI_CONSOLE_H */ diff --git a/0066-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch b/0066-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch new file mode 100644 index 0000000..7658e9b --- /dev/null +++ b/0066-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 28 Jun 2015 13:09:58 -0400 +Subject: [PATCH] Add grub_qdprintf() - grub_dprintf() without the file+line + number. + +This just makes copy+paste of our debug loading info easier. + +Signed-off-by: Peter Jones +--- + grub-core/kern/misc.c | 18 ++++++++++++++++++ + include/grub/misc.h | 2 ++ + 2 files changed, 20 insertions(+) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index a432a6be54..9a2fae6398 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -191,6 +191,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition, + } + } + ++void ++grub_qdprintf (const char *condition, const char *fmt, ...) ++{ ++ va_list args; ++ const char *debug = grub_env_get ("debug"); ++ ++ if (! debug) ++ return; ++ ++ if (grub_strword (debug, "all") || grub_strword (debug, condition)) ++ { ++ va_start (args, fmt); ++ grub_vprintf (fmt, args); ++ va_end (args); ++ grub_refresh (); ++ } ++} ++ + #define PREALLOC_SIZE 255 + + int +diff --git a/include/grub/misc.h b/include/grub/misc.h +index fd18e6320b..3adc4036e3 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -345,6 +345,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file, + const int line, + const char *condition, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5))); ++void EXPORT_FUNC(grub_qdprintf) (const char *condition, ++ const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 2, 3))); + int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); + int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) + __attribute__ ((format (GNU_PRINTF, 3, 4))); diff --git a/0066-Make-it-possible-to-enabled-build-id-sha1.patch b/0066-Make-it-possible-to-enabled-build-id-sha1.patch deleted file mode 100644 index 592635a..0000000 --- a/0066-Make-it-possible-to-enabled-build-id-sha1.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 25 Jun 2015 15:41:06 -0400 -Subject: [PATCH] Make it possible to enabled --build-id=sha1 - -Signed-off-by: Peter Jones ---- - configure.ac | 8 ++++++++ - acinclude.m4 | 19 +++++++++++++++++++ - 2 files changed, 27 insertions(+) - -diff --git a/configure.ac b/configure.ac -index 4f1676967e..b809c00784 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1443,7 +1443,15 @@ grub_PROG_TARGET_CC - if test "x$TARGET_APPLE_LINKER" != x1 ; then - grub_PROG_OBJCOPY_ABSOLUTE - fi -+ -+AC_ARG_ENABLE([build-id], -+ [AS_HELP_STRING([--enable-build-id], -+ [ask the linker to supply build-id notes (default=no)])]) -+if test x$enable_build_id = xyes; then -+grub_PROG_LD_BUILD_ID_SHA1 -+else - grub_PROG_LD_BUILD_ID_NONE -+fi - if test "x$target_cpu" = xi386; then - if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then - if test ! -z "$TARGET_IMG_LDSCRIPT"; then -diff --git a/acinclude.m4 b/acinclude.m4 -index 6e14bb553c..21238fcfd0 100644 ---- a/acinclude.m4 -+++ b/acinclude.m4 -@@ -136,6 +136,25 @@ if test "x$grub_cv_prog_ld_build_id_none" = xyes; then - fi - ]) - -+dnl Supply --build-id=sha1 to ld if building modules. -+dnl This suppresses warnings from ld on some systems -+AC_DEFUN([grub_PROG_LD_BUILD_ID_SHA1], -+[AC_MSG_CHECKING([whether linker accepts --build-id=sha1]) -+AC_CACHE_VAL(grub_cv_prog_ld_build_id_sha1, -+[save_LDFLAGS="$LDFLAGS" -+LDFLAGS="$LDFLAGS -Wl,--build-id=sha1" -+AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], -+ [grub_cv_prog_ld_build_id_sha1=yes], -+ [grub_cv_prog_ld_build_id_sha1=no]) -+LDFLAGS="$save_LDFLAGS" -+]) -+AC_MSG_RESULT([$grub_cv_prog_ld_build_id_sha1]) -+ -+if test "x$grub_cv_prog_ld_build_id_sha1" = xyes; then -+ TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,--build-id=sha1" -+fi -+]) -+ - dnl Check nm - AC_DEFUN([grub_PROG_NM_WORKS], - [AC_MSG_CHECKING([whether nm works]) diff --git a/0067-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch b/0067-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch deleted file mode 100644 index 7658e9b..0000000 --- a/0067-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Sun, 28 Jun 2015 13:09:58 -0400 -Subject: [PATCH] Add grub_qdprintf() - grub_dprintf() without the file+line - number. - -This just makes copy+paste of our debug loading info easier. - -Signed-off-by: Peter Jones ---- - grub-core/kern/misc.c | 18 ++++++++++++++++++ - include/grub/misc.h | 2 ++ - 2 files changed, 20 insertions(+) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index a432a6be54..9a2fae6398 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -191,6 +191,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition, - } - } - -+void -+grub_qdprintf (const char *condition, const char *fmt, ...) -+{ -+ va_list args; -+ const char *debug = grub_env_get ("debug"); -+ -+ if (! debug) -+ return; -+ -+ if (grub_strword (debug, "all") || grub_strword (debug, condition)) -+ { -+ va_start (args, fmt); -+ grub_vprintf (fmt, args); -+ va_end (args); -+ grub_refresh (); -+ } -+} -+ - #define PREALLOC_SIZE 255 - - int -diff --git a/include/grub/misc.h b/include/grub/misc.h -index fd18e6320b..3adc4036e3 100644 ---- a/include/grub/misc.h -+++ b/include/grub/misc.h -@@ -345,6 +345,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file, - const int line, - const char *condition, - const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5))); -+void EXPORT_FUNC(grub_qdprintf) (const char *condition, -+ const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 2, 3))); - int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); - int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) - __attribute__ ((format (GNU_PRINTF, 3, 4))); diff --git a/0067-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch b/0067-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch new file mode 100644 index 0000000..ccf34a5 --- /dev/null +++ b/0067-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch @@ -0,0 +1,178 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 25 Jun 2015 15:11:36 -0400 +Subject: [PATCH] Make a "gdb" dprintf that tells us load addresses. + +This makes a grub_dprintf() call during platform init and during module +loading that tells us the virtual addresses of the .text and .data +sections of grub-core/kernel.exec and any modules it loads. + +Specifically, it displays them in the gdb "add-symbol-file" syntax, with +the presumption that there's a variable $grubdir that reflects the path +to any such binaries. + +Signed-off-by: Peter Jones +--- + grub-core/kern/dl.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ + grub-core/kern/efi/efi.c | 4 ++-- + grub-core/kern/efi/init.c | 26 +++++++++++++++++++++++- + include/grub/efi/efi.h | 2 +- + 4 files changed, 78 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 88d2077709..9557254035 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -501,6 +501,23 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name) + return s; + return NULL; + } ++static long ++grub_dl_find_section_index (Elf_Ehdr *e, const char *name) ++{ ++ Elf_Shdr *s; ++ const char *str; ++ unsigned i; ++ ++ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + s->sh_offset; ++ ++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) ++ if (grub_strcmp (str + s->sh_name, name) == 0) ++ return (long)i; ++ return -1; ++} + + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. +@@ -653,6 +670,37 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + + return GRUB_ERR_NONE; + } ++static void ++grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) ++{ ++ void *text, *data = NULL; ++ long idx; ++ ++ idx = grub_dl_find_section_index (e, ".text"); ++ if (idx < 0) ++ return; ++ ++ text = grub_dl_get_section_addr (mod, idx); ++ if (!text) ++ return; ++ ++ idx = grub_dl_find_section_index (e, ".data"); ++ if (idx >= 0) ++ data = grub_dl_get_section_addr (mod, idx); ++ ++ if (data) ++ grub_qdprintf ("gdb", "add-symbol-file \\\n" ++ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " ++ "\\\n %p -s .data %p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, ++ mod->name, text, data); ++ else ++ grub_qdprintf ("gdb", "add-symbol-file \\\n" ++ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " ++ "\\\n%p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, ++ mod->name, text); ++} + + /* Load a module from core memory. */ + grub_dl_t +@@ -712,6 +760,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + grub_dprintf ("modules", "module name: %s\n", mod->name); + grub_dprintf ("modules", "init function: %p\n", mod->init); + ++ grub_dl_print_gdb_info (mod, e); ++ + if (grub_dl_add (mod)) + { + grub_dl_unload (mod); +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index ae9885edb8..d6a2fb5778 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -296,7 +296,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + /* Search the mods section from the PE32/PE32+ image. This code uses + a PE32 header, but should work with PE32+ as well. */ + grub_addr_t +-grub_efi_modules_addr (void) ++grub_efi_section_addr (const char *section_name) + { + grub_efi_loaded_image_t *image; + struct grub_pe32_header *header; +@@ -321,7 +321,7 @@ grub_efi_modules_addr (void) + i < coff_header->num_sections; + i++, section++) + { +- if (grub_strcmp (section->name, "mods") == 0) ++ if (grub_strcmp (section->name, section_name) == 0) + break; + } + +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 6d39bd3ad2..2d12e6188f 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -115,10 +115,33 @@ grub_efi_env_init (void) + grub_free (envblk_s.buf); + } + ++static void ++grub_efi_print_gdb_info (void) ++{ ++ grub_addr_t text; ++ grub_addr_t data; ++ ++ text = grub_efi_section_addr (".text"); ++ if (!text) ++ return; ++ ++ data = grub_efi_section_addr (".data"); ++ if (data) ++ grub_qdprintf ("gdb", ++ "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/" ++ "kernel.exec %p -s .data %p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text, (void *)data); ++ else ++ grub_qdprintf ("gdb", ++ "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/" ++ "kernel.exec %p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text); ++} ++ + void + grub_efi_init (void) + { +- grub_modbase = grub_efi_modules_addr (); ++ grub_modbase = grub_efi_section_addr ("mods"); + /* First of all, initialize the console so that GRUB can display + messages. */ + grub_console_init (); +@@ -142,6 +165,7 @@ grub_efi_init (void) + 0, 0, 0, NULL); + + grub_efi_env_init (); ++ grub_efi_print_gdb_info (); + grub_efidisk_init (); + } + +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 03f9a9d011..2e0691454b 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -138,7 +138,7 @@ grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); + grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); + #endif + +-grub_addr_t grub_efi_modules_addr (void); ++grub_addr_t grub_efi_section_addr (const char *section); + + void grub_efi_mm_init (void); + void grub_efi_mm_fini (void); diff --git a/0068-Fixup-for-newer-compiler.patch b/0068-Fixup-for-newer-compiler.patch new file mode 100644 index 0000000..ed23271 --- /dev/null +++ b/0068-Fixup-for-newer-compiler.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 10 May 2018 13:40:19 -0400 +Subject: [PATCH] Fixup for newer compiler + +--- + grub-core/fs/btrfs.c | 2 +- + include/grub/gpt_partition.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 2b21cbaa67..4cc86e9b79 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -218,7 +218,7 @@ struct grub_btrfs_inode + grub_uint64_t size; + grub_uint8_t dummy2[0x70]; + struct grub_btrfs_time mtime; +-} GRUB_PACKED; ++} GRUB_PACKED __attribute__ ((aligned(8))); + + struct grub_btrfs_extent_data + { +diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h +index 7a93f43291..8212697bf6 100644 +--- a/include/grub/gpt_partition.h ++++ b/include/grub/gpt_partition.h +@@ -76,7 +76,7 @@ struct grub_gpt_partentry + grub_uint64_t end; + grub_uint64_t attrib; + char name[72]; +-} GRUB_PACKED; ++} GRUB_PACKED __attribute__ ((aligned(8))); + + grub_err_t + grub_gpt_partition_map_iterate (grub_disk_t disk, diff --git a/0068-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch b/0068-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch deleted file mode 100644 index ccf34a5..0000000 --- a/0068-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch +++ /dev/null @@ -1,178 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 25 Jun 2015 15:11:36 -0400 -Subject: [PATCH] Make a "gdb" dprintf that tells us load addresses. - -This makes a grub_dprintf() call during platform init and during module -loading that tells us the virtual addresses of the .text and .data -sections of grub-core/kernel.exec and any modules it loads. - -Specifically, it displays them in the gdb "add-symbol-file" syntax, with -the presumption that there's a variable $grubdir that reflects the path -to any such binaries. - -Signed-off-by: Peter Jones ---- - grub-core/kern/dl.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ - grub-core/kern/efi/efi.c | 4 ++-- - grub-core/kern/efi/init.c | 26 +++++++++++++++++++++++- - include/grub/efi/efi.h | 2 +- - 4 files changed, 78 insertions(+), 4 deletions(-) - -diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c -index 88d2077709..9557254035 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -501,6 +501,23 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name) - return s; - return NULL; - } -+static long -+grub_dl_find_section_index (Elf_Ehdr *e, const char *name) -+{ -+ Elf_Shdr *s; -+ const char *str; -+ unsigned i; -+ -+ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); -+ str = (char *) e + s->sh_offset; -+ -+ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); -+ i < e->e_shnum; -+ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) -+ if (grub_strcmp (str + s->sh_name, name) == 0) -+ return (long)i; -+ return -1; -+} - - /* Me, Vladimir Serbinenko, hereby I add this module check as per new - GNU module policy. Note that this license check is informative only. -@@ -653,6 +670,37 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) - - return GRUB_ERR_NONE; - } -+static void -+grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) -+{ -+ void *text, *data = NULL; -+ long idx; -+ -+ idx = grub_dl_find_section_index (e, ".text"); -+ if (idx < 0) -+ return; -+ -+ text = grub_dl_get_section_addr (mod, idx); -+ if (!text) -+ return; -+ -+ idx = grub_dl_find_section_index (e, ".data"); -+ if (idx >= 0) -+ data = grub_dl_get_section_addr (mod, idx); -+ -+ if (data) -+ grub_qdprintf ("gdb", "add-symbol-file \\\n" -+ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " -+ "\\\n %p -s .data %p\n", -+ GRUB_TARGET_CPU, GRUB_PLATFORM, -+ mod->name, text, data); -+ else -+ grub_qdprintf ("gdb", "add-symbol-file \\\n" -+ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " -+ "\\\n%p\n", -+ GRUB_TARGET_CPU, GRUB_PLATFORM, -+ mod->name, text); -+} - - /* Load a module from core memory. */ - grub_dl_t -@@ -712,6 +760,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) - grub_dprintf ("modules", "module name: %s\n", mod->name); - grub_dprintf ("modules", "init function: %p\n", mod->init); - -+ grub_dl_print_gdb_info (mod, e); -+ - if (grub_dl_add (mod)) - { - grub_dl_unload (mod); -diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c -index ae9885edb8..d6a2fb5778 100644 ---- a/grub-core/kern/efi/efi.c -+++ b/grub-core/kern/efi/efi.c -@@ -296,7 +296,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, - /* Search the mods section from the PE32/PE32+ image. This code uses - a PE32 header, but should work with PE32+ as well. */ - grub_addr_t --grub_efi_modules_addr (void) -+grub_efi_section_addr (const char *section_name) - { - grub_efi_loaded_image_t *image; - struct grub_pe32_header *header; -@@ -321,7 +321,7 @@ grub_efi_modules_addr (void) - i < coff_header->num_sections; - i++, section++) - { -- if (grub_strcmp (section->name, "mods") == 0) -+ if (grub_strcmp (section->name, section_name) == 0) - break; - } - -diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c -index 6d39bd3ad2..2d12e6188f 100644 ---- a/grub-core/kern/efi/init.c -+++ b/grub-core/kern/efi/init.c -@@ -115,10 +115,33 @@ grub_efi_env_init (void) - grub_free (envblk_s.buf); - } - -+static void -+grub_efi_print_gdb_info (void) -+{ -+ grub_addr_t text; -+ grub_addr_t data; -+ -+ text = grub_efi_section_addr (".text"); -+ if (!text) -+ return; -+ -+ data = grub_efi_section_addr (".data"); -+ if (data) -+ grub_qdprintf ("gdb", -+ "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/" -+ "kernel.exec %p -s .data %p\n", -+ GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text, (void *)data); -+ else -+ grub_qdprintf ("gdb", -+ "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/" -+ "kernel.exec %p\n", -+ GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text); -+} -+ - void - grub_efi_init (void) - { -- grub_modbase = grub_efi_modules_addr (); -+ grub_modbase = grub_efi_section_addr ("mods"); - /* First of all, initialize the console so that GRUB can display - messages. */ - grub_console_init (); -@@ -142,6 +165,7 @@ grub_efi_init (void) - 0, 0, 0, NULL); - - grub_efi_env_init (); -+ grub_efi_print_gdb_info (); - grub_efidisk_init (); - } - -diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h -index 03f9a9d011..2e0691454b 100644 ---- a/include/grub/efi/efi.h -+++ b/include/grub/efi/efi.h -@@ -138,7 +138,7 @@ grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); - grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); - #endif - --grub_addr_t grub_efi_modules_addr (void); -+grub_addr_t grub_efi_section_addr (const char *section); - - void grub_efi_mm_init (void); - void grub_efi_mm_fini (void); diff --git a/0069-Don-t-attempt-to-export-the-start-and-_start-symbols.patch b/0069-Don-t-attempt-to-export-the-start-and-_start-symbols.patch new file mode 100644 index 0000000..9b78c00 --- /dev/null +++ b/0069-Don-t-attempt-to-export-the-start-and-_start-symbols.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Sat, 12 May 2018 11:29:07 +0200 +Subject: [PATCH] Don't attempt to export the start and _start symbols for + grub-emu + +Commit 318ee04aadc ("make better backtraces") reworked the backtrace logic +but the changes lead to the following build error on the grub-emu platform: + +grub_emu_lite-symlist.o:(.data+0xf08): undefined reference to `start' +collect2: error: ld returned 1 exit status +make[3]: *** [Makefile:25959: grub-emu-lite] Error 1 +make[3]: *** Waiting for unfinished jobs.... +cat kernel_syms.input | grep -v '^#' | sed -n \ + -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \ + -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \ + | sort -u >kernel_syms.lst + +The problem is that start and _start symbols are exported unconditionally, +but these aren't defined for grub-emu since is an emultaed platform so it +doesn't have a startup logic. Don't attempt to export those for grub-emu. + +Signed-off-by: Javier Martinez Canillas +--- + include/grub/kernel.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index 300a9766cd..55849777ea 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -111,8 +111,10 @@ grub_addr_t grub_modules_get_end (void); + + #endif + ++#if !defined(GRUB_MACHINE_EMU) + void EXPORT_FUNC(start) (void); + void EXPORT_FUNC(_start) (void); ++#endif + + /* The start point of the C code. */ + void grub_main (void) __attribute__ ((noreturn)); diff --git a/0069-Fixup-for-newer-compiler.patch b/0069-Fixup-for-newer-compiler.patch deleted file mode 100644 index ed23271..0000000 --- a/0069-Fixup-for-newer-compiler.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 10 May 2018 13:40:19 -0400 -Subject: [PATCH] Fixup for newer compiler - ---- - grub-core/fs/btrfs.c | 2 +- - include/grub/gpt_partition.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 2b21cbaa67..4cc86e9b79 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -218,7 +218,7 @@ struct grub_btrfs_inode - grub_uint64_t size; - grub_uint8_t dummy2[0x70]; - struct grub_btrfs_time mtime; --} GRUB_PACKED; -+} GRUB_PACKED __attribute__ ((aligned(8))); - - struct grub_btrfs_extent_data - { -diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h -index 7a93f43291..8212697bf6 100644 ---- a/include/grub/gpt_partition.h -+++ b/include/grub/gpt_partition.h -@@ -76,7 +76,7 @@ struct grub_gpt_partentry - grub_uint64_t end; - grub_uint64_t attrib; - char name[72]; --} GRUB_PACKED; -+} GRUB_PACKED __attribute__ ((aligned(8))); - - grub_err_t - grub_gpt_partition_map_iterate (grub_disk_t disk, diff --git a/0070-Don-t-attempt-to-export-the-start-and-_start-symbols.patch b/0070-Don-t-attempt-to-export-the-start-and-_start-symbols.patch deleted file mode 100644 index 9b78c00..0000000 --- a/0070-Don-t-attempt-to-export-the-start-and-_start-symbols.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Sat, 12 May 2018 11:29:07 +0200 -Subject: [PATCH] Don't attempt to export the start and _start symbols for - grub-emu - -Commit 318ee04aadc ("make better backtraces") reworked the backtrace logic -but the changes lead to the following build error on the grub-emu platform: - -grub_emu_lite-symlist.o:(.data+0xf08): undefined reference to `start' -collect2: error: ld returned 1 exit status -make[3]: *** [Makefile:25959: grub-emu-lite] Error 1 -make[3]: *** Waiting for unfinished jobs.... -cat kernel_syms.input | grep -v '^#' | sed -n \ - -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \ - -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \ - | sort -u >kernel_syms.lst - -The problem is that start and _start symbols are exported unconditionally, -but these aren't defined for grub-emu since is an emultaed platform so it -doesn't have a startup logic. Don't attempt to export those for grub-emu. - -Signed-off-by: Javier Martinez Canillas ---- - include/grub/kernel.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/include/grub/kernel.h b/include/grub/kernel.h -index 300a9766cd..55849777ea 100644 ---- a/include/grub/kernel.h -+++ b/include/grub/kernel.h -@@ -111,8 +111,10 @@ grub_addr_t grub_modules_get_end (void); - - #endif - -+#if !defined(GRUB_MACHINE_EMU) - void EXPORT_FUNC(start) (void); - void EXPORT_FUNC(_start) (void); -+#endif - - /* The start point of the C code. */ - void grub_main (void) __attribute__ ((noreturn)); diff --git a/0070-Fixup-for-newer-compiler.patch b/0070-Fixup-for-newer-compiler.patch new file mode 100644 index 0000000..167dca1 --- /dev/null +++ b/0070-Fixup-for-newer-compiler.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 10 May 2018 13:40:19 -0400 +Subject: [PATCH] Fixup for newer compiler + +--- + conf/Makefile.common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 191b1a70c6..5f0ef96985 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding + LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) + CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 + CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) +-STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx ++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes + + CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding + LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d diff --git a/0071-Add-support-for-non-Ethernet-network-cards.patch b/0071-Add-support-for-non-Ethernet-network-cards.patch new file mode 100644 index 0000000..fb44628 --- /dev/null +++ b/0071-Add-support-for-non-Ethernet-network-cards.patch @@ -0,0 +1,766 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrzej Kacprowski +Date: Wed, 10 Jul 2019 15:22:29 +0200 +Subject: [PATCH] Add support for non-Ethernet network cards + +This patch replaces fixed 6-byte link layer address with +up to 32-byte variable sized address. +This allows supporting Infiniband and Omni-Path fabric +which use 20-byte address, but other network card types +can also take advantage of this change. +The network card driver is responsible for replacing L2 +header provided by grub2 if needed. +This approach is compatible with UEFI network stack which +also allows up to 32-byte variable size link address. + +The BOOTP/DHCP packet format is limited to 16 byte client +hardware address, if link address is more that 16-bytes +then chaddr field in BOOTP it will be set to 0 as per rfc4390. + +Resolves: rhbz#1370642 + +Signed-off-by: Andrzej Kacprowski +[msalter: Fix max string calculation in grub_net_hwaddr_to_str] +Signed-off-by: Mark Salter +--- + grub-core/net/arp.c | 155 ++++++++++++++++++++++----------- + grub-core/net/bootp.c | 15 ++-- + grub-core/net/drivers/efi/efinet.c | 8 +- + grub-core/net/drivers/emu/emunet.c | 1 + + grub-core/net/drivers/i386/pc/pxe.c | 13 +-- + grub-core/net/drivers/ieee1275/ofnet.c | 2 + + grub-core/net/drivers/uboot/ubootnet.c | 1 + + grub-core/net/ethernet.c | 88 +++++++++---------- + grub-core/net/icmp6.c | 15 ++-- + grub-core/net/ip.c | 4 +- + grub-core/net/net.c | 50 ++++++----- + include/grub/net.h | 19 ++-- + 12 files changed, 219 insertions(+), 152 deletions(-) + +diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c +index 54306e3b16..67b409a8ac 100644 +--- a/grub-core/net/arp.c ++++ b/grub-core/net/arp.c +@@ -31,22 +31,12 @@ enum + ARP_REPLY = 2 + }; + +-enum +- { +- /* IANA ARP constant to define hardware type as ethernet. */ +- GRUB_NET_ARPHRD_ETHERNET = 1 +- }; +- +-struct arppkt { ++struct arphdr { + grub_uint16_t hrd; + grub_uint16_t pro; + grub_uint8_t hln; + grub_uint8_t pln; + grub_uint16_t op; +- grub_uint8_t sender_mac[6]; +- grub_uint32_t sender_ip; +- grub_uint8_t recv_mac[6]; +- grub_uint32_t recv_ip; + } GRUB_PACKED; + + static int have_pending; +@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr) + { + struct grub_net_buff nb; +- struct arppkt *arp_packet; ++ struct arphdr *arp_header; + grub_net_link_level_address_t target_mac_addr; + grub_err_t err; + int i; + grub_uint8_t *nbd; + grub_uint8_t arp_data[128]; ++ grub_uint8_t hln; ++ grub_uint8_t pln; ++ grub_uint8_t arp_packet_len; ++ grub_uint8_t *tmp_ptr; + + if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + return grub_error (GRUB_ERR_BUG, "unsupported address family"); +@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + grub_netbuff_clear (&nb); + grub_netbuff_reserve (&nb, 128); + +- err = grub_netbuff_push (&nb, sizeof (*arp_packet)); ++ hln = inf->card->default_address.len; ++ pln = sizeof (proto_addr->ipv4); ++ arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln); ++ ++ err = grub_netbuff_push (&nb, arp_packet_len); + if (err) + return err; + +- arp_packet = (struct arppkt *) nb.data; +- arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); +- arp_packet->hln = 6; +- arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); +- arp_packet->pln = 4; +- arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); +- /* Sender hardware address. */ +- grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6); +- arp_packet->sender_ip = inf->address.ipv4; +- grub_memset (arp_packet->recv_mac, 0, 6); +- arp_packet->recv_ip = proto_addr->ipv4; +- /* Target protocol address */ +- grub_memset (&target_mac_addr.mac, 0xff, 6); ++ arp_header = (struct arphdr *) nb.data; ++ arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type); ++ arp_header->hln = hln; ++ arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); ++ arp_header->pln = pln; ++ arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); ++ tmp_ptr = nb.data + sizeof (*arp_header); ++ ++ /* The source hardware address. */ ++ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ ++ grub_memcpy (tmp_ptr, &inf->address.ipv4, pln); ++ tmp_ptr += pln; ++ ++ /* The target hardware address. */ ++ grub_memset (tmp_ptr, 0, hln); ++ tmp_ptr += hln; ++ ++ /* The target protocol address */ ++ grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln); ++ tmp_ptr += pln; ++ ++ grub_memset (&target_mac_addr.mac, 0xff, hln); + + nbd = nb.data; + send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP); +@@ -114,28 +124,53 @@ grub_err_t + grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + grub_uint16_t *vlantag) + { +- struct arppkt *arp_packet = (struct arppkt *) nb->data; ++ struct arphdr *arp_header = (struct arphdr *) nb->data; + grub_net_network_level_address_t sender_addr, target_addr; + grub_net_link_level_address_t sender_mac_addr; + struct grub_net_network_level_interface *inf; ++ grub_uint16_t hw_type; ++ grub_uint8_t hln; ++ grub_uint8_t pln; ++ grub_uint8_t arp_packet_len; ++ grub_uint8_t *tmp_ptr; + +- if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) +- || arp_packet->pln != 4 || arp_packet->hln != 6 +- || nb->tail - nb->data < (int) sizeof (*arp_packet)) ++ hw_type = card->default_address.type; ++ hln = card->default_address.len; ++ pln = sizeof(sender_addr.ipv4); ++ arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln); ++ ++ if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) ++ || arp_header->hrd != grub_cpu_to_be16 (hw_type) ++ || arp_header->hln != hln || arp_header->pln != pln ++ || nb->tail - nb->data < (int) arp_packet_len) { + return GRUB_ERR_NONE; ++ } + ++ tmp_ptr = nb->data + sizeof (*arp_header); ++ ++ /* The source hardware address. */ ++ sender_mac_addr.type = hw_type; ++ sender_mac_addr.len = hln; ++ grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ + sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; ++ grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln); ++ tmp_ptr += pln; ++ ++ grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); ++ ++ /* The target hardware address. */ ++ tmp_ptr += hln; ++ ++ /* The target protocol address. */ + target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; +- sender_addr.ipv4 = arp_packet->sender_ip; +- target_addr.ipv4 = arp_packet->recv_ip; +- if (arp_packet->sender_ip == pending_req) ++ grub_memcpy(&target_addr.ipv4, tmp_ptr, pln); ++ ++ if (sender_addr.ipv4 == pending_req) + have_pending = 1; + +- sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac, +- sizeof (sender_mac_addr.mac)); +- grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); +- + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + /* Verify vlantag id */ +@@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + + /* Am I the protocol address target? */ + if (grub_net_addr_cmp (&inf->address, &target_addr) == 0 +- && arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) ++ && arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) + { + grub_net_link_level_address_t target; + struct grub_net_buff nb_reply; +- struct arppkt *arp_reply; ++ struct arphdr *arp_reply; + grub_uint8_t arp_data[128]; + grub_err_t err; + +@@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + grub_netbuff_clear (&nb_reply); + grub_netbuff_reserve (&nb_reply, 128); + +- err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet)); ++ err = grub_netbuff_push (&nb_reply, arp_packet_len); + if (err) + return err; + +- arp_reply = (struct arppkt *) nb_reply.data; ++ arp_reply = (struct arphdr *) nb_reply.data; + +- arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); ++ arp_reply->hrd = grub_cpu_to_be16 (hw_type); + arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); +- arp_reply->pln = 4; +- arp_reply->hln = 6; ++ arp_reply->pln = pln; ++ arp_reply->hln = hln; + arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY); +- arp_reply->sender_ip = arp_packet->recv_ip; +- arp_reply->recv_ip = arp_packet->sender_ip; +- arp_reply->hln = 6; +- +- target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (target.mac, arp_packet->sender_mac, 6); +- grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6); +- grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6); ++ ++ tmp_ptr = nb_reply.data + sizeof (*arp_reply); ++ ++ /* The source hardware address. */ ++ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ ++ grub_memcpy (tmp_ptr, &target_addr.ipv4, pln); ++ tmp_ptr += pln; ++ ++ /* The target hardware address. */ ++ grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The target protocol address */ ++ grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln); ++ tmp_ptr += pln; ++ ++ target.type = hw_type; ++ target.len = hln; ++ grub_memcpy (target.mac, sender_mac_addr.mac, hln); + + /* Change operation to REPLY and send packet */ + send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP); +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index e28fb6a09f..08b6b2b5d6 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -233,7 +233,6 @@ grub_net_configure_by_dhcp_ack (const char *name, + int is_def, char **device, char **path) + { + grub_net_network_level_address_t addr; +- grub_net_link_level_address_t hwaddr; + struct grub_net_network_level_interface *inter; + int mask = -1; + char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; +@@ -250,12 +249,8 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (path) + *path = 0; + +- grub_memcpy (hwaddr.mac, bp->mac_addr, +- bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len +- : sizeof (hwaddr.mac)); +- hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- +- inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags); ++ grub_dprintf("dhcp", "configuring dhcp for %s\n", name); ++ inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags); + if (!inter) + return 0; + +@@ -567,7 +562,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) + grub_memset (pack, 0, sizeof (*pack)); + pack->opcode = 1; + pack->hw_type = 1; +- pack->hw_len = 6; ++ pack->hw_len = iface->hwaddress.len > 16 ? 0 ++ : iface->hwaddress.len; ++ + err = grub_get_datetime (&date); + if (err || !grub_datetime2unixtime (&date, &t)) + { +@@ -580,7 +577,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) + else + pack->ident = iface->xid; + +- grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); ++ grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, pack->hw_len); + + grub_netbuff_push (nb, sizeof (*udph)); + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 173fb63153..a673bea807 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -279,6 +279,9 @@ grub_efinet_findcards (void) + /* This should not happen... Why? */ + continue; + ++ if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE) ++ continue; ++ + if (net->mode->state == GRUB_EFI_NETWORK_STOPPED + && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS) + continue; +@@ -315,10 +318,11 @@ grub_efinet_findcards (void) + card->name = grub_xasprintf ("efinet%d", i++); + card->driver = &efidriver; + card->flags = 0; +- card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ card->default_address.type = net->mode->if_type; ++ card->default_address.len = net->mode->hwaddr_size; + grub_memcpy (card->default_address.mac, + net->mode->current_address, +- sizeof (card->default_address.mac)); ++ net->mode->hwaddr_size); + card->efi_net = net; + card->efi_handle = *handle; + +diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c +index b194920861..5b6c5e16a6 100644 +--- a/grub-core/net/drivers/emu/emunet.c ++++ b/grub-core/net/drivers/emu/emunet.c +@@ -46,6 +46,7 @@ static struct grub_net_card emucard = + .mtu = 1500, + .default_address = { + .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET, ++ . len = 6, + {.mac = {0, 1, 2, 3, 4, 5}} + }, + .flags = 0 +diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c +index 3f4152d036..9f8fb4b6d2 100644 +--- a/grub-core/net/drivers/i386/pc/pxe.c ++++ b/grub-core/net/drivers/i386/pc/pxe.c +@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe) + grub_memset (ui, 0, sizeof (*ui)); + grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry); + ++ grub_pxe_card.default_address.len = 6; + grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr, +- sizeof (grub_pxe_card.default_address.mac)); +- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) ++ grub_pxe_card.default_address.len); ++ for (i = 0; i < grub_pxe_card.default_address.len; i++) + if (grub_pxe_card.default_address.mac[i] != 0) + break; +- if (i != sizeof (grub_pxe_card.default_address.mac)) ++ if (i != grub_pxe_card.default_address.len) + { +- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) ++ for (i = 0; i < grub_pxe_card.default_address.len; i++) + if (grub_pxe_card.default_address.mac[i] != 0xff) + break; + } +- if (i == sizeof (grub_pxe_card.default_address.mac)) ++ if (i == grub_pxe_card.default_address.len) + grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr, +- sizeof (grub_pxe_card.default_address.mac)); ++ grub_pxe_card.default_address.len); + grub_pxe_card.mtu = ui->mtu; + + grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c +index 3860b6f78d..bcb3f9ea02 100644 +--- a/grub-core/net/drivers/ieee1275/ofnet.c ++++ b/grub-core/net/drivers/ieee1275/ofnet.c +@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, + grub_uint16_t vlantag = 0; + + hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ hw_addr.len = 6; + + args = bootpath + grub_strlen (devpath) + 1; + do +@@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) + grub_memcpy (&lla.mac, pprop, 6); + + lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ lla.len = 6; + card->default_address = lla; + + card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; +diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c +index 056052e40d..22ebcbf211 100644 +--- a/grub-core/net/drivers/uboot/ubootnet.c ++++ b/grub-core/net/drivers/uboot/ubootnet.c +@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet) + + grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6); + card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ card->default_address.len = 6; + + card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; + card->txbuf = grub_zalloc (card->txbufsize); +diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c +index 4d7ceed6f9..9aae83a5eb 100644 +--- a/grub-core/net/ethernet.c ++++ b/grub-core/net/ethernet.c +@@ -29,13 +29,6 @@ + + #define LLCADDRMASK 0x7f + +-struct etherhdr +-{ +- grub_uint8_t dst[6]; +- grub_uint8_t src[6]; +- grub_uint16_t type; +-} GRUB_PACKED; +- + struct llchdr + { + grub_uint8_t dsap; +@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + grub_net_link_level_address_t target_addr, + grub_net_ethertype_t ethertype) + { +- struct etherhdr *eth; ++ grub_uint8_t *eth; + grub_err_t err; +- grub_uint8_t etherhdr_size; +- grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER; ++ grub_uint32_t vlantag = 0; ++ grub_uint8_t hw_addr_len = inf->card->default_address.len; ++ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; + +- etherhdr_size = sizeof (*eth); +- COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE); ++ /* Source and destination link addresses + ethertype + vlan tag */ ++ COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) < ++ GRUB_NET_MAX_LINK_HEADER_SIZE); + + /* Increase ethernet header in case of vlantag */ + if (inf->vlantag != 0) +@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + err = grub_netbuff_push (nb, etherhdr_size); + if (err) + return err; +- eth = (struct etherhdr *) nb->data; +- grub_memcpy (eth->dst, target_addr.mac, 6); +- grub_memcpy (eth->src, inf->hwaddress.mac, 6); ++ eth = nb->data; ++ grub_memcpy (eth, target_addr.mac, hw_addr_len); ++ eth += hw_addr_len; ++ grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len); ++ eth += hw_addr_len; ++ ++ /* Check if a vlan-tag is present. */ ++ if (vlantag != 0) ++ { ++ *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag); ++ eth += sizeof (vlantag); ++ } ++ ++ /* Write ethertype */ ++ *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype); + +- eth->type = grub_cpu_to_be16 (ethertype); + if (!inf->card->opened) + { + err = GRUB_ERR_NONE; +@@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + inf->card->opened = 1; + } + +- /* Check and add a vlan-tag if needed. */ +- if (inf->vlantag != 0) +- { +- /* Move eth type to the right */ +- grub_memcpy ((char *) nb->data + etherhdr_size - 2, +- (char *) nb->data + etherhdr_size - 6, 2); +- +- /* Add the tag in the middle */ +- grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2); +- grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2); +- } +- + return inf->card->driver->send (inf->card, nb); + } + +@@ -104,31 +98,40 @@ grub_err_t + grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + struct grub_net_card *card) + { +- struct etherhdr *eth; ++ grub_uint8_t *eth; + struct llchdr *llch; + struct snaphdr *snaph; + grub_net_ethertype_t type; + grub_net_link_level_address_t hwaddress; + grub_net_link_level_address_t src_hwaddress; + grub_err_t err; +- grub_uint8_t etherhdr_size = sizeof (*eth); ++ grub_uint8_t hw_addr_len = card->default_address.len; ++ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; + grub_uint16_t vlantag = 0; + ++ eth = nb->data; + +- /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */ +- /* longer than the original one. The vlantag id is extracted and the header */ +- /* is reseted to the original size. */ +- if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER) ++ hwaddress.type = card->default_address.type; ++ hwaddress.len = hw_addr_len; ++ grub_memcpy (hwaddress.mac, eth, hw_addr_len); ++ eth += hw_addr_len; ++ ++ src_hwaddress.type = card->default_address.type; ++ src_hwaddress.len = hw_addr_len; ++ grub_memcpy (src_hwaddress.mac, eth, hw_addr_len); ++ eth += hw_addr_len; ++ ++ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); ++ if (type == VLANTAG_IDENTIFIER) + { +- vlantag = grub_get_unaligned16 (nb->data + etherhdr_size); ++ /* Skip vlan tag */ ++ eth += 2; ++ vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); + etherhdr_size += 4; +- /* Move eth type to the original position */ +- grub_memcpy((char *) nb->data + etherhdr_size - 6, +- (char *) nb->data + etherhdr_size - 2, 2); ++ eth += 2; ++ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); + } + +- eth = (struct etherhdr *) nb->data; +- type = grub_be_to_cpu16 (eth->type); + err = grub_netbuff_pull (nb, etherhdr_size); + if (err) + return err; +@@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + } + } + +- hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac)); +- src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac)); +- + switch (type) + { + /* ARP packet. */ +diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c +index 2cbd95dce2..56a3ec5c8e 100644 +--- a/grub-core/net/icmp6.c ++++ b/grub-core/net/icmp6.c +@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } +@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } +@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + if (ohdr->type == OPTION_PREFIX && ohdr->len == 4) +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index ea5edf8f1f..a5896f6dc2 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -276,8 +276,8 @@ handle_dgram (struct grub_net_buff *nb, + if (inf->card == card + && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV + && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET +- && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, +- sizeof (inf->hwaddress.mac)) == 0) ++ && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, ++ bootp->hw_len) == 0 || bootp->hw_len == 0)) + { + grub_net_process_dhcp (nb, inf); + grub_netbuff_free (nb); +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 22f2689aae..a46f82362e 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -133,8 +133,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + << 48) + && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1)))) + { +- hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memset (hw_addr->mac, -1, 6); ++ hw_addr->type = inf->card->default_address.type; ++ hw_addr->len = inf->card->default_address.len; ++ grub_memset (hw_addr->mac, -1, hw_addr->len); + return GRUB_ERR_NONE; + } + +@@ -142,6 +143,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff)) + { + hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ hw_addr->len = inf->card->default_address.len; + hw_addr->mac[0] = 0x33; + hw_addr->mac[1] = 0x33; + hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff); +@@ -762,23 +764,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) + void + grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str) + { +- str[0] = 0; +- switch (addr->type) ++ char *ptr; ++ unsigned i; ++ int maxstr; ++ ++ if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) + { +- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: +- { +- char *ptr; +- unsigned i; +- for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++) +- { +- grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str), +- "%02x:", addr->mac[i] & 0xff); +- ptr += (sizeof ("XX:") - 1); +- } +- return; +- } ++ str[0] = 0; ++ grub_printf (_("Unsupported hw address type %d len %d\n"), ++ addr->type, addr->len); ++ return; ++ } ++ maxstr = addr->len * grub_strlen ("XX:"); ++ for (ptr = str, i = 0; i < addr->len; i++) ++ { ++ ptr += grub_snprintf (ptr, maxstr - (ptr - str), ++ "%02x:", addr->mac[i] & 0xff); + } +- grub_printf (_("Unsupported hw address type %d\n"), addr->type); + } + + int +@@ -789,13 +791,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + return -1; + if (a->type > b->type) + return +1; +- switch (a->type) ++ if (a->len < b->len) ++ return -1; ++ if (a->len > b->len) ++ return +1; ++ if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) + { +- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: +- return grub_memcmp (a->mac, b->mac, sizeof (a->mac)); ++ grub_printf (_("Unsupported hw address type %d len %d\n"), ++ a->type, a->len); ++ return + 1; + } +- grub_printf (_("Unsupported hw address type %d\n"), a->type); +- return 1; ++ return grub_memcmp (a->mac, b->mac, a->len); + } + + int +diff --git a/include/grub/net.h b/include/grub/net.h +index 8a05ec4fe7..af0404db7e 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -29,7 +29,8 @@ + + enum + { +- GRUB_NET_MAX_LINK_HEADER_SIZE = 64, ++ GRUB_NET_MAX_LINK_HEADER_SIZE = 96, ++ GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32, + GRUB_NET_UDP_HEADER_SIZE = 8, + GRUB_NET_TCP_HEADER_SIZE = 20, + GRUB_NET_OUR_IPV4_HEADER_SIZE = 20, +@@ -42,15 +43,17 @@ enum + + typedef enum grub_link_level_protocol_id + { +- GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET ++ /* IANA ARP constant to define hardware type. */ ++ GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1, + } grub_link_level_protocol_id_t; + + typedef struct grub_net_link_level_address + { + grub_link_level_protocol_id_t type; ++ grub_uint8_t len; + union + { +- grub_uint8_t mac[6]; ++ grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE]; + }; + } grub_net_link_level_address_t; + +@@ -566,11 +569,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a, + #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX") + + /* +- Currently suppoerted adresses: +- ethernet: XX:XX:XX:XX:XX:XX ++ Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE + */ +- +-#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX")) ++#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX")) + + void + grub_net_addr_to_str (const grub_net_network_level_address_t *target, diff --git a/0071-Fixup-for-newer-compiler.patch b/0071-Fixup-for-newer-compiler.patch deleted file mode 100644 index 167dca1..0000000 --- a/0071-Fixup-for-newer-compiler.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 10 May 2018 13:40:19 -0400 -Subject: [PATCH] Fixup for newer compiler - ---- - conf/Makefile.common | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/conf/Makefile.common b/conf/Makefile.common -index 191b1a70c6..5f0ef96985 100644 ---- a/conf/Makefile.common -+++ b/conf/Makefile.common -@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding - LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) - CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 - CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) --STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -+STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes - - CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding - LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d diff --git a/0072-Add-support-for-non-Ethernet-network-cards.patch b/0072-Add-support-for-non-Ethernet-network-cards.patch deleted file mode 100644 index fb44628..0000000 --- a/0072-Add-support-for-non-Ethernet-network-cards.patch +++ /dev/null @@ -1,766 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Andrzej Kacprowski -Date: Wed, 10 Jul 2019 15:22:29 +0200 -Subject: [PATCH] Add support for non-Ethernet network cards - -This patch replaces fixed 6-byte link layer address with -up to 32-byte variable sized address. -This allows supporting Infiniband and Omni-Path fabric -which use 20-byte address, but other network card types -can also take advantage of this change. -The network card driver is responsible for replacing L2 -header provided by grub2 if needed. -This approach is compatible with UEFI network stack which -also allows up to 32-byte variable size link address. - -The BOOTP/DHCP packet format is limited to 16 byte client -hardware address, if link address is more that 16-bytes -then chaddr field in BOOTP it will be set to 0 as per rfc4390. - -Resolves: rhbz#1370642 - -Signed-off-by: Andrzej Kacprowski -[msalter: Fix max string calculation in grub_net_hwaddr_to_str] -Signed-off-by: Mark Salter ---- - grub-core/net/arp.c | 155 ++++++++++++++++++++++----------- - grub-core/net/bootp.c | 15 ++-- - grub-core/net/drivers/efi/efinet.c | 8 +- - grub-core/net/drivers/emu/emunet.c | 1 + - grub-core/net/drivers/i386/pc/pxe.c | 13 +-- - grub-core/net/drivers/ieee1275/ofnet.c | 2 + - grub-core/net/drivers/uboot/ubootnet.c | 1 + - grub-core/net/ethernet.c | 88 +++++++++---------- - grub-core/net/icmp6.c | 15 ++-- - grub-core/net/ip.c | 4 +- - grub-core/net/net.c | 50 ++++++----- - include/grub/net.h | 19 ++-- - 12 files changed, 219 insertions(+), 152 deletions(-) - -diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c -index 54306e3b16..67b409a8ac 100644 ---- a/grub-core/net/arp.c -+++ b/grub-core/net/arp.c -@@ -31,22 +31,12 @@ enum - ARP_REPLY = 2 - }; - --enum -- { -- /* IANA ARP constant to define hardware type as ethernet. */ -- GRUB_NET_ARPHRD_ETHERNET = 1 -- }; -- --struct arppkt { -+struct arphdr { - grub_uint16_t hrd; - grub_uint16_t pro; - grub_uint8_t hln; - grub_uint8_t pln; - grub_uint16_t op; -- grub_uint8_t sender_mac[6]; -- grub_uint32_t sender_ip; -- grub_uint8_t recv_mac[6]; -- grub_uint32_t recv_ip; - } GRUB_PACKED; - - static int have_pending; -@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, - const grub_net_network_level_address_t *proto_addr) - { - struct grub_net_buff nb; -- struct arppkt *arp_packet; -+ struct arphdr *arp_header; - grub_net_link_level_address_t target_mac_addr; - grub_err_t err; - int i; - grub_uint8_t *nbd; - grub_uint8_t arp_data[128]; -+ grub_uint8_t hln; -+ grub_uint8_t pln; -+ grub_uint8_t arp_packet_len; -+ grub_uint8_t *tmp_ptr; - - if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) - return grub_error (GRUB_ERR_BUG, "unsupported address family"); -@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, - grub_netbuff_clear (&nb); - grub_netbuff_reserve (&nb, 128); - -- err = grub_netbuff_push (&nb, sizeof (*arp_packet)); -+ hln = inf->card->default_address.len; -+ pln = sizeof (proto_addr->ipv4); -+ arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln); -+ -+ err = grub_netbuff_push (&nb, arp_packet_len); - if (err) - return err; - -- arp_packet = (struct arppkt *) nb.data; -- arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); -- arp_packet->hln = 6; -- arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); -- arp_packet->pln = 4; -- arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); -- /* Sender hardware address. */ -- grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6); -- arp_packet->sender_ip = inf->address.ipv4; -- grub_memset (arp_packet->recv_mac, 0, 6); -- arp_packet->recv_ip = proto_addr->ipv4; -- /* Target protocol address */ -- grub_memset (&target_mac_addr.mac, 0xff, 6); -+ arp_header = (struct arphdr *) nb.data; -+ arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type); -+ arp_header->hln = hln; -+ arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); -+ arp_header->pln = pln; -+ arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); -+ tmp_ptr = nb.data + sizeof (*arp_header); -+ -+ /* The source hardware address. */ -+ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); -+ tmp_ptr += hln; -+ -+ /* The source protocol address. */ -+ grub_memcpy (tmp_ptr, &inf->address.ipv4, pln); -+ tmp_ptr += pln; -+ -+ /* The target hardware address. */ -+ grub_memset (tmp_ptr, 0, hln); -+ tmp_ptr += hln; -+ -+ /* The target protocol address */ -+ grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln); -+ tmp_ptr += pln; -+ -+ grub_memset (&target_mac_addr.mac, 0xff, hln); - - nbd = nb.data; - send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP); -@@ -114,28 +124,53 @@ grub_err_t - grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, - grub_uint16_t *vlantag) - { -- struct arppkt *arp_packet = (struct arppkt *) nb->data; -+ struct arphdr *arp_header = (struct arphdr *) nb->data; - grub_net_network_level_address_t sender_addr, target_addr; - grub_net_link_level_address_t sender_mac_addr; - struct grub_net_network_level_interface *inf; -+ grub_uint16_t hw_type; -+ grub_uint8_t hln; -+ grub_uint8_t pln; -+ grub_uint8_t arp_packet_len; -+ grub_uint8_t *tmp_ptr; - -- if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) -- || arp_packet->pln != 4 || arp_packet->hln != 6 -- || nb->tail - nb->data < (int) sizeof (*arp_packet)) -+ hw_type = card->default_address.type; -+ hln = card->default_address.len; -+ pln = sizeof(sender_addr.ipv4); -+ arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln); -+ -+ if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) -+ || arp_header->hrd != grub_cpu_to_be16 (hw_type) -+ || arp_header->hln != hln || arp_header->pln != pln -+ || nb->tail - nb->data < (int) arp_packet_len) { - return GRUB_ERR_NONE; -+ } - -+ tmp_ptr = nb->data + sizeof (*arp_header); -+ -+ /* The source hardware address. */ -+ sender_mac_addr.type = hw_type; -+ sender_mac_addr.len = hln; -+ grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln); -+ tmp_ptr += hln; -+ -+ /* The source protocol address. */ - sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; -+ grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln); -+ tmp_ptr += pln; -+ -+ grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); -+ -+ /* The target hardware address. */ -+ tmp_ptr += hln; -+ -+ /* The target protocol address. */ - target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; -- sender_addr.ipv4 = arp_packet->sender_ip; -- target_addr.ipv4 = arp_packet->recv_ip; -- if (arp_packet->sender_ip == pending_req) -+ grub_memcpy(&target_addr.ipv4, tmp_ptr, pln); -+ -+ if (sender_addr.ipv4 == pending_req) - have_pending = 1; - -- sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac, -- sizeof (sender_mac_addr.mac)); -- grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); -- - FOR_NET_NETWORK_LEVEL_INTERFACES (inf) - { - /* Verify vlantag id */ -@@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, - - /* Am I the protocol address target? */ - if (grub_net_addr_cmp (&inf->address, &target_addr) == 0 -- && arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) -+ && arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) - { - grub_net_link_level_address_t target; - struct grub_net_buff nb_reply; -- struct arppkt *arp_reply; -+ struct arphdr *arp_reply; - grub_uint8_t arp_data[128]; - grub_err_t err; - -@@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, - grub_netbuff_clear (&nb_reply); - grub_netbuff_reserve (&nb_reply, 128); - -- err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet)); -+ err = grub_netbuff_push (&nb_reply, arp_packet_len); - if (err) - return err; - -- arp_reply = (struct arppkt *) nb_reply.data; -+ arp_reply = (struct arphdr *) nb_reply.data; - -- arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); -+ arp_reply->hrd = grub_cpu_to_be16 (hw_type); - arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); -- arp_reply->pln = 4; -- arp_reply->hln = 6; -+ arp_reply->pln = pln; -+ arp_reply->hln = hln; - arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY); -- arp_reply->sender_ip = arp_packet->recv_ip; -- arp_reply->recv_ip = arp_packet->sender_ip; -- arp_reply->hln = 6; -- -- target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (target.mac, arp_packet->sender_mac, 6); -- grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6); -- grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6); -+ -+ tmp_ptr = nb_reply.data + sizeof (*arp_reply); -+ -+ /* The source hardware address. */ -+ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); -+ tmp_ptr += hln; -+ -+ /* The source protocol address. */ -+ grub_memcpy (tmp_ptr, &target_addr.ipv4, pln); -+ tmp_ptr += pln; -+ -+ /* The target hardware address. */ -+ grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln); -+ tmp_ptr += hln; -+ -+ /* The target protocol address */ -+ grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln); -+ tmp_ptr += pln; -+ -+ target.type = hw_type; -+ target.len = hln; -+ grub_memcpy (target.mac, sender_mac_addr.mac, hln); - - /* Change operation to REPLY and send packet */ - send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP); -diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c -index e28fb6a09f..08b6b2b5d6 100644 ---- a/grub-core/net/bootp.c -+++ b/grub-core/net/bootp.c -@@ -233,7 +233,6 @@ grub_net_configure_by_dhcp_ack (const char *name, - int is_def, char **device, char **path) - { - grub_net_network_level_address_t addr; -- grub_net_link_level_address_t hwaddr; - struct grub_net_network_level_interface *inter; - int mask = -1; - char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; -@@ -250,12 +249,8 @@ grub_net_configure_by_dhcp_ack (const char *name, - if (path) - *path = 0; - -- grub_memcpy (hwaddr.mac, bp->mac_addr, -- bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len -- : sizeof (hwaddr.mac)); -- hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- -- inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags); -+ grub_dprintf("dhcp", "configuring dhcp for %s\n", name); -+ inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags); - if (!inter) - return 0; - -@@ -567,7 +562,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) - grub_memset (pack, 0, sizeof (*pack)); - pack->opcode = 1; - pack->hw_type = 1; -- pack->hw_len = 6; -+ pack->hw_len = iface->hwaddress.len > 16 ? 0 -+ : iface->hwaddress.len; -+ - err = grub_get_datetime (&date); - if (err || !grub_datetime2unixtime (&date, &t)) - { -@@ -580,7 +577,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) - else - pack->ident = iface->xid; - -- grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); -+ grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, pack->hw_len); - - grub_netbuff_push (nb, sizeof (*udph)); - -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index 173fb63153..a673bea807 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -279,6 +279,9 @@ grub_efinet_findcards (void) - /* This should not happen... Why? */ - continue; - -+ if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE) -+ continue; -+ - if (net->mode->state == GRUB_EFI_NETWORK_STOPPED - && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS) - continue; -@@ -315,10 +318,11 @@ grub_efinet_findcards (void) - card->name = grub_xasprintf ("efinet%d", i++); - card->driver = &efidriver; - card->flags = 0; -- card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -+ card->default_address.type = net->mode->if_type; -+ card->default_address.len = net->mode->hwaddr_size; - grub_memcpy (card->default_address.mac, - net->mode->current_address, -- sizeof (card->default_address.mac)); -+ net->mode->hwaddr_size); - card->efi_net = net; - card->efi_handle = *handle; - -diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c -index b194920861..5b6c5e16a6 100644 ---- a/grub-core/net/drivers/emu/emunet.c -+++ b/grub-core/net/drivers/emu/emunet.c -@@ -46,6 +46,7 @@ static struct grub_net_card emucard = - .mtu = 1500, - .default_address = { - .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET, -+ . len = 6, - {.mac = {0, 1, 2, 3, 4, 5}} - }, - .flags = 0 -diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c -index 3f4152d036..9f8fb4b6d2 100644 ---- a/grub-core/net/drivers/i386/pc/pxe.c -+++ b/grub-core/net/drivers/i386/pc/pxe.c -@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe) - grub_memset (ui, 0, sizeof (*ui)); - grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry); - -+ grub_pxe_card.default_address.len = 6; - grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr, -- sizeof (grub_pxe_card.default_address.mac)); -- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) -+ grub_pxe_card.default_address.len); -+ for (i = 0; i < grub_pxe_card.default_address.len; i++) - if (grub_pxe_card.default_address.mac[i] != 0) - break; -- if (i != sizeof (grub_pxe_card.default_address.mac)) -+ if (i != grub_pxe_card.default_address.len) - { -- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) -+ for (i = 0; i < grub_pxe_card.default_address.len; i++) - if (grub_pxe_card.default_address.mac[i] != 0xff) - break; - } -- if (i == sizeof (grub_pxe_card.default_address.mac)) -+ if (i == grub_pxe_card.default_address.len) - grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr, -- sizeof (grub_pxe_card.default_address.mac)); -+ grub_pxe_card.default_address.len); - grub_pxe_card.mtu = ui->mtu; - - grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c -index 3860b6f78d..bcb3f9ea02 100644 ---- a/grub-core/net/drivers/ieee1275/ofnet.c -+++ b/grub-core/net/drivers/ieee1275/ofnet.c -@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, - grub_uint16_t vlantag = 0; - - hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -+ hw_addr.len = 6; - - args = bootpath + grub_strlen (devpath) + 1; - do -@@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) - grub_memcpy (&lla.mac, pprop, 6); - - lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -+ lla.len = 6; - card->default_address = lla; - - card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; -diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c -index 056052e40d..22ebcbf211 100644 ---- a/grub-core/net/drivers/uboot/ubootnet.c -+++ b/grub-core/net/drivers/uboot/ubootnet.c -@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet) - - grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6); - card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -+ card->default_address.len = 6; - - card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; - card->txbuf = grub_zalloc (card->txbufsize); -diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c -index 4d7ceed6f9..9aae83a5eb 100644 ---- a/grub-core/net/ethernet.c -+++ b/grub-core/net/ethernet.c -@@ -29,13 +29,6 @@ - - #define LLCADDRMASK 0x7f - --struct etherhdr --{ -- grub_uint8_t dst[6]; -- grub_uint8_t src[6]; -- grub_uint16_t type; --} GRUB_PACKED; -- - struct llchdr - { - grub_uint8_t dsap; -@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, - grub_net_link_level_address_t target_addr, - grub_net_ethertype_t ethertype) - { -- struct etherhdr *eth; -+ grub_uint8_t *eth; - grub_err_t err; -- grub_uint8_t etherhdr_size; -- grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER; -+ grub_uint32_t vlantag = 0; -+ grub_uint8_t hw_addr_len = inf->card->default_address.len; -+ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; - -- etherhdr_size = sizeof (*eth); -- COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE); -+ /* Source and destination link addresses + ethertype + vlan tag */ -+ COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) < -+ GRUB_NET_MAX_LINK_HEADER_SIZE); - - /* Increase ethernet header in case of vlantag */ - if (inf->vlantag != 0) -@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, - err = grub_netbuff_push (nb, etherhdr_size); - if (err) - return err; -- eth = (struct etherhdr *) nb->data; -- grub_memcpy (eth->dst, target_addr.mac, 6); -- grub_memcpy (eth->src, inf->hwaddress.mac, 6); -+ eth = nb->data; -+ grub_memcpy (eth, target_addr.mac, hw_addr_len); -+ eth += hw_addr_len; -+ grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len); -+ eth += hw_addr_len; -+ -+ /* Check if a vlan-tag is present. */ -+ if (vlantag != 0) -+ { -+ *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag); -+ eth += sizeof (vlantag); -+ } -+ -+ /* Write ethertype */ -+ *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype); - -- eth->type = grub_cpu_to_be16 (ethertype); - if (!inf->card->opened) - { - err = GRUB_ERR_NONE; -@@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, - inf->card->opened = 1; - } - -- /* Check and add a vlan-tag if needed. */ -- if (inf->vlantag != 0) -- { -- /* Move eth type to the right */ -- grub_memcpy ((char *) nb->data + etherhdr_size - 2, -- (char *) nb->data + etherhdr_size - 6, 2); -- -- /* Add the tag in the middle */ -- grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2); -- grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2); -- } -- - return inf->card->driver->send (inf->card, nb); - } - -@@ -104,31 +98,40 @@ grub_err_t - grub_net_recv_ethernet_packet (struct grub_net_buff *nb, - struct grub_net_card *card) - { -- struct etherhdr *eth; -+ grub_uint8_t *eth; - struct llchdr *llch; - struct snaphdr *snaph; - grub_net_ethertype_t type; - grub_net_link_level_address_t hwaddress; - grub_net_link_level_address_t src_hwaddress; - grub_err_t err; -- grub_uint8_t etherhdr_size = sizeof (*eth); -+ grub_uint8_t hw_addr_len = card->default_address.len; -+ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; - grub_uint16_t vlantag = 0; - -+ eth = nb->data; - -- /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */ -- /* longer than the original one. The vlantag id is extracted and the header */ -- /* is reseted to the original size. */ -- if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER) -+ hwaddress.type = card->default_address.type; -+ hwaddress.len = hw_addr_len; -+ grub_memcpy (hwaddress.mac, eth, hw_addr_len); -+ eth += hw_addr_len; -+ -+ src_hwaddress.type = card->default_address.type; -+ src_hwaddress.len = hw_addr_len; -+ grub_memcpy (src_hwaddress.mac, eth, hw_addr_len); -+ eth += hw_addr_len; -+ -+ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); -+ if (type == VLANTAG_IDENTIFIER) - { -- vlantag = grub_get_unaligned16 (nb->data + etherhdr_size); -+ /* Skip vlan tag */ -+ eth += 2; -+ vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); - etherhdr_size += 4; -- /* Move eth type to the original position */ -- grub_memcpy((char *) nb->data + etherhdr_size - 6, -- (char *) nb->data + etherhdr_size - 2, 2); -+ eth += 2; -+ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); - } - -- eth = (struct etherhdr *) nb->data; -- type = grub_be_to_cpu16 (eth->type); - err = grub_netbuff_pull (nb, etherhdr_size); - if (err) - return err; -@@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb, - } - } - -- hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac)); -- src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac)); -- - switch (type) - { - /* ARP packet. */ -diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c -index 2cbd95dce2..56a3ec5c8e 100644 ---- a/grub-core/net/icmp6.c -+++ b/grub-core/net/icmp6.c -@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, - && ohdr->len == 1) - { - grub_net_link_level_address_t ll_address; -- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); -+ ll_address.type = card->default_address.type; -+ ll_address.len = card->default_address.len; -+ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); - grub_net_link_layer_add_address (card, source, &ll_address, 0); - } - } -@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, - && ohdr->len == 1) - { - grub_net_link_level_address_t ll_address; -- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); -+ ll_address.type = card->default_address.type; -+ ll_address.len = card->default_address.len; -+ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); - grub_net_link_layer_add_address (card, source, &ll_address, 0); - } - } -@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, - && ohdr->len == 1) - { - grub_net_link_level_address_t ll_address; -- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); -+ ll_address.type = card->default_address.type; -+ ll_address.len = card->default_address.len; -+ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); - grub_net_link_layer_add_address (card, source, &ll_address, 0); - } - if (ohdr->type == OPTION_PREFIX && ohdr->len == 4) -diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c -index ea5edf8f1f..a5896f6dc2 100644 ---- a/grub-core/net/ip.c -+++ b/grub-core/net/ip.c -@@ -276,8 +276,8 @@ handle_dgram (struct grub_net_buff *nb, - if (inf->card == card - && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV - && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET -- && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, -- sizeof (inf->hwaddress.mac)) == 0) -+ && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, -+ bootp->hw_len) == 0 || bootp->hw_len == 0)) - { - grub_net_process_dhcp (nb, inf); - grub_netbuff_free (nb); -diff --git a/grub-core/net/net.c b/grub-core/net/net.c -index 22f2689aae..a46f82362e 100644 ---- a/grub-core/net/net.c -+++ b/grub-core/net/net.c -@@ -133,8 +133,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, - << 48) - && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1)))) - { -- hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memset (hw_addr->mac, -1, 6); -+ hw_addr->type = inf->card->default_address.type; -+ hw_addr->len = inf->card->default_address.len; -+ grub_memset (hw_addr->mac, -1, hw_addr->len); - return GRUB_ERR_NONE; - } - -@@ -142,6 +143,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, - && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff)) - { - hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -+ hw_addr->len = inf->card->default_address.len; - hw_addr->mac[0] = 0x33; - hw_addr->mac[1] = 0x33; - hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff); -@@ -762,23 +764,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) - void - grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str) - { -- str[0] = 0; -- switch (addr->type) -+ char *ptr; -+ unsigned i; -+ int maxstr; -+ -+ if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) - { -- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: -- { -- char *ptr; -- unsigned i; -- for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++) -- { -- grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str), -- "%02x:", addr->mac[i] & 0xff); -- ptr += (sizeof ("XX:") - 1); -- } -- return; -- } -+ str[0] = 0; -+ grub_printf (_("Unsupported hw address type %d len %d\n"), -+ addr->type, addr->len); -+ return; -+ } -+ maxstr = addr->len * grub_strlen ("XX:"); -+ for (ptr = str, i = 0; i < addr->len; i++) -+ { -+ ptr += grub_snprintf (ptr, maxstr - (ptr - str), -+ "%02x:", addr->mac[i] & 0xff); - } -- grub_printf (_("Unsupported hw address type %d\n"), addr->type); - } - - int -@@ -789,13 +791,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, - return -1; - if (a->type > b->type) - return +1; -- switch (a->type) -+ if (a->len < b->len) -+ return -1; -+ if (a->len > b->len) -+ return +1; -+ if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) - { -- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: -- return grub_memcmp (a->mac, b->mac, sizeof (a->mac)); -+ grub_printf (_("Unsupported hw address type %d len %d\n"), -+ a->type, a->len); -+ return + 1; - } -- grub_printf (_("Unsupported hw address type %d\n"), a->type); -- return 1; -+ return grub_memcmp (a->mac, b->mac, a->len); - } - - int -diff --git a/include/grub/net.h b/include/grub/net.h -index 8a05ec4fe7..af0404db7e 100644 ---- a/include/grub/net.h -+++ b/include/grub/net.h -@@ -29,7 +29,8 @@ - - enum - { -- GRUB_NET_MAX_LINK_HEADER_SIZE = 64, -+ GRUB_NET_MAX_LINK_HEADER_SIZE = 96, -+ GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32, - GRUB_NET_UDP_HEADER_SIZE = 8, - GRUB_NET_TCP_HEADER_SIZE = 20, - GRUB_NET_OUR_IPV4_HEADER_SIZE = 20, -@@ -42,15 +43,17 @@ enum - - typedef enum grub_link_level_protocol_id - { -- GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET -+ /* IANA ARP constant to define hardware type. */ -+ GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1, - } grub_link_level_protocol_id_t; - - typedef struct grub_net_link_level_address - { - grub_link_level_protocol_id_t type; -+ grub_uint8_t len; - union - { -- grub_uint8_t mac[6]; -+ grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE]; - }; - } grub_net_link_level_address_t; - -@@ -566,11 +569,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a, - #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX") - - /* -- Currently suppoerted adresses: -- ethernet: XX:XX:XX:XX:XX:XX -+ Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE - */ -- --#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX")) -+#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\ -+ "XX:XX:XX:XX:XX:XX:XX:XX:"\ -+ "XX:XX:XX:XX:XX:XX:XX:XX:"\ -+ "XX:XX:XX:XX:XX:XX:XX:XX:"\ -+ "XX:XX:XX:XX:XX:XX:XX:XX")) - - void - grub_net_addr_to_str (const grub_net_network_level_address_t *target, diff --git a/0072-net-read-bracketed-ipv6-addrs-and-port-numbers.patch b/0072-net-read-bracketed-ipv6-addrs-and-port-numbers.patch new file mode 100644 index 0000000..307e33c --- /dev/null +++ b/0072-net-read-bracketed-ipv6-addrs-and-port-numbers.patch @@ -0,0 +1,270 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aaron Miller +Date: Fri, 29 Jul 2016 17:41:38 +0800 +Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers + +Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses +to be recognized with brackets around them, which is required to specify a port +number + +Signed-off-by: Aaron Miller +[pjones: various bug fixes] +Signed-off-by: Peter Jones +--- + grub-core/net/http.c | 25 ++++++++++++--- + grub-core/net/net.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++--- + grub-core/net/tftp.c | 8 +++-- + include/grub/net.h | 1 + + 4 files changed, 109 insertions(+), 12 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index b616cf40b1..12a2632ea5 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + nb2 = grub_netbuff_alloc (data->chunk_rem); + if (!nb2) + return grub_errno; +- grub_netbuff_put (nb2, data->chunk_rem); ++ err = grub_netbuff_put (nb2, data->chunk_rem); ++ if (err) ++ return grub_errno; + grub_memcpy (nb2->data, nb->data, data->chunk_rem); + if (file->device->net->packs.count >= 20) + { +@@ -312,12 +314,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + int i; + struct grub_net_buff *nb; + grub_err_t err; ++ char* server = file->device->net->server; ++ int port = file->device->net->port; + + nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE + + sizeof ("GET ") - 1 + + grub_strlen (data->filename) + + sizeof (" HTTP/1.1\r\nHost: ") - 1 +- + grub_strlen (file->device->net->server) ++ + grub_strlen (server) + sizeof (":XXXXXXXXXX") + + sizeof ("\r\nUser-Agent: " PACKAGE_STRING + "\r\n") - 1 + + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX" +@@ -356,7 +360,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + sizeof (" HTTP/1.1\r\nHost: ") - 1); + + ptr = nb->tail; +- err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); ++ err = grub_netbuff_put (nb, grub_strlen (server)); + if (err) + { + grub_netbuff_free (nb); +@@ -365,6 +369,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + grub_memcpy (ptr, file->device->net->server, + grub_strlen (file->device->net->server)); + ++ if (port) ++ { ++ ptr = nb->tail; ++ grub_snprintf ((char *) ptr, ++ sizeof (":XXXXXXXXXX"), ++ ":%d", ++ port); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, + sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") +@@ -390,8 +403,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + grub_netbuff_put (nb, 2); + grub_memcpy (ptr, "\r\n", 2); + +- data->sock = grub_net_tcp_open (file->device->net->server, +- HTTP_PORT, http_receive, ++ grub_dprintf ("http", "opening path %s on host %s TCP port %d\n", ++ data->filename, server, port ? port : HTTP_PORT); ++ data->sock = grub_net_tcp_open (server, ++ port ? port : HTTP_PORT, http_receive, + http_err, NULL, + file); + if (!data->sock) +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index a46f82362e..0ce5e675ed 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -444,6 +444,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + grub_uint16_t newip[8]; + const char *ptr = val; + int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') ++ { ++ bracketed = 1; ++ ptr++; ++ } + + if (ptr[0] == ':' && ptr[1] != ':') + return 0; +@@ -482,6 +489,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); + } + grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') ++ ptr++; + if (rest) + *rest = ptr; + return 1; +@@ -1343,8 +1352,10 @@ grub_net_open_real (const char *name) + { + grub_net_app_level_t proto; + const char *protname, *server; ++ char *host; + grub_size_t protnamelen; + int try; ++ int port = 0; + + if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) + { +@@ -1382,6 +1393,72 @@ grub_net_open_real (const char *name) + return NULL; + } + ++ char* port_start; ++ /* ipv6 or port specified? */ ++ if ((port_start = grub_strchr (server, ':'))) ++ { ++ char* ipv6_begin; ++ if((ipv6_begin = grub_strchr (server, '['))) ++ { ++ char* ipv6_end = grub_strchr (server, ']'); ++ if(!ipv6_end) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("mismatched [ in address")); ++ return NULL; ++ } ++ /* port number after bracketed ipv6 addr */ ++ if(ipv6_end[1] == ':') ++ { ++ port = grub_strtoul (ipv6_end + 2, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ } ++ host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1); ++ } ++ else ++ { ++ if (grub_strchr (port_start + 1, ':')) ++ { ++ int iplen = grub_strlen (server); ++ /* bracket bare ipv6 addrs */ ++ host = grub_malloc (iplen + 3); ++ if(!host) ++ { ++ return NULL; ++ } ++ host[0] = '['; ++ grub_memcpy (host + 1, server, iplen); ++ host[iplen + 1] = ']'; ++ host[iplen + 2] = '\0'; ++ } ++ else ++ { ++ /* hostname:port or ipv4:port */ ++ port = grub_strtol (port_start + 1, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ host = grub_strndup (server, port_start - server); ++ } ++ } ++ } ++ else ++ { ++ host = grub_strdup (server); ++ } ++ if (!host) ++ { ++ return NULL; ++ } ++ + for (try = 0; try < 2; try++) + { + FOR_NET_APP_LEVEL (proto) +@@ -1391,14 +1468,13 @@ grub_net_open_real (const char *name) + { + grub_net_t ret = grub_zalloc (sizeof (*ret)); + if (!ret) +- return NULL; +- ret->protocol = proto; +- ret->server = grub_strdup (server); +- if (!ret->server) + { +- grub_free (ret); ++ grub_free (host); + return NULL; + } ++ ret->protocol = proto; ++ ret->port = port; ++ ret->server = host; + ret->fs = &grub_net_fs; + return ret; + } +@@ -1473,6 +1549,7 @@ grub_net_open_real (const char *name) + grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), + name); + ++ grub_free (host); + return NULL; + } + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 4ab2f5c735..d54b13f09f 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename) + grub_err_t err; + grub_uint8_t *nbd; + grub_net_network_level_address_t addr; ++ int port = file->device->net->port; + + data = grub_zalloc (sizeof (*data)); + if (!data) +@@ -362,14 +363,17 @@ tftp_open (struct grub_file *file, const char *filename) + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { +- grub_dprintf("tftp", "Address resolution failed: %d\n", err); ++ grub_dprintf ("tftp", "Address resolution failed: %d\n", err); ++ grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n", ++ (unsigned long long)data->file_size, ++ (unsigned long long)data->block_size); + grub_free (data); + return err; + } + + grub_dprintf("tftp", "opening connection\n"); + data->sock = grub_net_udp_open (addr, +- TFTP_SERVER_PORT, tftp_receive, ++ port ? port : TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { +diff --git a/include/grub/net.h b/include/grub/net.h +index af0404db7e..d55d505a03 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -273,6 +273,7 @@ typedef struct grub_net + { + char *server; + char *name; ++ int port; + grub_net_app_level_t protocol; + grub_net_packets_t packs; + grub_off_t offset; diff --git a/0073-bootp-New-net_bootp6-command.patch b/0073-bootp-New-net_bootp6-command.patch new file mode 100644 index 0000000..bef3acd --- /dev/null +++ b/0073-bootp-New-net_bootp6-command.patch @@ -0,0 +1,1368 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 10 Jul 2019 15:42:36 +0200 +Subject: [PATCH] bootp: New net_bootp6 command + +Implement new net_bootp6 command for IPv6 network auto configuration via the +DHCPv6 protocol (RFC3315). + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +[pjones: Put back our code to add a local route] +Signed-off-by: Peter Jones +--- + grub-core/net/bootp.c | 1059 ++++++++++++++++++++++++++++++------ + grub-core/net/drivers/efi/efinet.c | 20 +- + grub-core/net/ip.c | 39 ++ + include/grub/efi/api.h | 2 +- + include/grub/net.h | 91 ++-- + 5 files changed, 1002 insertions(+), 209 deletions(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 08b6b2b5d6..fe93b80f1c 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -24,6 +24,98 @@ + #include + #include + #include ++#include ++#include ++ ++static int ++dissect_url (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} + + struct grub_dhcp_discover_options + { +@@ -604,6 +696,584 @@ out: + return err; + } + ++/* The default netbuff size for sending DHCPv6 packets which should be ++ large enough to hold the information */ ++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512 ++ ++struct grub_dhcp6_options ++{ ++ grub_uint8_t *client_duid; ++ grub_uint16_t client_duid_len; ++ grub_uint8_t *server_duid; ++ grub_uint16_t server_duid_len; ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_net_network_level_address_t *ia_addr; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_net_network_level_address_t *dns_server_addrs; ++ grub_uint16_t num_dns_server; ++ char *boot_file_proto; ++ char *boot_file_server_ip; ++ char *boot_file_path; ++}; ++ ++typedef struct grub_dhcp6_options *grub_dhcp6_options_t; ++ ++struct grub_dhcp6_session ++{ ++ struct grub_dhcp6_session *next; ++ struct grub_dhcp6_session **prev; ++ grub_uint32_t iaid; ++ grub_uint32_t transaction_id:24; ++ grub_uint64_t start_time; ++ struct grub_net_dhcp6_option_duid_ll duid; ++ struct grub_net_network_level_interface *iface; ++ ++ /* The associated dhcpv6 options */ ++ grub_dhcp6_options_t adv; ++ grub_dhcp6_options_t reply; ++}; ++ ++typedef struct grub_dhcp6_session *grub_dhcp6_session_t; ++ ++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data); ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, ++ dhcp6_option_hook_fn hook, void *hook_data); ++ ++static void ++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data; ++ ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ if (code == GRUB_NET_DHCP6_OPTION_IAADDR) ++ { ++ const struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ ++ if (len < sizeof (*iaaddr)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len); ++ return; ++ } ++ if (!dhcp6->ia_addr) ++ { ++ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr)); ++ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr); ++ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8); ++ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime); ++ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime); ++ } ++ } ++} ++ ++static void ++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data; ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ switch (code) ++ { ++ case GRUB_NET_DHCP6_OPTION_CLIENTID: ++ ++ if (dhcp6->client_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len); ++ break; ++ } ++ dhcp6->client_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->client_duid, opt->data, len); ++ dhcp6->client_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_SERVERID: ++ ++ if (dhcp6->server_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len); ++ break; ++ } ++ dhcp6->server_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->server_duid, opt->data, len); ++ dhcp6->server_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_IA_NA: ++ { ++ const struct grub_net_dhcp6_option_iana *ia_na; ++ grub_uint16_t data_len; ++ ++ if (dhcp6->iaid || len < sizeof (*ia_na)) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len); ++ break; ++ } ++ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data; ++ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid); ++ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1); ++ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2); ++ ++ data_len = len - sizeof (*ia_na); ++ if (data_len) ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6); ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS: ++ { ++ const grub_uint8_t *po; ++ grub_uint16_t ln; ++ grub_net_network_level_address_t *la; ++ ++ if (!len || len & 0xf) ++ { ++ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n"); ++ break; ++ } ++ dhcp6->num_dns_server = ln = len >> 4; ++ dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la)); ++ ++ for (po = opt->data; ln > 0; po += 0x10, la++, ln--) ++ { ++ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ la->ipv6[0] = grub_get_unaligned64 (po); ++ la->ipv6[1] = grub_get_unaligned64 (po + 8); ++ la->option = DNS_OPTION_PREFER_IPV6; ++ } ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL: ++ dissect_url ((const char *)opt->data, ++ &dhcp6->boot_file_proto, ++ &dhcp6->boot_file_server_ip, ++ &dhcp6->boot_file_path); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data) ++{ ++ while (size) ++ { ++ grub_uint16_t code, len; ++ ++ if (size < sizeof (*opt)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size); ++ break; ++ } ++ size -= sizeof (*opt); ++ len = grub_be_to_cpu16 (opt->len); ++ code = grub_be_to_cpu16 (opt->code); ++ if (size < len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code); ++ break; ++ } ++ if (!len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code); ++ break; ++ } ++ else ++ { ++ if (hook) ++ hook (opt, hook_data); ++ size -= len; ++ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt)); ++ } ++ } ++} ++ ++static grub_dhcp6_options_t ++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size) ++{ ++ grub_dhcp6_options_t options; ++ ++ if (size < sizeof (*v6h)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return NULL; ++ } ++ ++ options = grub_zalloc (sizeof(*options)); ++ if (!options) ++ return NULL; ++ ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options, ++ size - sizeof (*v6h), parse_dhcp6_option, options); ++ ++ return options; ++} ++ ++static void ++grub_dhcp6_options_free (grub_dhcp6_options_t options) ++{ ++ if (options->client_duid) ++ grub_free (options->client_duid); ++ if (options->server_duid) ++ grub_free (options->server_duid); ++ if (options->ia_addr) ++ grub_free (options->ia_addr); ++ if (options->dns_server_addrs) ++ grub_free (options->dns_server_addrs); ++ if (options->boot_file_proto) ++ grub_free (options->boot_file_proto); ++ if (options->boot_file_server_ip) ++ grub_free (options->boot_file_server_ip); ++ if (options->boot_file_path) ++ grub_free (options->boot_file_path); ++ ++ grub_free (options); ++} ++ ++static grub_dhcp6_session_t grub_dhcp6_sessions; ++#define FOR_DHCP6_SESSIONS_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE (var, next, grub_dhcp6_sessions) ++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions) ++ ++static void ++grub_net_configure_by_dhcp6_info (const char *name, ++ struct grub_net_card *card, ++ grub_dhcp6_options_t dhcp6, ++ int is_def, ++ int flags, ++ struct grub_net_network_level_interface **ret_inf) ++{ ++ grub_net_network_level_netaddress_t netaddr; ++ struct grub_net_network_level_interface *inf; ++ ++ if (dhcp6->ia_addr) ++ { ++ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags); ++ ++ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0]; ++ netaddr.ipv6.base[1] = 0; ++ netaddr.ipv6.masksize = 64; ++ grub_net_add_route (name, netaddr, inf); ++ ++ if (ret_inf) ++ *ret_inf = inf; ++ } ++ ++ if (dhcp6->dns_server_addrs) ++ { ++ grub_uint16_t i; ++ ++ for (i = 0; i < dhcp6->num_dns_server; ++i) ++ grub_net_add_dns_server (dhcp6->dns_server_addrs + i); ++ } ++ ++ if (dhcp6->boot_file_path) ++ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path, ++ grub_strlen (dhcp6->boot_file_path)); ++ ++ if (is_def && dhcp6->boot_file_server_ip) ++ { ++ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++} ++ ++static void ++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface, ++ grub_uint32_t iaid) ++{ ++ grub_dhcp6_session_t se; ++ struct grub_datetime date; ++ grub_err_t err; ++ grub_int32_t t = 0; ++ ++ se = grub_malloc (sizeof (*se)); ++ ++ err = grub_get_datetime (&date); ++ if (err || !grub_datetime2unixtime (&date, &t)) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ t = 0; ++ } ++ ++ se->iface = iface; ++ se->iaid = iaid; ++ se->transaction_id = t; ++ se->start_time = grub_get_time_ms (); ++ se->duid.type = grub_cpu_to_be16_compile_time (3) ; ++ se->duid.hw_type = grub_cpu_to_be16_compile_time (1); ++ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr)); ++ se->adv = NULL; ++ se->reply = NULL; ++ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se)); ++} ++ ++static void ++grub_dhcp6_session_remove (grub_dhcp6_session_t se) ++{ ++ grub_list_remove (GRUB_AS_LIST (se)); ++ if (se->adv) ++ grub_dhcp6_options_free (se->adv); ++ if (se->reply) ++ grub_dhcp6_options_free (se->reply); ++ grub_free (se); ++} ++ ++static void ++grub_dhcp6_session_remove_all (void) ++{ ++ grub_dhcp6_session_t se, next; ++ ++ FOR_DHCP6_SESSIONS_SAFE (se, next) ++ { ++ grub_dhcp6_session_remove (se); ++ } ++ grub_dhcp6_sessions = NULL; ++} ++ ++static grub_err_t ++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se) ++{ ++ char *name; ++ ++ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name); ++ if (!name) ++ return grub_errno; ++ ++ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0); ++ grub_free (name); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_dhcp6_session_send_request (grub_dhcp6_session_t se) ++{ ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ struct udphdr *udph; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ grub_uint64_t elapsed; ++ struct grub_net_network_level_interface *inf = se->iface; ++ grub_dhcp6_options_t dhcp6 = se->adv; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast); ++ if (err) ++ return err; ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ return grub_errno; ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len); ++ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len); ++ ++ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID); ++ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len); ++ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len); ++ ++ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ if (dhcp6->ia_addr) ++ { ++ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ if (dhcp6->ia_addr) ++ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt)); ++ ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid); ++ ++ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1); ++ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2); ++ ++ if (dhcp6->ia_addr) ++ { ++ opt = (struct grub_net_dhcp6_option *)ia_na->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr)); ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]); ++ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]); ++ ++ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime); ++ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime); ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO); ++ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)); ++ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ ++ /* the time is expressed in hundredths of a second */ ++ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0); ++ ++ if (elapsed > 0xffff) ++ elapsed = 0xffff; ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed)); ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *) nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_REQUEST; ++ v6h->transaction_id = se->transaction_id; ++ ++ err = grub_netbuff_push (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &inf->address, ++ &multicast); ++ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, ++ GRUB_NET_IP_UDP); ++ ++ grub_netbuff_free (nb); ++ ++ return err; ++} ++ ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size, ++ int is_def, ++ char **device, char **path) ++{ ++ struct grub_net_network_level_interface *inf; ++ grub_dhcp6_options_t dhcp6; ++ int mask = -1; ++ ++ dhcp6 = grub_dhcp6_options_get (v6h, size); ++ if (!dhcp6) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ ++ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf); ++ ++ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip) ++ { ++ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip); ++ grub_print_error (); ++ } ++ if (path && dhcp6->boot_file_path) ++ { ++ *path = grub_strdup (dhcp6->boot_file_path); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ ++ grub_dhcp6_options_free (dhcp6); ++ ++ if (inf) ++ grub_net_add_ipv6_local (inf, mask); ++ ++ return inf; ++} ++ + /* + * This is called directly from net/ip.c:handle_dgram(), because those + * BOOTP/DHCP packets are a bit special due to their improper +@@ -672,6 +1342,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb, + } + } + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card __attribute__ ((unused))) ++{ ++ const struct grub_net_dhcp6_packet *v6h; ++ grub_dhcp6_session_t se; ++ grub_size_t size; ++ grub_dhcp6_options_t options; ++ ++ v6h = (const struct grub_net_dhcp6_packet *) nb->data; ++ size = nb->tail - nb->data; ++ ++ options = grub_dhcp6_options_get (v6h, size); ++ if (!options) ++ return grub_errno; ++ ++ if (!options->client_duid || !options->server_duid || !options->ia_addr) ++ { ++ grub_dhcp6_options_free (options); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet"); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ if (se->transaction_id == v6h->transaction_id && ++ grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 && ++ se->iaid == options->iaid) ++ break; ++ } ++ ++ if (!se) ++ { ++ grub_dprintf ("bootp", "DHCPv6 session not found\n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE) ++ { ++ if (se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->adv = options; ++ return grub_dhcp6_session_send_request (se); ++ } ++ else if (v6h->message_type == GRUB_NET_DHCP6_REPLY) ++ { ++ if (!se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->reply = options; ++ grub_dhcp6_session_configure_network (se); ++ grub_dhcp6_session_remove (se); ++ return GRUB_ERR_NONE; ++ } ++ else ++ { ++ grub_dhcp6_options_free (options); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +@@ -897,180 +1638,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), + return err; + } + +-static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; +- +-struct grub_net_network_level_interface * +-grub_net_configure_by_dhcpv6_ack (const char *name, +- struct grub_net_card *card, +- grub_net_interface_flags_t flags +- __attribute__((__unused__)), +- const grub_net_link_level_address_t *hwaddr, +- const struct grub_net_dhcpv6_packet *packet, +- int is_def, char **device, char **path) ++static grub_err_t ++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) + { +- struct grub_net_network_level_interface *inter = NULL; +- struct grub_net_network_level_address addr; +- int mask = -1; ++ struct grub_net_card *card; ++ grub_uint32_t iaid = 0; ++ int interval; ++ grub_err_t err; ++ grub_dhcp6_session_t se; + +- if (!device || !path) +- return NULL; ++ err = GRUB_ERR_NONE; + +- *device = 0; +- *path = 0; ++ FOR_NET_CARDS (card) ++ { ++ struct grub_net_network_level_interface *iface; + +- grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n", +- hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2], +- hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]); ++ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) ++ continue; + +- if (is_def) +- grub_net_default_server = 0; ++ iface = grub_net_ipv6_get_link_local (card, &card->default_address); ++ if (!iface) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } + +- if (is_def && !grub_net_default_server && packet) ++ grub_dhcp6_session_add (iface, iaid++); ++ } ++ ++ for (interval = 200; interval < 10000; interval *= 2) + { +- const grub_uint8_t *options = packet->dhcp_options; +- unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet); +- unsigned int i; +- +- for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); ) +- { +- grub_uint16_t num, len; +- grub_net_dhcpv6_option_t *opt = +- (grub_net_dhcpv6_option_t *)(options + i); +- +- num = grub_be_to_cpu16(opt->option_num); +- len = grub_be_to_cpu16(opt->option_len); +- +- grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len); +- +- if (len == 0) +- break; +- +- if (len + i > 1024) +- break; +- +- if (num == GRUB_NET_DHCP6_BOOTFILE_URL) +- { +- char *scheme, *userinfo, *host, *file; +- char *tmp; +- int hostlen; +- int port; +- int rc = extract_url_info ((const char *)opt->option_data, +- (grub_size_t)len, +- &scheme, &userinfo, &host, &port, +- &file); +- if (rc < 0) +- continue; +- +- /* right now this only handles tftp. */ +- if (grub_strcmp("tftp", scheme)) +- { +- grub_free (scheme); +- grub_free (userinfo); +- grub_free (host); +- grub_free (file); +- continue; +- } +- grub_free (userinfo); +- +- hostlen = grub_strlen (host); +- if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']') +- { +- tmp = host+1; +- host[hostlen-1] = '\0'; +- } +- else +- tmp = host; +- +- *device = grub_xasprintf ("%s,%s", scheme, tmp); +- grub_free (scheme); +- grub_free (host); +- +- if (file && *file) +- { +- tmp = grub_strrchr (file, '/'); +- if (tmp) +- *(tmp+1) = '\0'; +- else +- file[0] = '\0'; +- } +- else if (!file) +- file = grub_strdup (""); +- +- if (file[0] == '/') +- { +- *path = grub_strdup (file+1); +- grub_free (file); +- } +- else +- *path = file; +- } +- else if (num == GRUB_NET_DHCP6_IA_NA) +- { +- const grub_net_dhcpv6_option_t *ia_na_opt; +- const grub_net_dhcpv6_opt_ia_na_t *ia_na = +- (const grub_net_dhcpv6_opt_ia_na_t *)opt; +- unsigned int left = len - OFFSET_OF (options, ia_na); +- unsigned int j; +- +- if ((grub_uint8_t *)ia_na + left > +- (grub_uint8_t *)options + option_max) +- left -= ((grub_uint8_t *)ia_na + left) +- - ((grub_uint8_t *)options + option_max); +- +- if (len < OFFSET_OF (option_data, opt) +- + sizeof (grub_net_dhcpv6_option_t)) +- { +- grub_dprintf ("net", +- "found dhcpv6 ia_na option with no address\n"); +- continue; +- } +- +- for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); ) +- { +- ia_na_opt = (const grub_net_dhcpv6_option_t *) +- (ia_na->options + j); +- grub_uint16_t ia_na_opt_num, ia_na_opt_len; +- +- ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num); +- ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len); +- if (ia_na_opt_len == 0) +- break; +- if (j + ia_na_opt_len > left) +- break; +- if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS) +- { +- const grub_net_dhcpv6_opt_ia_address_t *ia_addr; +- +- ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *) +- ia_na_opt; +- addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; +- grub_memcpy(addr.ipv6, ia_addr->ipv6_address, +- sizeof (ia_addr->ipv6_address)); +- inter = grub_net_add_addr (name, card, &addr, hwaddr, 0); +- } +- +- j += ia_na_opt_len; +- left -= ia_na_opt_len; +- } +- } +- +- i += len + 4; +- } +- +- grub_print_error (); ++ int done = 1; ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_duid_ll *duid; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ struct udphdr *udph; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (se->iface, ++ &multicast, &ll_multicast); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, 0); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (sizeof (*duid)); ++ ++ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data; ++ grub_memcpy (duid, &se->duid, sizeof (*duid)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (se->iaid); ++ ia_na->t1 = 0; ++ ia_na->t2 = 0; ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *)nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_SOLICIT; ++ v6h->transaction_id = se->transaction_id; ++ ++ grub_netbuff_push (nb, sizeof (*udph)); ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &se->iface->address, &multicast); ++ ++ err = grub_net_send_ip_packet (se->iface, &multicast, ++ &ll_multicast, nb, GRUB_NET_IP_UDP); ++ done = 0; ++ grub_netbuff_free (nb); ++ ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ } ++ if (!done) ++ grub_net_poll_cards (interval, 0); + } + +- if (is_def) ++ FOR_DHCP6_SESSIONS (se) + { +- grub_env_set ("net_default_interface", name); +- grub_env_export ("net_default_interface"); ++ grub_error_push (); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("couldn't autoconfigure %s"), ++ se->iface->card->name); + } + +- if (inter) +- grub_net_add_ipv6_local (inter, mask); +- return inter; ++ grub_dhcp6_session_remove_all (); ++ ++ return err; + } + ++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6; + + void + grub_bootp_init (void) +@@ -1084,11 +1819,15 @@ grub_bootp_init (void) + cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, + N_("VAR INTERFACE NUMBER DESCRIPTION"), + N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6, ++ N_("[CARD]"), ++ N_("perform a DHCPv6 autoconfiguration")); + } + + void + grub_bootp_fini (void) + { ++ grub_unregister_command (cmd_bootp6); + grub_unregister_command (cmd_getdhcp); + grub_unregister_command (cmd_bootp); + grub_unregister_command (cmd_dhcp); +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index a673bea807..8e25680db0 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -393,9 +393,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + pxe_mode = pxe->mode; + if (pxe_mode->using_ipv6) + { +- grub_net_link_level_address_t hwaddr; +- struct grub_net_network_level_interface *intf; +- + grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); + grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", + pxe_mode->dhcp_ack_received ? "yes" : "no", +@@ -403,15 +400,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (!pxe_mode->dhcp_ack_received) + continue; + +- hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (hwaddr.mac, +- card->efi_net->mode->current_address, +- sizeof (hwaddr.mac)); +- +- intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr, +- (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6, +- 1, device, path); +- if (intf && device && path) ++ grub_net_configure_by_dhcpv6_reply (card->name, card, 0, ++ (struct grub_net_dhcp6_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ if (grub_errno) ++ grub_print_error (); ++ if (device && path) + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + } + else +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index a5896f6dc2..ce6bdc75c6 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb, + { + struct udphdr *udph; + udph = (struct udphdr *) nb->data; ++ ++ if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT)) ++ { ++ if (udph->chksum) ++ { ++ grub_uint16_t chk, expected; ++ chk = udph->chksum; ++ udph->chksum = 0; ++ expected = grub_net_ip_transport_checksum (nb, ++ GRUB_NET_IP_UDP, ++ source, ++ dest); ++ if (expected != chk) ++ { ++ grub_dprintf ("net", "Invalid UDP checksum. " ++ "Expected %x, got %x\n", ++ grub_be_to_cpu16 (expected), ++ grub_be_to_cpu16 (chk)); ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ udph->chksum = chk; ++ } ++ ++ err = grub_netbuff_pull (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_net_process_dhcp6 (nb, card); ++ if (err) ++ grub_print_error (); ++ ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ + if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68) + { + const struct grub_net_bootp_packet *bootp; +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 9962880147..7614b58dca 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -1532,7 +1532,7 @@ typedef struct grub_efi_pxe_ip_filter + { + grub_efi_uint8_t filters; + grub_efi_uint8_t ip_count; +- grub_efi_uint8_t reserved; ++ grub_efi_uint16_t reserved; + grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; + } grub_efi_pxe_ip_filter_t; + +diff --git a/include/grub/net.h b/include/grub/net.h +index d55d505a03..543251f727 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -451,50 +451,65 @@ struct grub_net_bootp_packet + grub_uint8_t vendor[0]; + } GRUB_PACKED; + +-enum +- { +- GRUB_NET_DHCP6_IA_NA = 3, +- GRUB_NET_DHCP6_IA_ADDRESS = 5, +- GRUB_NET_DHCP6_BOOTFILE_URL = 59, +- }; +- +-struct grub_net_dhcpv6_option ++struct grub_net_dhcp6_packet + { +- grub_uint16_t option_num; +- grub_uint16_t option_len; +- grub_uint8_t option_data[]; ++ grub_uint32_t message_type:8; ++ grub_uint32_t transaction_id:24; ++ grub_uint8_t dhcp_options[0]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t; + +-struct grub_net_dhcpv6_opt_ia_na +-{ +- grub_uint16_t option_num; +- grub_uint16_t option_len; ++struct grub_net_dhcp6_option { ++ grub_uint16_t code; ++ grub_uint16_t len; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iana { + grub_uint32_t iaid; + grub_uint32_t t1; + grub_uint32_t t2; +- grub_uint8_t options[]; ++ grub_uint8_t data[0]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t; + +-struct grub_net_dhcpv6_opt_ia_address +-{ +- grub_uint16_t option_num; +- grub_uint16_t option_len; +- grub_uint64_t ipv6_address[2]; ++struct grub_net_dhcp6_option_iaaddr { ++ grub_uint8_t addr[16]; + grub_uint32_t preferred_lifetime; + grub_uint32_t valid_lifetime; +- grub_uint8_t options[]; ++ grub_uint8_t data[0]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t; + +-struct grub_net_dhcpv6_packet ++struct grub_net_dhcp6_option_duid_ll + { +- grub_uint32_t message_type:8; +- grub_uint32_t transaction_id:24; +- grub_uint8_t dhcp_options[1024]; ++ grub_uint16_t type; ++ grub_uint16_t hw_type; ++ grub_uint8_t hwaddr[6]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t; ++ ++enum ++ { ++ GRUB_NET_DHCP6_SOLICIT = 1, ++ GRUB_NET_DHCP6_ADVERTISE = 2, ++ GRUB_NET_DHCP6_REQUEST = 3, ++ GRUB_NET_DHCP6_REPLY = 7 ++ }; ++ ++enum ++ { ++ DHCP6_CLIENT_PORT = 546, ++ DHCP6_SERVER_PORT = 547 ++ }; ++ ++enum ++ { ++ GRUB_NET_DHCP6_OPTION_CLIENTID = 1, ++ GRUB_NET_DHCP6_OPTION_SERVERID = 2, ++ GRUB_NET_DHCP6_OPTION_IA_NA = 3, ++ GRUB_NET_DHCP6_OPTION_IAADDR = 5, ++ GRUB_NET_DHCP6_OPTION_ORO = 6, ++ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8, ++ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23, ++ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59 ++ }; + + #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 +@@ -532,12 +547,12 @@ grub_net_configure_by_dhcp_ack (const char *name, + int is_def, char **device, char **path); + + struct grub_net_network_level_interface * +-grub_net_configure_by_dhcpv6_ack (const char *name, +- struct grub_net_card *card, +- grub_net_interface_flags_t flags, +- const grub_net_link_level_address_t *hwaddr, +- const struct grub_net_dhcpv6_packet *packet, +- int is_def, char **device, char **path); ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6, ++ grub_size_t size, ++ int is_def, char **device, char **path); + + int + grub_ipv6_get_masksize(grub_uint16_t *mask); +@@ -554,6 +569,10 @@ void + grub_net_process_dhcp (struct grub_net_buff *nb, + struct grub_net_network_level_interface *iface); + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card); ++ + int + grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + const grub_net_link_level_address_t *b); diff --git a/0073-net-read-bracketed-ipv6-addrs-and-port-numbers.patch b/0073-net-read-bracketed-ipv6-addrs-and-port-numbers.patch deleted file mode 100644 index 307e33c..0000000 --- a/0073-net-read-bracketed-ipv6-addrs-and-port-numbers.patch +++ /dev/null @@ -1,270 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aaron Miller -Date: Fri, 29 Jul 2016 17:41:38 +0800 -Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers - -Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses -to be recognized with brackets around them, which is required to specify a port -number - -Signed-off-by: Aaron Miller -[pjones: various bug fixes] -Signed-off-by: Peter Jones ---- - grub-core/net/http.c | 25 ++++++++++++--- - grub-core/net/net.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++--- - grub-core/net/tftp.c | 8 +++-- - include/grub/net.h | 1 + - 4 files changed, 109 insertions(+), 12 deletions(-) - -diff --git a/grub-core/net/http.c b/grub-core/net/http.c -index b616cf40b1..12a2632ea5 100644 ---- a/grub-core/net/http.c -+++ b/grub-core/net/http.c -@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), - nb2 = grub_netbuff_alloc (data->chunk_rem); - if (!nb2) - return grub_errno; -- grub_netbuff_put (nb2, data->chunk_rem); -+ err = grub_netbuff_put (nb2, data->chunk_rem); -+ if (err) -+ return grub_errno; - grub_memcpy (nb2->data, nb->data, data->chunk_rem); - if (file->device->net->packs.count >= 20) - { -@@ -312,12 +314,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) - int i; - struct grub_net_buff *nb; - grub_err_t err; -+ char* server = file->device->net->server; -+ int port = file->device->net->port; - - nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE - + sizeof ("GET ") - 1 - + grub_strlen (data->filename) - + sizeof (" HTTP/1.1\r\nHost: ") - 1 -- + grub_strlen (file->device->net->server) -+ + grub_strlen (server) + sizeof (":XXXXXXXXXX") - + sizeof ("\r\nUser-Agent: " PACKAGE_STRING - "\r\n") - 1 - + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX" -@@ -356,7 +360,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) - sizeof (" HTTP/1.1\r\nHost: ") - 1); - - ptr = nb->tail; -- err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); -+ err = grub_netbuff_put (nb, grub_strlen (server)); - if (err) - { - grub_netbuff_free (nb); -@@ -365,6 +369,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) - grub_memcpy (ptr, file->device->net->server, - grub_strlen (file->device->net->server)); - -+ if (port) -+ { -+ ptr = nb->tail; -+ grub_snprintf ((char *) ptr, -+ sizeof (":XXXXXXXXXX"), -+ ":%d", -+ port); -+ } -+ - ptr = nb->tail; - err = grub_netbuff_put (nb, - sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") -@@ -390,8 +403,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) - grub_netbuff_put (nb, 2); - grub_memcpy (ptr, "\r\n", 2); - -- data->sock = grub_net_tcp_open (file->device->net->server, -- HTTP_PORT, http_receive, -+ grub_dprintf ("http", "opening path %s on host %s TCP port %d\n", -+ data->filename, server, port ? port : HTTP_PORT); -+ data->sock = grub_net_tcp_open (server, -+ port ? port : HTTP_PORT, http_receive, - http_err, NULL, - file); - if (!data->sock) -diff --git a/grub-core/net/net.c b/grub-core/net/net.c -index a46f82362e..0ce5e675ed 100644 ---- a/grub-core/net/net.c -+++ b/grub-core/net/net.c -@@ -444,6 +444,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) - grub_uint16_t newip[8]; - const char *ptr = val; - int word, quaddot = -1; -+ int bracketed = 0; -+ -+ if (ptr[0] == '[') -+ { -+ bracketed = 1; -+ ptr++; -+ } - - if (ptr[0] == ':' && ptr[1] != ':') - return 0; -@@ -482,6 +489,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) - grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); - } - grub_memcpy (ip, newip, 16); -+ if (bracketed && *ptr == ']') -+ ptr++; - if (rest) - *rest = ptr; - return 1; -@@ -1343,8 +1352,10 @@ grub_net_open_real (const char *name) - { - grub_net_app_level_t proto; - const char *protname, *server; -+ char *host; - grub_size_t protnamelen; - int try; -+ int port = 0; - - if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) - { -@@ -1382,6 +1393,72 @@ grub_net_open_real (const char *name) - return NULL; - } - -+ char* port_start; -+ /* ipv6 or port specified? */ -+ if ((port_start = grub_strchr (server, ':'))) -+ { -+ char* ipv6_begin; -+ if((ipv6_begin = grub_strchr (server, '['))) -+ { -+ char* ipv6_end = grub_strchr (server, ']'); -+ if(!ipv6_end) -+ { -+ grub_error (GRUB_ERR_NET_BAD_ADDRESS, -+ N_("mismatched [ in address")); -+ return NULL; -+ } -+ /* port number after bracketed ipv6 addr */ -+ if(ipv6_end[1] == ':') -+ { -+ port = grub_strtoul (ipv6_end + 2, NULL, 10); -+ if(port > 65535) -+ { -+ grub_error (GRUB_ERR_NET_BAD_ADDRESS, -+ N_("bad port number")); -+ return NULL; -+ } -+ } -+ host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1); -+ } -+ else -+ { -+ if (grub_strchr (port_start + 1, ':')) -+ { -+ int iplen = grub_strlen (server); -+ /* bracket bare ipv6 addrs */ -+ host = grub_malloc (iplen + 3); -+ if(!host) -+ { -+ return NULL; -+ } -+ host[0] = '['; -+ grub_memcpy (host + 1, server, iplen); -+ host[iplen + 1] = ']'; -+ host[iplen + 2] = '\0'; -+ } -+ else -+ { -+ /* hostname:port or ipv4:port */ -+ port = grub_strtol (port_start + 1, NULL, 10); -+ if(port > 65535) -+ { -+ grub_error (GRUB_ERR_NET_BAD_ADDRESS, -+ N_("bad port number")); -+ return NULL; -+ } -+ host = grub_strndup (server, port_start - server); -+ } -+ } -+ } -+ else -+ { -+ host = grub_strdup (server); -+ } -+ if (!host) -+ { -+ return NULL; -+ } -+ - for (try = 0; try < 2; try++) - { - FOR_NET_APP_LEVEL (proto) -@@ -1391,14 +1468,13 @@ grub_net_open_real (const char *name) - { - grub_net_t ret = grub_zalloc (sizeof (*ret)); - if (!ret) -- return NULL; -- ret->protocol = proto; -- ret->server = grub_strdup (server); -- if (!ret->server) - { -- grub_free (ret); -+ grub_free (host); - return NULL; - } -+ ret->protocol = proto; -+ ret->port = port; -+ ret->server = host; - ret->fs = &grub_net_fs; - return ret; - } -@@ -1473,6 +1549,7 @@ grub_net_open_real (const char *name) - grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), - name); - -+ grub_free (host); - return NULL; - } - -diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c -index 4ab2f5c735..d54b13f09f 100644 ---- a/grub-core/net/tftp.c -+++ b/grub-core/net/tftp.c -@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename) - grub_err_t err; - grub_uint8_t *nbd; - grub_net_network_level_address_t addr; -+ int port = file->device->net->port; - - data = grub_zalloc (sizeof (*data)); - if (!data) -@@ -362,14 +363,17 @@ tftp_open (struct grub_file *file, const char *filename) - err = grub_net_resolve_address (file->device->net->server, &addr); - if (err) - { -- grub_dprintf("tftp", "Address resolution failed: %d\n", err); -+ grub_dprintf ("tftp", "Address resolution failed: %d\n", err); -+ grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n", -+ (unsigned long long)data->file_size, -+ (unsigned long long)data->block_size); - grub_free (data); - return err; - } - - grub_dprintf("tftp", "opening connection\n"); - data->sock = grub_net_udp_open (addr, -- TFTP_SERVER_PORT, tftp_receive, -+ port ? port : TFTP_SERVER_PORT, tftp_receive, - file); - if (!data->sock) - { -diff --git a/include/grub/net.h b/include/grub/net.h -index af0404db7e..d55d505a03 100644 ---- a/include/grub/net.h -+++ b/include/grub/net.h -@@ -273,6 +273,7 @@ typedef struct grub_net - { - char *server; - char *name; -+ int port; - grub_net_app_level_t protocol; - grub_net_packets_t packs; - grub_off_t offset; diff --git a/0074-bootp-New-net_bootp6-command.patch b/0074-bootp-New-net_bootp6-command.patch deleted file mode 100644 index bef3acd..0000000 --- a/0074-bootp-New-net_bootp6-command.patch +++ /dev/null @@ -1,1368 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Wed, 10 Jul 2019 15:42:36 +0200 -Subject: [PATCH] bootp: New net_bootp6 command - -Implement new net_bootp6 command for IPv6 network auto configuration via the -DHCPv6 protocol (RFC3315). - -Signed-off-by: Michael Chang -Signed-off-by: Ken Lin -[pjones: Put back our code to add a local route] -Signed-off-by: Peter Jones ---- - grub-core/net/bootp.c | 1059 ++++++++++++++++++++++++++++++------ - grub-core/net/drivers/efi/efinet.c | 20 +- - grub-core/net/ip.c | 39 ++ - include/grub/efi/api.h | 2 +- - include/grub/net.h | 91 ++-- - 5 files changed, 1002 insertions(+), 209 deletions(-) - -diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c -index 08b6b2b5d6..fe93b80f1c 100644 ---- a/grub-core/net/bootp.c -+++ b/grub-core/net/bootp.c -@@ -24,6 +24,98 @@ - #include - #include - #include -+#include -+#include -+ -+static int -+dissect_url (const char *url, char **proto, char **host, char **path) -+{ -+ const char *p, *ps; -+ grub_size_t l; -+ -+ *proto = *host = *path = NULL; -+ ps = p = url; -+ -+ while ((p = grub_strchr (p, ':'))) -+ { -+ if (grub_strlen (p) < sizeof ("://") - 1) -+ break; -+ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) -+ { -+ l = p - ps; -+ *proto = grub_malloc (l + 1); -+ if (!*proto) -+ { -+ grub_print_error (); -+ return 0; -+ } -+ -+ grub_memcpy (*proto, ps, l); -+ (*proto)[l] = '\0'; -+ p += sizeof ("://") - 1; -+ break; -+ } -+ ++p; -+ } -+ -+ if (!*proto) -+ { -+ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); -+ return 0; -+ } -+ -+ ps = p; -+ p = grub_strchr (p, '/'); -+ -+ if (!p) -+ { -+ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); -+ grub_free (*proto); -+ *proto = NULL; -+ return 0; -+ } -+ -+ l = p - ps; -+ -+ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') -+ { -+ *host = grub_malloc (l - 1); -+ if (!*host) -+ { -+ grub_print_error (); -+ grub_free (*proto); -+ *proto = NULL; -+ return 0; -+ } -+ grub_memcpy (*host, ps + 1, l - 2); -+ (*host)[l - 2] = 0; -+ } -+ else -+ { -+ *host = grub_malloc (l + 1); -+ if (!*host) -+ { -+ grub_print_error (); -+ grub_free (*proto); -+ *proto = NULL; -+ return 0; -+ } -+ grub_memcpy (*host, ps, l); -+ (*host)[l] = 0; -+ } -+ -+ *path = grub_strdup (p); -+ if (!*path) -+ { -+ grub_print_error (); -+ grub_free (*host); -+ grub_free (*proto); -+ *host = NULL; -+ *proto = NULL; -+ return 0; -+ } -+ return 1; -+} - - struct grub_dhcp_discover_options - { -@@ -604,6 +696,584 @@ out: - return err; - } - -+/* The default netbuff size for sending DHCPv6 packets which should be -+ large enough to hold the information */ -+#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512 -+ -+struct grub_dhcp6_options -+{ -+ grub_uint8_t *client_duid; -+ grub_uint16_t client_duid_len; -+ grub_uint8_t *server_duid; -+ grub_uint16_t server_duid_len; -+ grub_uint32_t iaid; -+ grub_uint32_t t1; -+ grub_uint32_t t2; -+ grub_net_network_level_address_t *ia_addr; -+ grub_uint32_t preferred_lifetime; -+ grub_uint32_t valid_lifetime; -+ grub_net_network_level_address_t *dns_server_addrs; -+ grub_uint16_t num_dns_server; -+ char *boot_file_proto; -+ char *boot_file_server_ip; -+ char *boot_file_path; -+}; -+ -+typedef struct grub_dhcp6_options *grub_dhcp6_options_t; -+ -+struct grub_dhcp6_session -+{ -+ struct grub_dhcp6_session *next; -+ struct grub_dhcp6_session **prev; -+ grub_uint32_t iaid; -+ grub_uint32_t transaction_id:24; -+ grub_uint64_t start_time; -+ struct grub_net_dhcp6_option_duid_ll duid; -+ struct grub_net_network_level_interface *iface; -+ -+ /* The associated dhcpv6 options */ -+ grub_dhcp6_options_t adv; -+ grub_dhcp6_options_t reply; -+}; -+ -+typedef struct grub_dhcp6_session *grub_dhcp6_session_t; -+ -+typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data); -+ -+static void -+foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, -+ dhcp6_option_hook_fn hook, void *hook_data); -+ -+static void -+parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data) -+{ -+ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data; -+ -+ grub_uint16_t code = grub_be_to_cpu16 (opt->code); -+ grub_uint16_t len = grub_be_to_cpu16 (opt->len); -+ -+ if (code == GRUB_NET_DHCP6_OPTION_IAADDR) -+ { -+ const struct grub_net_dhcp6_option_iaaddr *iaaddr; -+ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data; -+ -+ if (len < sizeof (*iaaddr)) -+ { -+ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len); -+ return; -+ } -+ if (!dhcp6->ia_addr) -+ { -+ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr)); -+ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -+ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr); -+ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8); -+ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime); -+ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime); -+ } -+ } -+} -+ -+static void -+parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data) -+{ -+ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data; -+ grub_uint16_t code = grub_be_to_cpu16 (opt->code); -+ grub_uint16_t len = grub_be_to_cpu16 (opt->len); -+ -+ switch (code) -+ { -+ case GRUB_NET_DHCP6_OPTION_CLIENTID: -+ -+ if (dhcp6->client_duid || !len) -+ { -+ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len); -+ break; -+ } -+ dhcp6->client_duid = grub_malloc (len); -+ grub_memcpy (dhcp6->client_duid, opt->data, len); -+ dhcp6->client_duid_len = len; -+ break; -+ -+ case GRUB_NET_DHCP6_OPTION_SERVERID: -+ -+ if (dhcp6->server_duid || !len) -+ { -+ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len); -+ break; -+ } -+ dhcp6->server_duid = grub_malloc (len); -+ grub_memcpy (dhcp6->server_duid, opt->data, len); -+ dhcp6->server_duid_len = len; -+ break; -+ -+ case GRUB_NET_DHCP6_OPTION_IA_NA: -+ { -+ const struct grub_net_dhcp6_option_iana *ia_na; -+ grub_uint16_t data_len; -+ -+ if (dhcp6->iaid || len < sizeof (*ia_na)) -+ { -+ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len); -+ break; -+ } -+ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data; -+ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid); -+ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1); -+ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2); -+ -+ data_len = len - sizeof (*ia_na); -+ if (data_len) -+ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6); -+ } -+ break; -+ -+ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS: -+ { -+ const grub_uint8_t *po; -+ grub_uint16_t ln; -+ grub_net_network_level_address_t *la; -+ -+ if (!len || len & 0xf) -+ { -+ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n"); -+ break; -+ } -+ dhcp6->num_dns_server = ln = len >> 4; -+ dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la)); -+ -+ for (po = opt->data; ln > 0; po += 0x10, la++, ln--) -+ { -+ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -+ la->ipv6[0] = grub_get_unaligned64 (po); -+ la->ipv6[1] = grub_get_unaligned64 (po + 8); -+ la->option = DNS_OPTION_PREFER_IPV6; -+ } -+ } -+ break; -+ -+ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL: -+ dissect_url ((const char *)opt->data, -+ &dhcp6->boot_file_proto, -+ &dhcp6->boot_file_server_ip, -+ &dhcp6->boot_file_path); -+ break; -+ -+ default: -+ break; -+ } -+} -+ -+static void -+foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data) -+{ -+ while (size) -+ { -+ grub_uint16_t code, len; -+ -+ if (size < sizeof (*opt)) -+ { -+ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size); -+ break; -+ } -+ size -= sizeof (*opt); -+ len = grub_be_to_cpu16 (opt->len); -+ code = grub_be_to_cpu16 (opt->code); -+ if (size < len) -+ { -+ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code); -+ break; -+ } -+ if (!len) -+ { -+ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code); -+ break; -+ } -+ else -+ { -+ if (hook) -+ hook (opt, hook_data); -+ size -= len; -+ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt)); -+ } -+ } -+} -+ -+static grub_dhcp6_options_t -+grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h, -+ grub_size_t size) -+{ -+ grub_dhcp6_options_t options; -+ -+ if (size < sizeof (*v6h)) -+ { -+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); -+ return NULL; -+ } -+ -+ options = grub_zalloc (sizeof(*options)); -+ if (!options) -+ return NULL; -+ -+ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options, -+ size - sizeof (*v6h), parse_dhcp6_option, options); -+ -+ return options; -+} -+ -+static void -+grub_dhcp6_options_free (grub_dhcp6_options_t options) -+{ -+ if (options->client_duid) -+ grub_free (options->client_duid); -+ if (options->server_duid) -+ grub_free (options->server_duid); -+ if (options->ia_addr) -+ grub_free (options->ia_addr); -+ if (options->dns_server_addrs) -+ grub_free (options->dns_server_addrs); -+ if (options->boot_file_proto) -+ grub_free (options->boot_file_proto); -+ if (options->boot_file_server_ip) -+ grub_free (options->boot_file_server_ip); -+ if (options->boot_file_path) -+ grub_free (options->boot_file_path); -+ -+ grub_free (options); -+} -+ -+static grub_dhcp6_session_t grub_dhcp6_sessions; -+#define FOR_DHCP6_SESSIONS_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE (var, next, grub_dhcp6_sessions) -+#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions) -+ -+static void -+grub_net_configure_by_dhcp6_info (const char *name, -+ struct grub_net_card *card, -+ grub_dhcp6_options_t dhcp6, -+ int is_def, -+ int flags, -+ struct grub_net_network_level_interface **ret_inf) -+{ -+ grub_net_network_level_netaddress_t netaddr; -+ struct grub_net_network_level_interface *inf; -+ -+ if (dhcp6->ia_addr) -+ { -+ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags); -+ -+ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -+ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0]; -+ netaddr.ipv6.base[1] = 0; -+ netaddr.ipv6.masksize = 64; -+ grub_net_add_route (name, netaddr, inf); -+ -+ if (ret_inf) -+ *ret_inf = inf; -+ } -+ -+ if (dhcp6->dns_server_addrs) -+ { -+ grub_uint16_t i; -+ -+ for (i = 0; i < dhcp6->num_dns_server; ++i) -+ grub_net_add_dns_server (dhcp6->dns_server_addrs + i); -+ } -+ -+ if (dhcp6->boot_file_path) -+ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path, -+ grub_strlen (dhcp6->boot_file_path)); -+ -+ if (is_def && dhcp6->boot_file_server_ip) -+ { -+ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip); -+ grub_env_set ("net_default_interface", name); -+ grub_env_export ("net_default_interface"); -+ } -+} -+ -+static void -+grub_dhcp6_session_add (struct grub_net_network_level_interface *iface, -+ grub_uint32_t iaid) -+{ -+ grub_dhcp6_session_t se; -+ struct grub_datetime date; -+ grub_err_t err; -+ grub_int32_t t = 0; -+ -+ se = grub_malloc (sizeof (*se)); -+ -+ err = grub_get_datetime (&date); -+ if (err || !grub_datetime2unixtime (&date, &t)) -+ { -+ grub_errno = GRUB_ERR_NONE; -+ t = 0; -+ } -+ -+ se->iface = iface; -+ se->iaid = iaid; -+ se->transaction_id = t; -+ se->start_time = grub_get_time_ms (); -+ se->duid.type = grub_cpu_to_be16_compile_time (3) ; -+ se->duid.hw_type = grub_cpu_to_be16_compile_time (1); -+ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr)); -+ se->adv = NULL; -+ se->reply = NULL; -+ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se)); -+} -+ -+static void -+grub_dhcp6_session_remove (grub_dhcp6_session_t se) -+{ -+ grub_list_remove (GRUB_AS_LIST (se)); -+ if (se->adv) -+ grub_dhcp6_options_free (se->adv); -+ if (se->reply) -+ grub_dhcp6_options_free (se->reply); -+ grub_free (se); -+} -+ -+static void -+grub_dhcp6_session_remove_all (void) -+{ -+ grub_dhcp6_session_t se, next; -+ -+ FOR_DHCP6_SESSIONS_SAFE (se, next) -+ { -+ grub_dhcp6_session_remove (se); -+ } -+ grub_dhcp6_sessions = NULL; -+} -+ -+static grub_err_t -+grub_dhcp6_session_configure_network (grub_dhcp6_session_t se) -+{ -+ char *name; -+ -+ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name); -+ if (!name) -+ return grub_errno; -+ -+ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0); -+ grub_free (name); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_dhcp6_session_send_request (grub_dhcp6_session_t se) -+{ -+ struct grub_net_buff *nb; -+ struct grub_net_dhcp6_option *opt; -+ struct grub_net_dhcp6_packet *v6h; -+ struct grub_net_dhcp6_option_iana *ia_na; -+ struct grub_net_dhcp6_option_iaaddr *iaaddr; -+ struct udphdr *udph; -+ grub_net_network_level_address_t multicast; -+ grub_net_link_level_address_t ll_multicast; -+ grub_uint64_t elapsed; -+ struct grub_net_network_level_interface *inf = se->iface; -+ grub_dhcp6_options_t dhcp6 = se->adv; -+ grub_err_t err = GRUB_ERR_NONE; -+ -+ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -+ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); -+ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); -+ -+ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast); -+ if (err) -+ return err; -+ -+ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); -+ -+ if (!nb) -+ return grub_errno; -+ -+ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ opt = (struct grub_net_dhcp6_option *)nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); -+ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len); -+ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len); -+ -+ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ opt = (struct grub_net_dhcp6_option *)nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID); -+ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len); -+ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len); -+ -+ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ if (dhcp6->ia_addr) -+ { -+ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ } -+ opt = (struct grub_net_dhcp6_option *)nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); -+ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); -+ if (dhcp6->ia_addr) -+ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt)); -+ -+ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; -+ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid); -+ -+ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1); -+ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2); -+ -+ if (dhcp6->ia_addr) -+ { -+ opt = (struct grub_net_dhcp6_option *)ia_na->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); -+ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr)); -+ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data; -+ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]); -+ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]); -+ -+ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime); -+ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime); -+ } -+ -+ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ opt = (struct grub_net_dhcp6_option*) nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO); -+ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t)); -+ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)); -+ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS)); -+ -+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ opt = (struct grub_net_dhcp6_option*) nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); -+ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); -+ -+ /* the time is expressed in hundredths of a second */ -+ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0); -+ -+ if (elapsed > 0xffff) -+ elapsed = 0xffff; -+ -+ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed)); -+ -+ err = grub_netbuff_push (nb, sizeof (*v6h)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ v6h = (struct grub_net_dhcp6_packet *) nb->data; -+ v6h->message_type = GRUB_NET_DHCP6_REQUEST; -+ v6h->transaction_id = se->transaction_id; -+ -+ err = grub_netbuff_push (nb, sizeof (*udph)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ udph = (struct udphdr *) nb->data; -+ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); -+ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); -+ udph->chksum = 0; -+ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); -+ -+ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, -+ &inf->address, -+ &multicast); -+ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, -+ GRUB_NET_IP_UDP); -+ -+ grub_netbuff_free (nb); -+ -+ return err; -+} -+ -+struct grub_net_network_level_interface * -+grub_net_configure_by_dhcpv6_reply (const char *name, -+ struct grub_net_card *card, -+ grub_net_interface_flags_t flags, -+ const struct grub_net_dhcp6_packet *v6h, -+ grub_size_t size, -+ int is_def, -+ char **device, char **path) -+{ -+ struct grub_net_network_level_interface *inf; -+ grub_dhcp6_options_t dhcp6; -+ int mask = -1; -+ -+ dhcp6 = grub_dhcp6_options_get (v6h, size); -+ if (!dhcp6) -+ { -+ grub_print_error (); -+ return NULL; -+ } -+ -+ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf); -+ -+ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip) -+ { -+ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip); -+ grub_print_error (); -+ } -+ if (path && dhcp6->boot_file_path) -+ { -+ *path = grub_strdup (dhcp6->boot_file_path); -+ grub_print_error (); -+ if (*path) -+ { -+ char *slash; -+ slash = grub_strrchr (*path, '/'); -+ if (slash) -+ *slash = 0; -+ else -+ **path = 0; -+ } -+ } -+ -+ grub_dhcp6_options_free (dhcp6); -+ -+ if (inf) -+ grub_net_add_ipv6_local (inf, mask); -+ -+ return inf; -+} -+ - /* - * This is called directly from net/ip.c:handle_dgram(), because those - * BOOTP/DHCP packets are a bit special due to their improper -@@ -672,6 +1342,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb, - } - } - -+grub_err_t -+grub_net_process_dhcp6 (struct grub_net_buff *nb, -+ struct grub_net_card *card __attribute__ ((unused))) -+{ -+ const struct grub_net_dhcp6_packet *v6h; -+ grub_dhcp6_session_t se; -+ grub_size_t size; -+ grub_dhcp6_options_t options; -+ -+ v6h = (const struct grub_net_dhcp6_packet *) nb->data; -+ size = nb->tail - nb->data; -+ -+ options = grub_dhcp6_options_get (v6h, size); -+ if (!options) -+ return grub_errno; -+ -+ if (!options->client_duid || !options->server_duid || !options->ia_addr) -+ { -+ grub_dhcp6_options_free (options); -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet"); -+ } -+ -+ FOR_DHCP6_SESSIONS (se) -+ { -+ if (se->transaction_id == v6h->transaction_id && -+ grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 && -+ se->iaid == options->iaid) -+ break; -+ } -+ -+ if (!se) -+ { -+ grub_dprintf ("bootp", "DHCPv6 session not found\n"); -+ grub_dhcp6_options_free (options); -+ return GRUB_ERR_NONE; -+ } -+ -+ if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE) -+ { -+ if (se->adv) -+ { -+ grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n"); -+ grub_dhcp6_options_free (options); -+ return GRUB_ERR_NONE; -+ } -+ -+ se->adv = options; -+ return grub_dhcp6_session_send_request (se); -+ } -+ else if (v6h->message_type == GRUB_NET_DHCP6_REPLY) -+ { -+ if (!se->adv) -+ { -+ grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n"); -+ grub_dhcp6_options_free (options); -+ return GRUB_ERR_NONE; -+ } -+ -+ se->reply = options; -+ grub_dhcp6_session_configure_network (se); -+ grub_dhcp6_session_remove (se); -+ return GRUB_ERR_NONE; -+ } -+ else -+ { -+ grub_dhcp6_options_free (options); -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ - static grub_err_t - grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), - int argc, char **args) -@@ -897,180 +1638,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), - return err; - } - --static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; -- --struct grub_net_network_level_interface * --grub_net_configure_by_dhcpv6_ack (const char *name, -- struct grub_net_card *card, -- grub_net_interface_flags_t flags -- __attribute__((__unused__)), -- const grub_net_link_level_address_t *hwaddr, -- const struct grub_net_dhcpv6_packet *packet, -- int is_def, char **device, char **path) -+static grub_err_t -+grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)), -+ int argc, char **args) - { -- struct grub_net_network_level_interface *inter = NULL; -- struct grub_net_network_level_address addr; -- int mask = -1; -+ struct grub_net_card *card; -+ grub_uint32_t iaid = 0; -+ int interval; -+ grub_err_t err; -+ grub_dhcp6_session_t se; - -- if (!device || !path) -- return NULL; -+ err = GRUB_ERR_NONE; - -- *device = 0; -- *path = 0; -+ FOR_NET_CARDS (card) -+ { -+ struct grub_net_network_level_interface *iface; - -- grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n", -- hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2], -- hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]); -+ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) -+ continue; - -- if (is_def) -- grub_net_default_server = 0; -+ iface = grub_net_ipv6_get_link_local (card, &card->default_address); -+ if (!iface) -+ { -+ grub_dhcp6_session_remove_all (); -+ return grub_errno; -+ } - -- if (is_def && !grub_net_default_server && packet) -+ grub_dhcp6_session_add (iface, iaid++); -+ } -+ -+ for (interval = 200; interval < 10000; interval *= 2) - { -- const grub_uint8_t *options = packet->dhcp_options; -- unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet); -- unsigned int i; -- -- for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); ) -- { -- grub_uint16_t num, len; -- grub_net_dhcpv6_option_t *opt = -- (grub_net_dhcpv6_option_t *)(options + i); -- -- num = grub_be_to_cpu16(opt->option_num); -- len = grub_be_to_cpu16(opt->option_len); -- -- grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len); -- -- if (len == 0) -- break; -- -- if (len + i > 1024) -- break; -- -- if (num == GRUB_NET_DHCP6_BOOTFILE_URL) -- { -- char *scheme, *userinfo, *host, *file; -- char *tmp; -- int hostlen; -- int port; -- int rc = extract_url_info ((const char *)opt->option_data, -- (grub_size_t)len, -- &scheme, &userinfo, &host, &port, -- &file); -- if (rc < 0) -- continue; -- -- /* right now this only handles tftp. */ -- if (grub_strcmp("tftp", scheme)) -- { -- grub_free (scheme); -- grub_free (userinfo); -- grub_free (host); -- grub_free (file); -- continue; -- } -- grub_free (userinfo); -- -- hostlen = grub_strlen (host); -- if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']') -- { -- tmp = host+1; -- host[hostlen-1] = '\0'; -- } -- else -- tmp = host; -- -- *device = grub_xasprintf ("%s,%s", scheme, tmp); -- grub_free (scheme); -- grub_free (host); -- -- if (file && *file) -- { -- tmp = grub_strrchr (file, '/'); -- if (tmp) -- *(tmp+1) = '\0'; -- else -- file[0] = '\0'; -- } -- else if (!file) -- file = grub_strdup (""); -- -- if (file[0] == '/') -- { -- *path = grub_strdup (file+1); -- grub_free (file); -- } -- else -- *path = file; -- } -- else if (num == GRUB_NET_DHCP6_IA_NA) -- { -- const grub_net_dhcpv6_option_t *ia_na_opt; -- const grub_net_dhcpv6_opt_ia_na_t *ia_na = -- (const grub_net_dhcpv6_opt_ia_na_t *)opt; -- unsigned int left = len - OFFSET_OF (options, ia_na); -- unsigned int j; -- -- if ((grub_uint8_t *)ia_na + left > -- (grub_uint8_t *)options + option_max) -- left -= ((grub_uint8_t *)ia_na + left) -- - ((grub_uint8_t *)options + option_max); -- -- if (len < OFFSET_OF (option_data, opt) -- + sizeof (grub_net_dhcpv6_option_t)) -- { -- grub_dprintf ("net", -- "found dhcpv6 ia_na option with no address\n"); -- continue; -- } -- -- for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); ) -- { -- ia_na_opt = (const grub_net_dhcpv6_option_t *) -- (ia_na->options + j); -- grub_uint16_t ia_na_opt_num, ia_na_opt_len; -- -- ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num); -- ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len); -- if (ia_na_opt_len == 0) -- break; -- if (j + ia_na_opt_len > left) -- break; -- if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS) -- { -- const grub_net_dhcpv6_opt_ia_address_t *ia_addr; -- -- ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *) -- ia_na_opt; -- addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -- grub_memcpy(addr.ipv6, ia_addr->ipv6_address, -- sizeof (ia_addr->ipv6_address)); -- inter = grub_net_add_addr (name, card, &addr, hwaddr, 0); -- } -- -- j += ia_na_opt_len; -- left -= ia_na_opt_len; -- } -- } -- -- i += len + 4; -- } -- -- grub_print_error (); -+ int done = 1; -+ -+ FOR_DHCP6_SESSIONS (se) -+ { -+ struct grub_net_buff *nb; -+ struct grub_net_dhcp6_option *opt; -+ struct grub_net_dhcp6_packet *v6h; -+ struct grub_net_dhcp6_option_duid_ll *duid; -+ struct grub_net_dhcp6_option_iana *ia_na; -+ grub_net_network_level_address_t multicast; -+ grub_net_link_level_address_t ll_multicast; -+ struct udphdr *udph; -+ -+ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; -+ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); -+ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); -+ -+ err = grub_net_link_layer_resolve (se->iface, -+ &multicast, &ll_multicast); -+ if (err) -+ { -+ grub_dhcp6_session_remove_all (); -+ return err; -+ } -+ -+ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); -+ -+ if (!nb) -+ { -+ grub_dhcp6_session_remove_all (); -+ return grub_errno; -+ } -+ -+ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); -+ if (err) -+ { -+ grub_dhcp6_session_remove_all (); -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); -+ if (err) -+ { -+ grub_dhcp6_session_remove_all (); -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ opt = (struct grub_net_dhcp6_option *)nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); -+ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); -+ grub_set_unaligned16 (opt->data, 0); -+ -+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid)); -+ if (err) -+ { -+ grub_dhcp6_session_remove_all (); -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ opt = (struct grub_net_dhcp6_option *)nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); -+ opt->len = grub_cpu_to_be16 (sizeof (*duid)); -+ -+ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data; -+ grub_memcpy (duid, &se->duid, sizeof (*duid)); -+ -+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na)); -+ if (err) -+ { -+ grub_dhcp6_session_remove_all (); -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ opt = (struct grub_net_dhcp6_option *)nb->data; -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); -+ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); -+ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; -+ ia_na->iaid = grub_cpu_to_be32 (se->iaid); -+ ia_na->t1 = 0; -+ ia_na->t2 = 0; -+ -+ err = grub_netbuff_push (nb, sizeof (*v6h)); -+ if (err) -+ { -+ grub_dhcp6_session_remove_all (); -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ v6h = (struct grub_net_dhcp6_packet *)nb->data; -+ v6h->message_type = GRUB_NET_DHCP6_SOLICIT; -+ v6h->transaction_id = se->transaction_id; -+ -+ grub_netbuff_push (nb, sizeof (*udph)); -+ -+ udph = (struct udphdr *) nb->data; -+ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); -+ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); -+ udph->chksum = 0; -+ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); -+ -+ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, -+ &se->iface->address, &multicast); -+ -+ err = grub_net_send_ip_packet (se->iface, &multicast, -+ &ll_multicast, nb, GRUB_NET_IP_UDP); -+ done = 0; -+ grub_netbuff_free (nb); -+ -+ if (err) -+ { -+ grub_dhcp6_session_remove_all (); -+ return err; -+ } -+ } -+ if (!done) -+ grub_net_poll_cards (interval, 0); - } - -- if (is_def) -+ FOR_DHCP6_SESSIONS (se) - { -- grub_env_set ("net_default_interface", name); -- grub_env_export ("net_default_interface"); -+ grub_error_push (); -+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, -+ N_("couldn't autoconfigure %s"), -+ se->iface->card->name); - } - -- if (inter) -- grub_net_add_ipv6_local (inter, mask); -- return inter; -+ grub_dhcp6_session_remove_all (); -+ -+ return err; - } - -+static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6; - - void - grub_bootp_init (void) -@@ -1084,11 +1819,15 @@ grub_bootp_init (void) - cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, - N_("VAR INTERFACE NUMBER DESCRIPTION"), - N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); -+ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6, -+ N_("[CARD]"), -+ N_("perform a DHCPv6 autoconfiguration")); - } - - void - grub_bootp_fini (void) - { -+ grub_unregister_command (cmd_bootp6); - grub_unregister_command (cmd_getdhcp); - grub_unregister_command (cmd_bootp); - grub_unregister_command (cmd_dhcp); -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index a673bea807..8e25680db0 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -393,9 +393,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - pxe_mode = pxe->mode; - if (pxe_mode->using_ipv6) - { -- grub_net_link_level_address_t hwaddr; -- struct grub_net_network_level_interface *intf; -- - grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); - grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", - pxe_mode->dhcp_ack_received ? "yes" : "no", -@@ -403,15 +400,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - if (!pxe_mode->dhcp_ack_received) - continue; - -- hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; -- grub_memcpy (hwaddr.mac, -- card->efi_net->mode->current_address, -- sizeof (hwaddr.mac)); -- -- intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr, -- (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6, -- 1, device, path); -- if (intf && device && path) -+ grub_net_configure_by_dhcpv6_reply (card->name, card, 0, -+ (struct grub_net_dhcp6_packet *) -+ &pxe_mode->dhcp_ack, -+ sizeof (pxe_mode->dhcp_ack), -+ 1, device, path); -+ if (grub_errno) -+ grub_print_error (); -+ if (device && path) - grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); - } - else -diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c -index a5896f6dc2..ce6bdc75c6 100644 ---- a/grub-core/net/ip.c -+++ b/grub-core/net/ip.c -@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb, - { - struct udphdr *udph; - udph = (struct udphdr *) nb->data; -+ -+ if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT)) -+ { -+ if (udph->chksum) -+ { -+ grub_uint16_t chk, expected; -+ chk = udph->chksum; -+ udph->chksum = 0; -+ expected = grub_net_ip_transport_checksum (nb, -+ GRUB_NET_IP_UDP, -+ source, -+ dest); -+ if (expected != chk) -+ { -+ grub_dprintf ("net", "Invalid UDP checksum. " -+ "Expected %x, got %x\n", -+ grub_be_to_cpu16 (expected), -+ grub_be_to_cpu16 (chk)); -+ grub_netbuff_free (nb); -+ return GRUB_ERR_NONE; -+ } -+ udph->chksum = chk; -+ } -+ -+ err = grub_netbuff_pull (nb, sizeof (*udph)); -+ if (err) -+ { -+ grub_netbuff_free (nb); -+ return err; -+ } -+ -+ err = grub_net_process_dhcp6 (nb, card); -+ if (err) -+ grub_print_error (); -+ -+ grub_netbuff_free (nb); -+ return GRUB_ERR_NONE; -+ } -+ - if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68) - { - const struct grub_net_bootp_packet *bootp; -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index 9962880147..7614b58dca 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -1532,7 +1532,7 @@ typedef struct grub_efi_pxe_ip_filter - { - grub_efi_uint8_t filters; - grub_efi_uint8_t ip_count; -- grub_efi_uint8_t reserved; -+ grub_efi_uint16_t reserved; - grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; - } grub_efi_pxe_ip_filter_t; - -diff --git a/include/grub/net.h b/include/grub/net.h -index d55d505a03..543251f727 100644 ---- a/include/grub/net.h -+++ b/include/grub/net.h -@@ -451,50 +451,65 @@ struct grub_net_bootp_packet - grub_uint8_t vendor[0]; - } GRUB_PACKED; - --enum -- { -- GRUB_NET_DHCP6_IA_NA = 3, -- GRUB_NET_DHCP6_IA_ADDRESS = 5, -- GRUB_NET_DHCP6_BOOTFILE_URL = 59, -- }; -- --struct grub_net_dhcpv6_option -+struct grub_net_dhcp6_packet - { -- grub_uint16_t option_num; -- grub_uint16_t option_len; -- grub_uint8_t option_data[]; -+ grub_uint32_t message_type:8; -+ grub_uint32_t transaction_id:24; -+ grub_uint8_t dhcp_options[0]; - } GRUB_PACKED; --typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t; - --struct grub_net_dhcpv6_opt_ia_na --{ -- grub_uint16_t option_num; -- grub_uint16_t option_len; -+struct grub_net_dhcp6_option { -+ grub_uint16_t code; -+ grub_uint16_t len; -+ grub_uint8_t data[0]; -+} GRUB_PACKED; -+ -+struct grub_net_dhcp6_option_iana { - grub_uint32_t iaid; - grub_uint32_t t1; - grub_uint32_t t2; -- grub_uint8_t options[]; -+ grub_uint8_t data[0]; - } GRUB_PACKED; --typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t; - --struct grub_net_dhcpv6_opt_ia_address --{ -- grub_uint16_t option_num; -- grub_uint16_t option_len; -- grub_uint64_t ipv6_address[2]; -+struct grub_net_dhcp6_option_iaaddr { -+ grub_uint8_t addr[16]; - grub_uint32_t preferred_lifetime; - grub_uint32_t valid_lifetime; -- grub_uint8_t options[]; -+ grub_uint8_t data[0]; - } GRUB_PACKED; --typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t; - --struct grub_net_dhcpv6_packet -+struct grub_net_dhcp6_option_duid_ll - { -- grub_uint32_t message_type:8; -- grub_uint32_t transaction_id:24; -- grub_uint8_t dhcp_options[1024]; -+ grub_uint16_t type; -+ grub_uint16_t hw_type; -+ grub_uint8_t hwaddr[6]; - } GRUB_PACKED; --typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t; -+ -+enum -+ { -+ GRUB_NET_DHCP6_SOLICIT = 1, -+ GRUB_NET_DHCP6_ADVERTISE = 2, -+ GRUB_NET_DHCP6_REQUEST = 3, -+ GRUB_NET_DHCP6_REPLY = 7 -+ }; -+ -+enum -+ { -+ DHCP6_CLIENT_PORT = 546, -+ DHCP6_SERVER_PORT = 547 -+ }; -+ -+enum -+ { -+ GRUB_NET_DHCP6_OPTION_CLIENTID = 1, -+ GRUB_NET_DHCP6_OPTION_SERVERID = 2, -+ GRUB_NET_DHCP6_OPTION_IA_NA = 3, -+ GRUB_NET_DHCP6_OPTION_IAADDR = 5, -+ GRUB_NET_DHCP6_OPTION_ORO = 6, -+ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8, -+ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23, -+ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59 -+ }; - - #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 - #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 -@@ -532,12 +547,12 @@ grub_net_configure_by_dhcp_ack (const char *name, - int is_def, char **device, char **path); - - struct grub_net_network_level_interface * --grub_net_configure_by_dhcpv6_ack (const char *name, -- struct grub_net_card *card, -- grub_net_interface_flags_t flags, -- const grub_net_link_level_address_t *hwaddr, -- const struct grub_net_dhcpv6_packet *packet, -- int is_def, char **device, char **path); -+grub_net_configure_by_dhcpv6_reply (const char *name, -+ struct grub_net_card *card, -+ grub_net_interface_flags_t flags, -+ const struct grub_net_dhcp6_packet *v6, -+ grub_size_t size, -+ int is_def, char **device, char **path); - - int - grub_ipv6_get_masksize(grub_uint16_t *mask); -@@ -554,6 +569,10 @@ void - grub_net_process_dhcp (struct grub_net_buff *nb, - struct grub_net_network_level_interface *iface); - -+grub_err_t -+grub_net_process_dhcp6 (struct grub_net_buff *nb, -+ struct grub_net_card *card); -+ - int - grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, - const grub_net_link_level_address_t *b); diff --git a/0074-efinet-UEFI-IPv6-PXE-support.patch b/0074-efinet-UEFI-IPv6-PXE-support.patch new file mode 100644 index 0000000..988c178 --- /dev/null +++ b/0074-efinet-UEFI-IPv6-PXE-support.patch @@ -0,0 +1,126 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 15 Apr 2015 14:48:30 +0800 +Subject: [PATCH] efinet: UEFI IPv6 PXE support + +When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is +cached in firmware buffer which can be obtained by PXE Base Code protocol. The +network interface can be setup through the parameters in that obtained packet. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 2 ++ + include/grub/efi/api.h | 71 +++++++++++++++++++++++--------------- + 2 files changed, 46 insertions(+), 27 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 8e25680db0..014e5bf980 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -409,6 +409,8 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_print_error (); + if (device && path) + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ if (grub_errno) ++ grub_print_error (); + } + else + { +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 7614b58dca..91ab528e4d 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -1524,31 +1524,6 @@ typedef union + grub_efi_pxe_dhcpv6_packet_t dhcpv6; + } grub_efi_pxe_packet_t; + +-#define GRUB_EFI_PXE_MAX_IPCNT 8 +-#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8 +-#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8 +- +-typedef struct grub_efi_pxe_ip_filter +-{ +- grub_efi_uint8_t filters; +- grub_efi_uint8_t ip_count; +- grub_efi_uint16_t reserved; +- grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; +-} grub_efi_pxe_ip_filter_t; +- +-typedef struct grub_efi_pxe_arp_entry +-{ +- grub_efi_ip_address_t ip_addr; +- grub_efi_mac_address_t mac_addr; +-} grub_efi_pxe_arp_entry_t; +- +-typedef struct grub_efi_pxe_route_entry +-{ +- grub_efi_ip_address_t ip_addr; +- grub_efi_ip_address_t subnet_mask; +- grub_efi_ip_address_t gateway_addr; +-} grub_efi_pxe_route_entry_t; +- + typedef struct grub_efi_pxe_icmp_error + { + grub_efi_uint8_t type; +@@ -1574,6 +1549,48 @@ typedef struct grub_efi_pxe_tftp_error + grub_efi_char8_t error_string[127]; + } grub_efi_pxe_tftp_error_t; + ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 ++typedef struct grub_efi_pxe_ip_filter ++{ ++ grub_efi_uint8_t filters; ++ grub_efi_uint8_t ip_count; ++ grub_efi_uint16_t reserved; ++ grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT]; ++} grub_efi_pxe_ip_filter_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_mac_address_t mac_addr; ++} grub_efi_pxe_arp_entry_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ grub_efi_pxe_ip_address_t gw_addr; ++} grub_efi_pxe_route_entry_t; ++ ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 ++ + typedef struct grub_efi_pxe_mode + { + grub_efi_boolean_t started; +@@ -1605,9 +1622,9 @@ typedef struct grub_efi_pxe_mode + grub_efi_pxe_packet_t pxe_bis_reply; + grub_efi_pxe_ip_filter_t ip_filter; + grub_efi_uint32_t arp_cache_entries; +- grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES]; ++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; + grub_efi_uint32_t route_table_entries; +- grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES]; ++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; + grub_efi_pxe_icmp_error_t icmp_error; + grub_efi_pxe_tftp_error_t tftp_error; + } grub_efi_pxe_mode_t; diff --git a/0075-efinet-UEFI-IPv6-PXE-support.patch b/0075-efinet-UEFI-IPv6-PXE-support.patch deleted file mode 100644 index 988c178..0000000 --- a/0075-efinet-UEFI-IPv6-PXE-support.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Wed, 15 Apr 2015 14:48:30 +0800 -Subject: [PATCH] efinet: UEFI IPv6 PXE support - -When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is -cached in firmware buffer which can be obtained by PXE Base Code protocol. The -network interface can be setup through the parameters in that obtained packet. - -Signed-off-by: Michael Chang -Signed-off-by: Ken Lin ---- - grub-core/net/drivers/efi/efinet.c | 2 ++ - include/grub/efi/api.h | 71 +++++++++++++++++++++++--------------- - 2 files changed, 46 insertions(+), 27 deletions(-) - -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index 8e25680db0..014e5bf980 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -409,6 +409,8 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - grub_print_error (); - if (device && path) - grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); -+ if (grub_errno) -+ grub_print_error (); - } - else - { -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index 7614b58dca..91ab528e4d 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -1524,31 +1524,6 @@ typedef union - grub_efi_pxe_dhcpv6_packet_t dhcpv6; - } grub_efi_pxe_packet_t; - --#define GRUB_EFI_PXE_MAX_IPCNT 8 --#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8 --#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8 -- --typedef struct grub_efi_pxe_ip_filter --{ -- grub_efi_uint8_t filters; -- grub_efi_uint8_t ip_count; -- grub_efi_uint16_t reserved; -- grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; --} grub_efi_pxe_ip_filter_t; -- --typedef struct grub_efi_pxe_arp_entry --{ -- grub_efi_ip_address_t ip_addr; -- grub_efi_mac_address_t mac_addr; --} grub_efi_pxe_arp_entry_t; -- --typedef struct grub_efi_pxe_route_entry --{ -- grub_efi_ip_address_t ip_addr; -- grub_efi_ip_address_t subnet_mask; -- grub_efi_ip_address_t gateway_addr; --} grub_efi_pxe_route_entry_t; -- - typedef struct grub_efi_pxe_icmp_error - { - grub_efi_uint8_t type; -@@ -1574,6 +1549,48 @@ typedef struct grub_efi_pxe_tftp_error - grub_efi_char8_t error_string[127]; - } grub_efi_pxe_tftp_error_t; - -+typedef struct { -+ grub_uint8_t addr[4]; -+} grub_efi_pxe_ipv4_address_t; -+ -+typedef struct { -+ grub_uint8_t addr[16]; -+} grub_efi_pxe_ipv6_address_t; -+ -+typedef struct { -+ grub_uint8_t addr[32]; -+} grub_efi_pxe_mac_address_t; -+ -+typedef union { -+ grub_uint32_t addr[4]; -+ grub_efi_pxe_ipv4_address_t v4; -+ grub_efi_pxe_ipv6_address_t v6; -+} grub_efi_pxe_ip_address_t; -+ -+#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 -+typedef struct grub_efi_pxe_ip_filter -+{ -+ grub_efi_uint8_t filters; -+ grub_efi_uint8_t ip_count; -+ grub_efi_uint16_t reserved; -+ grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT]; -+} grub_efi_pxe_ip_filter_t; -+ -+typedef struct { -+ grub_efi_pxe_ip_address_t ip_addr; -+ grub_efi_pxe_mac_address_t mac_addr; -+} grub_efi_pxe_arp_entry_t; -+ -+typedef struct { -+ grub_efi_pxe_ip_address_t ip_addr; -+ grub_efi_pxe_ip_address_t subnet_mask; -+ grub_efi_pxe_ip_address_t gw_addr; -+} grub_efi_pxe_route_entry_t; -+ -+ -+#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 -+#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 -+ - typedef struct grub_efi_pxe_mode - { - grub_efi_boolean_t started; -@@ -1605,9 +1622,9 @@ typedef struct grub_efi_pxe_mode - grub_efi_pxe_packet_t pxe_bis_reply; - grub_efi_pxe_ip_filter_t ip_filter; - grub_efi_uint32_t arp_cache_entries; -- grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES]; -+ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; - grub_efi_uint32_t route_table_entries; -- grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES]; -+ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; - grub_efi_pxe_icmp_error_t icmp_error; - grub_efi_pxe_tftp_error_t tftp_error; - } grub_efi_pxe_mode_t; diff --git a/0075-grub.texi-Add-net_bootp6-doument.patch b/0075-grub.texi-Add-net_bootp6-doument.patch new file mode 100644 index 0000000..b42e09b --- /dev/null +++ b/0075-grub.texi-Add-net_bootp6-doument.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 5 May 2015 14:19:24 +0800 +Subject: [PATCH] grub.texi: Add net_bootp6 doument + +Update grub documentation for net_bootp6 command. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + docs/grub.texi | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 0615d0ed97..04ed6ac1f0 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5487,6 +5487,7 @@ This command is only available on AArch64 systems. + * net_add_dns:: Add a DNS server + * net_add_route:: Add routing entry + * net_bootp:: Perform a bootp/DHCP autoconfiguration ++* net_bootp6:: Perform a DHCPv6 autoconfiguration + * net_del_addr:: Remove IP address from interface + * net_del_dns:: Remove a DNS server + * net_del_route:: Remove a route entry +@@ -5611,6 +5612,22 @@ Sets environment variable @samp{net_}@var{}@samp{_boot_file} + + @end deffn + ++@node net_bootp6 ++@subsection net_bootp6 ++ ++@deffn Command net_bootp6 [@var{card}] ++Perform configuration of @var{card} using DHCPv6 protocol. If no card name is ++specified, try to configure all existing cards. If configuration was ++successful, interface with name @var{card}@samp{:dhcp6} and configured address ++is added to @var{card}. ++ ++@table @samp ++@item 1 (Domain Name Server) ++Adds all servers from option value to the list of servers used during name ++resolution. ++@end table ++ ++@end deffn + + @node net_get_dhcp_option + @subsection net_get_dhcp_option diff --git a/0076-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch b/0076-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch new file mode 100644 index 0000000..abff9eb --- /dev/null +++ b/0076-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 10 Jul 2019 23:58:28 +0200 +Subject: [PATCH] bootp: Add processing DHCPACK packet from HTTP Boot + +The vendor class identifier with the string "HTTPClient" is used to denote the +packet as responding to HTTP boot request. In DHCP4 config, the filename for +HTTP boot is the URL of the boot file while for PXE boot it is the path to the +boot file. As a consequence, the next-server becomes obseleted because the HTTP +URL already contains the server address for the boot file. For DHCP6 config, +there's no difference definition in existing config as dhcp6.bootfile-url can +be used to specify URL for both HTTP and PXE boot file. + +This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK +packet by treating it as HTTP format, not as the PXE format. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/bootp.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ + include/grub/net.h | 1 + + 2 files changed, 56 insertions(+) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index fe93b80f1c..8fb8918ae7 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -500,6 +501,60 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (opt && opt_len) + grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len); + ++ opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, &opt_len); ++ if (opt && opt_len) ++ { ++ grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); ++ if (opt && grub_strcmp (opt, "HTTPClient") == 0) ++ { ++ char *proto, *ip, *pa; ++ ++ if (!dissect_url (bp->boot_file, &proto, &ip, &pa)) ++ return inter; ++ ++ grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa)); ++ if (is_def) ++ { ++ grub_net_default_server = grub_strdup (ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++ if (device && !*device) ++ { ++ *device = grub_xasprintf ("%s,%s", proto, ip); ++ grub_print_error (); ++ } ++ if (path) ++ { ++ *path = grub_strdup (pa); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ grub_net_add_ipv4_local (inter, mask); ++ inter->dhcp_ack = grub_malloc (size); ++ if (inter->dhcp_ack) ++ { ++ grub_memcpy (inter->dhcp_ack, bp, size); ++ inter->dhcp_acklen = size; ++ } ++ else ++ grub_errno = GRUB_ERR_NONE; ++ ++ grub_free (proto); ++ grub_free (ip); ++ grub_free (pa); ++ return inter; ++ } ++ } ++ + opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len); + if (opt && opt_len) + grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len); +diff --git a/include/grub/net.h b/include/grub/net.h +index 543251f727..42af7de250 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -531,6 +531,7 @@ enum + GRUB_NET_DHCP_MESSAGE_TYPE = 53, + GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, ++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60, + GRUB_NET_BOOTP_CLIENT_ID = 61, + GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, + GRUB_NET_DHCP_BOOTFILE_NAME = 67, diff --git a/0076-grub.texi-Add-net_bootp6-doument.patch b/0076-grub.texi-Add-net_bootp6-doument.patch deleted file mode 100644 index b42e09b..0000000 --- a/0076-grub.texi-Add-net_bootp6-doument.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Tue, 5 May 2015 14:19:24 +0800 -Subject: [PATCH] grub.texi: Add net_bootp6 doument - -Update grub documentation for net_bootp6 command. - -Signed-off-by: Michael Chang -Signed-off-by: Ken Lin ---- - docs/grub.texi | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/docs/grub.texi b/docs/grub.texi -index 0615d0ed97..04ed6ac1f0 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -5487,6 +5487,7 @@ This command is only available on AArch64 systems. - * net_add_dns:: Add a DNS server - * net_add_route:: Add routing entry - * net_bootp:: Perform a bootp/DHCP autoconfiguration -+* net_bootp6:: Perform a DHCPv6 autoconfiguration - * net_del_addr:: Remove IP address from interface - * net_del_dns:: Remove a DNS server - * net_del_route:: Remove a route entry -@@ -5611,6 +5612,22 @@ Sets environment variable @samp{net_}@var{}@samp{_boot_file} - - @end deffn - -+@node net_bootp6 -+@subsection net_bootp6 -+ -+@deffn Command net_bootp6 [@var{card}] -+Perform configuration of @var{card} using DHCPv6 protocol. If no card name is -+specified, try to configure all existing cards. If configuration was -+successful, interface with name @var{card}@samp{:dhcp6} and configured address -+is added to @var{card}. -+ -+@table @samp -+@item 1 (Domain Name Server) -+Adds all servers from option value to the list of servers used during name -+resolution. -+@end table -+ -+@end deffn - - @node net_get_dhcp_option - @subsection net_get_dhcp_option diff --git a/0077-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch b/0077-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch deleted file mode 100644 index abff9eb..0000000 --- a/0077-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Wed, 10 Jul 2019 23:58:28 +0200 -Subject: [PATCH] bootp: Add processing DHCPACK packet from HTTP Boot - -The vendor class identifier with the string "HTTPClient" is used to denote the -packet as responding to HTTP boot request. In DHCP4 config, the filename for -HTTP boot is the URL of the boot file while for PXE boot it is the path to the -boot file. As a consequence, the next-server becomes obseleted because the HTTP -URL already contains the server address for the boot file. For DHCP6 config, -there's no difference definition in existing config as dhcp6.bootfile-url can -be used to specify URL for both HTTP and PXE boot file. - -This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK -packet by treating it as HTTP format, not as the PXE format. - -Signed-off-by: Michael Chang -Signed-off-by: Ken Lin ---- - grub-core/net/bootp.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ - include/grub/net.h | 1 + - 2 files changed, 56 insertions(+) - -diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c -index fe93b80f1c..8fb8918ae7 100644 ---- a/grub-core/net/bootp.c -+++ b/grub-core/net/bootp.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -500,6 +501,60 @@ grub_net_configure_by_dhcp_ack (const char *name, - if (opt && opt_len) - grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len); - -+ opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, &opt_len); -+ if (opt && opt_len) -+ { -+ grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); -+ if (opt && grub_strcmp (opt, "HTTPClient") == 0) -+ { -+ char *proto, *ip, *pa; -+ -+ if (!dissect_url (bp->boot_file, &proto, &ip, &pa)) -+ return inter; -+ -+ grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa)); -+ if (is_def) -+ { -+ grub_net_default_server = grub_strdup (ip); -+ grub_env_set ("net_default_interface", name); -+ grub_env_export ("net_default_interface"); -+ } -+ if (device && !*device) -+ { -+ *device = grub_xasprintf ("%s,%s", proto, ip); -+ grub_print_error (); -+ } -+ if (path) -+ { -+ *path = grub_strdup (pa); -+ grub_print_error (); -+ if (*path) -+ { -+ char *slash; -+ slash = grub_strrchr (*path, '/'); -+ if (slash) -+ *slash = 0; -+ else -+ **path = 0; -+ } -+ } -+ grub_net_add_ipv4_local (inter, mask); -+ inter->dhcp_ack = grub_malloc (size); -+ if (inter->dhcp_ack) -+ { -+ grub_memcpy (inter->dhcp_ack, bp, size); -+ inter->dhcp_acklen = size; -+ } -+ else -+ grub_errno = GRUB_ERR_NONE; -+ -+ grub_free (proto); -+ grub_free (ip); -+ grub_free (pa); -+ return inter; -+ } -+ } -+ - opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len); - if (opt && opt_len) - grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len); -diff --git a/include/grub/net.h b/include/grub/net.h -index 543251f727..42af7de250 100644 ---- a/include/grub/net.h -+++ b/include/grub/net.h -@@ -531,6 +531,7 @@ enum - GRUB_NET_DHCP_MESSAGE_TYPE = 53, - GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, - GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, -+ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60, - GRUB_NET_BOOTP_CLIENT_ID = 61, - GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, - GRUB_NET_DHCP_BOOTFILE_NAME = 67, diff --git a/0077-efinet-Setting-network-from-UEFI-device-path.patch b/0077-efinet-Setting-network-from-UEFI-device-path.patch new file mode 100644 index 0000000..f4faf27 --- /dev/null +++ b/0077-efinet-Setting-network-from-UEFI-device-path.patch @@ -0,0 +1,405 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Sun, 10 Jul 2016 23:46:31 +0800 +Subject: [PATCH] efinet: Setting network from UEFI device path + +The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no +longer provided for HTTP Boot. Instead, we have to get the HTTP boot +information from the device path nodes defined in following UEFI Specification +sections. + + 9.3.5.12 IPv4 Device Path + 9.3.5.13 IPv6 Device Path + 9.3.5.23 Uniform Resource Identifiers (URI) Device Path + +This patch basically does: + +include/grub/efi/api.h: +Add new structure of Uniform Resource Identifiers (URI) Device Path + +grub-core/net/drivers/efi/efinet.c: +Check if PXE Base Code is available, if not it will try to obtain the netboot +information from the device path where the image booted from. The DHCPACK +packet is recoverd from the information in device patch and feed into the same +DHCP packet processing functions to ensure the network interface is setting up +the same way it used to be. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 284 +++++++++++++++++++++++++++++++++++-- + include/grub/efi/api.h | 11 ++ + 2 files changed, 280 insertions(+), 15 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 014e5bf980..8171ecaa5e 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -331,6 +332,227 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static struct grub_net_buff * ++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) ++{ ++ grub_efi_uint16_t uri_len; ++ grub_efi_device_path_t *ldp, *ddp; ++ grub_efi_uri_device_path_t *uri_dp; ++ struct grub_net_buff *nb; ++ grub_err_t err; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ if (!ddp) ++ return NULL; ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0; ++ ++ if (!uri_len) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_dp = (grub_efi_uri_device_path_t *) ldp; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ nb = grub_netbuff_alloc (512); ++ if (!nb) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; ++ struct grub_net_bootp_packet *bp; ++ grub_uint8_t *ptr; ++ ++ bp = (struct grub_net_bootp_packet *) nb->tail; ++ err = grub_netbuff_put (nb, sizeof (*bp) + 4); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ if (sizeof(bp->boot_file) < uri_len) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len); ++ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip)); ++ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip)); ++ ++ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0; ++ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1; ++ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2; ++ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_NETMASK; ++ *ptr++ = sizeof (ipv4->subnet_mask); ++ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_ROUTER; ++ *ptr++ = sizeof (ipv4->gateway_ip_address); ++ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER; ++ *ptr++ = sizeof ("HTTPClient") - 1; ++ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr = GRUB_NET_BOOTP_END; ++ *use_ipv6 = 0; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp; ++ bp->hw_type = mac->if_type; ++ bp->hw_len = sizeof (bp->mac_addr); ++ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len); ++ } ++ } ++ else ++ { ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp; ++ ++ struct grub_net_dhcp6_packet *d6p; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_option_iana *iana; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ ++ d6p = (struct grub_net_dhcp6_packet *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*d6p)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ d6p->message_type = GRUB_NET_DHCP6_REPLY; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr)); ++ ++ err = grub_netbuff_put (nb, sizeof(*iana)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr)); ++ ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*iaaddr)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address)); ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL); ++ opt->len = grub_cpu_to_be16 (uri_len); ++ grub_memcpy (opt->data, uri_dp->uri, uri_len); ++ ++ *use_ipv6 = 1; ++ } ++ ++ grub_free (ddp); ++ return nb; ++} ++ + static void + grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) +@@ -346,7 +568,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + { + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; +- struct grub_efi_pxe_mode *pxe_mode; ++ struct grub_efi_pxe_mode *pxe_mode = NULL; ++ grub_uint8_t *packet_buf; ++ grub_size_t packet_bufsz ; ++ int ipv6; ++ struct grub_net_buff *nb = NULL; + + if (card->driver != &efidriver) + continue; +@@ -370,11 +596,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + */ + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE +- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); + if (!dup_dp) + continue; ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ + dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +@@ -387,23 +623,37 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +- if (! pxe) +- continue; ++ if (!pxe) ++ { ++ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6); ++ if (!nb) ++ { ++ grub_print_error (); ++ continue; ++ } ++ packet_buf = nb->head; ++ packet_bufsz = nb->tail - nb->head; ++ } ++ else ++ { ++ pxe_mode = pxe->mode; ++ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack; ++ packet_bufsz = sizeof (pxe_mode->dhcp_ack); ++ ipv6 = pxe_mode->using_ipv6; ++ } + +- pxe_mode = pxe->mode; +- if (pxe_mode->using_ipv6) ++ if (ipv6) + { + grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); +- grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", +- pxe_mode->dhcp_ack_received ? "yes" : "no", +- pxe_mode->dhcp_ack_received ? "" : " cannot continue"); +- if (!pxe_mode->dhcp_ack_received) +- continue; ++ if (pxe_mode) ++ grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", ++ pxe_mode->dhcp_ack_received ? "yes" : "no", ++ pxe_mode->dhcp_ack_received ? "" : " cannot continue"); + + grub_net_configure_by_dhcpv6_reply (card->name, card, 0, + (struct grub_net_dhcp6_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + if (grub_errno) + grub_print_error (); +@@ -417,11 +667,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_dprintf ("efinet", "using ipv4 and dhcp\n"); + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + } ++ ++ if (nb) ++ grub_netbuff_free (nb); ++ + return; + } + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 91ab528e4d..4a51667adb 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -864,6 +864,8 @@ struct grub_efi_ipv4_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_ipv4_address_t gateway_ip_address; ++ grub_efi_ipv4_address_t subnet_mask; + } GRUB_PACKED; + typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; + +@@ -918,6 +920,15 @@ struct grub_efi_sata_device_path + } GRUB_PACKED; + typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t; + ++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24 ++ ++struct grub_efi_uri_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t uri[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ diff --git a/0078-efinet-Setting-DNS-server-from-UEFI-protocol.patch b/0078-efinet-Setting-DNS-server-from-UEFI-protocol.patch new file mode 100644 index 0000000..2d92ff0 --- /dev/null +++ b/0078-efinet-Setting-DNS-server-from-UEFI-protocol.patch @@ -0,0 +1,336 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 14 Jul 2016 17:48:45 +0800 +Subject: [PATCH] efinet: Setting DNS server from UEFI protocol + +In the URI device path node, any name rahter than address can be used for +looking up the resources so that DNS service become needed to get answer of the +name's address. Unfortunately the DNS is not defined in any of the device path +nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL +to obtain it. + +These two protcols are defined the sections of UEFI specification. + + 27.5 EFI IPv4 Configuration II Protocol + 27.7 EFI IPv6 Configuration Protocol + +include/grub/efi/api.h: +Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and +EFI_IP6_CONFIG_PROTOCOL. + +grub-core/net/drivers/efi/efinet.c: +Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list +of DNS server address for IPv4 and IPv6 respectively. The address of DNS +servers is structured into DHCPACK packet and feed into the same DHCP packet +processing functions to ensure the network interface is setting up the same way +it used to be. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 75 +++++++++++++++++ + 2 files changed, 238 insertions(+) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 8171ecaa5e..715a6168d7 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -33,6 +33,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + /* GUID. */ + static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; + static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; + + static grub_err_t + send_card_buffer (struct grub_net_card *dev, +@@ -332,6 +334,125 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static grub_efi_ipv4_address_t * ++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_protocol_t *conf; ++ grub_efi_ipv4_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t); ++ return addrs; ++} ++ ++static grub_efi_ipv6_address_t * ++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_protocol_t *conf; ++ grub_efi_ipv6_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t); ++ return addrs; ++} ++ + static struct grub_net_buff * + grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) + { +@@ -390,6 +511,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; + struct grub_net_bootp_packet *bp; + grub_uint8_t *ptr; ++ grub_efi_ipv4_address_t *dns; ++ grub_efi_uintn_t num_dns; + + bp = (struct grub_net_bootp_packet *) nb->tail; + err = grub_netbuff_put (nb, sizeof (*bp) + 4); +@@ -451,6 +574,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + *ptr++ = sizeof ("HTTPClient") - 1; + grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); + ++ dns = grub_dns_server_ip4_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, size_dns + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_DNS; ++ *ptr++ = size_dns; ++ grub_memcpy (ptr, dns, size_dns); ++ grub_free (dns); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, 1); + if (err) +@@ -483,6 +625,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + struct grub_net_dhcp6_option *opt; + struct grub_net_dhcp6_option_iana *iana; + struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ grub_efi_ipv6_address_t *dns; ++ grub_efi_uintn_t num_dns; + + d6p = (struct grub_net_dhcp6_packet *)nb->tail; + err = grub_netbuff_put (nb, sizeof(*d6p)); +@@ -546,6 +690,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + opt->len = grub_cpu_to_be16 (uri_len); + grub_memcpy (opt->data, uri_dp->uri, uri_len); + ++ dns = grub_dns_server_ip6_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + size_dns); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS); ++ opt->len = grub_cpu_to_be16 (size_dns); ++ grub_memcpy (opt->data, dns, size_dns); ++ grub_free (dns); ++ } ++ + *use_ipv6 = 1; + } + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 4a51667adb..0b490195ad 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -352,6 +352,15 @@ + #define GRUB_EFI_RNG_PROTOCOL_GUID \ + { 0x3152bca5, 0xeade, 0x433d, \ + { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ ++ ++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \ ++ { 0x5b446ed1, 0xe30b, 0x4faa, \ ++ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ ++ } ++ ++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \ ++ { 0x937fe521, 0x95ae, 0x4d1a, \ ++ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ + } + + struct grub_efi_sal_system_table +@@ -1883,6 +1892,72 @@ struct grub_efi_rng_protocol + }; + typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; + ++enum grub_efi_ip4_config2_data_type { ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t; ++ ++struct grub_efi_ip4_config2_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; ++ ++enum grub_efi_ip6_config_data_type { ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t; ++ ++struct grub_efi_ip6_config_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) diff --git a/0078-efinet-Setting-network-from-UEFI-device-path.patch b/0078-efinet-Setting-network-from-UEFI-device-path.patch deleted file mode 100644 index f4faf27..0000000 --- a/0078-efinet-Setting-network-from-UEFI-device-path.patch +++ /dev/null @@ -1,405 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Sun, 10 Jul 2016 23:46:31 +0800 -Subject: [PATCH] efinet: Setting network from UEFI device path - -The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no -longer provided for HTTP Boot. Instead, we have to get the HTTP boot -information from the device path nodes defined in following UEFI Specification -sections. - - 9.3.5.12 IPv4 Device Path - 9.3.5.13 IPv6 Device Path - 9.3.5.23 Uniform Resource Identifiers (URI) Device Path - -This patch basically does: - -include/grub/efi/api.h: -Add new structure of Uniform Resource Identifiers (URI) Device Path - -grub-core/net/drivers/efi/efinet.c: -Check if PXE Base Code is available, if not it will try to obtain the netboot -information from the device path where the image booted from. The DHCPACK -packet is recoverd from the information in device patch and feed into the same -DHCP packet processing functions to ensure the network interface is setting up -the same way it used to be. - -Signed-off-by: Michael Chang -Signed-off-by: Ken Lin ---- - grub-core/net/drivers/efi/efinet.c | 284 +++++++++++++++++++++++++++++++++++-- - include/grub/efi/api.h | 11 ++ - 2 files changed, 280 insertions(+), 15 deletions(-) - -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index 014e5bf980..8171ecaa5e 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -331,6 +332,227 @@ grub_efinet_findcards (void) - grub_free (handles); - } - -+static struct grub_net_buff * -+grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) -+{ -+ grub_efi_uint16_t uri_len; -+ grub_efi_device_path_t *ldp, *ddp; -+ grub_efi_uri_device_path_t *uri_dp; -+ struct grub_net_buff *nb; -+ grub_err_t err; -+ -+ ddp = grub_efi_duplicate_device_path (dp); -+ if (!ddp) -+ return NULL; -+ -+ ldp = grub_efi_find_last_device_path (ddp); -+ -+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE -+ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) -+ { -+ grub_free (ddp); -+ return NULL; -+ } -+ -+ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0; -+ -+ if (!uri_len) -+ { -+ grub_free (ddp); -+ return NULL; -+ } -+ -+ uri_dp = (grub_efi_uri_device_path_t *) ldp; -+ -+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; -+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -+ ldp->length = sizeof (*ldp); -+ -+ ldp = grub_efi_find_last_device_path (ddp); -+ -+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE -+ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE -+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) -+ { -+ grub_free (ddp); -+ return NULL; -+ } -+ -+ nb = grub_netbuff_alloc (512); -+ if (!nb) -+ { -+ grub_free (ddp); -+ return NULL; -+ } -+ -+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) -+ { -+ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; -+ struct grub_net_bootp_packet *bp; -+ grub_uint8_t *ptr; -+ -+ bp = (struct grub_net_bootp_packet *) nb->tail; -+ err = grub_netbuff_put (nb, sizeof (*bp) + 4); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ -+ if (sizeof(bp->boot_file) < uri_len) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len); -+ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip)); -+ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip)); -+ -+ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0; -+ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1; -+ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2; -+ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3; -+ -+ ptr = nb->tail; -+ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ *ptr++ = GRUB_NET_BOOTP_NETMASK; -+ *ptr++ = sizeof (ipv4->subnet_mask); -+ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask)); -+ -+ ptr = nb->tail; -+ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ *ptr++ = GRUB_NET_BOOTP_ROUTER; -+ *ptr++ = sizeof (ipv4->gateway_ip_address); -+ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address)); -+ -+ ptr = nb->tail; -+ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER; -+ *ptr++ = sizeof ("HTTPClient") - 1; -+ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); -+ -+ ptr = nb->tail; -+ err = grub_netbuff_put (nb, 1); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ *ptr = GRUB_NET_BOOTP_END; -+ *use_ipv6 = 0; -+ -+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; -+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -+ ldp->length = sizeof (*ldp); -+ ldp = grub_efi_find_last_device_path (ddp); -+ -+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) -+ { -+ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp; -+ bp->hw_type = mac->if_type; -+ bp->hw_len = sizeof (bp->mac_addr); -+ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len); -+ } -+ } -+ else -+ { -+ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp; -+ -+ struct grub_net_dhcp6_packet *d6p; -+ struct grub_net_dhcp6_option *opt; -+ struct grub_net_dhcp6_option_iana *iana; -+ struct grub_net_dhcp6_option_iaaddr *iaaddr; -+ -+ d6p = (struct grub_net_dhcp6_packet *)nb->tail; -+ err = grub_netbuff_put (nb, sizeof(*d6p)); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ d6p->message_type = GRUB_NET_DHCP6_REPLY; -+ -+ opt = (struct grub_net_dhcp6_option *)nb->tail; -+ err = grub_netbuff_put (nb, sizeof(*opt)); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); -+ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr)); -+ -+ err = grub_netbuff_put (nb, sizeof(*iana)); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ -+ opt = (struct grub_net_dhcp6_option *)nb->tail; -+ err = grub_netbuff_put (nb, sizeof(*opt)); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); -+ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr)); -+ -+ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail; -+ err = grub_netbuff_put (nb, sizeof(*iaaddr)); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address)); -+ -+ opt = (struct grub_net_dhcp6_option *)nb->tail; -+ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL); -+ opt->len = grub_cpu_to_be16 (uri_len); -+ grub_memcpy (opt->data, uri_dp->uri, uri_len); -+ -+ *use_ipv6 = 1; -+ } -+ -+ grub_free (ddp); -+ return nb; -+} -+ - static void - grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - char **path) -@@ -346,7 +568,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - { - grub_efi_device_path_t *cdp; - struct grub_efi_pxe *pxe; -- struct grub_efi_pxe_mode *pxe_mode; -+ struct grub_efi_pxe_mode *pxe_mode = NULL; -+ grub_uint8_t *packet_buf; -+ grub_size_t packet_bufsz ; -+ int ipv6; -+ struct grub_net_buff *nb = NULL; - - if (card->driver != &efidriver) - continue; -@@ -370,11 +596,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - */ - if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE - || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE -- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) -+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE -+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) - continue; - dup_dp = grub_efi_duplicate_device_path (dp); - if (!dup_dp) - continue; -+ -+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) -+ { -+ dup_ldp = grub_efi_find_last_device_path (dup_dp); -+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; -+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -+ dup_ldp->length = sizeof (*dup_ldp); -+ } -+ - dup_ldp = grub_efi_find_last_device_path (dup_dp); - dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; - dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -@@ -387,23 +623,37 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - - pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, - GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -- if (! pxe) -- continue; -+ if (!pxe) -+ { -+ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6); -+ if (!nb) -+ { -+ grub_print_error (); -+ continue; -+ } -+ packet_buf = nb->head; -+ packet_bufsz = nb->tail - nb->head; -+ } -+ else -+ { -+ pxe_mode = pxe->mode; -+ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack; -+ packet_bufsz = sizeof (pxe_mode->dhcp_ack); -+ ipv6 = pxe_mode->using_ipv6; -+ } - -- pxe_mode = pxe->mode; -- if (pxe_mode->using_ipv6) -+ if (ipv6) - { - grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); -- grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", -- pxe_mode->dhcp_ack_received ? "yes" : "no", -- pxe_mode->dhcp_ack_received ? "" : " cannot continue"); -- if (!pxe_mode->dhcp_ack_received) -- continue; -+ if (pxe_mode) -+ grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", -+ pxe_mode->dhcp_ack_received ? "yes" : "no", -+ pxe_mode->dhcp_ack_received ? "" : " cannot continue"); - - grub_net_configure_by_dhcpv6_reply (card->name, card, 0, - (struct grub_net_dhcp6_packet *) -- &pxe_mode->dhcp_ack, -- sizeof (pxe_mode->dhcp_ack), -+ packet_buf, -+ packet_bufsz, - 1, device, path); - if (grub_errno) - grub_print_error (); -@@ -417,11 +667,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - grub_dprintf ("efinet", "using ipv4 and dhcp\n"); - grub_net_configure_by_dhcp_ack (card->name, card, 0, - (struct grub_net_bootp_packet *) -- &pxe_mode->dhcp_ack, -- sizeof (pxe_mode->dhcp_ack), -+ packet_buf, -+ packet_bufsz, - 1, device, path); - grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); - } -+ -+ if (nb) -+ grub_netbuff_free (nb); -+ - return; - } - } -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index 91ab528e4d..4a51667adb 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -864,6 +864,8 @@ struct grub_efi_ipv4_device_path - grub_efi_uint16_t remote_port; - grub_efi_uint16_t protocol; - grub_efi_uint8_t static_ip_address; -+ grub_efi_ipv4_address_t gateway_ip_address; -+ grub_efi_ipv4_address_t subnet_mask; - } GRUB_PACKED; - typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; - -@@ -918,6 +920,15 @@ struct grub_efi_sata_device_path - } GRUB_PACKED; - typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t; - -+#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24 -+ -+struct grub_efi_uri_device_path -+{ -+ grub_efi_device_path_t header; -+ grub_efi_uint8_t uri[0]; -+} GRUB_PACKED; -+typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; -+ - #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 - - /* Media Device Path. */ diff --git a/0079-Support-UEFI-networking-protocols.patch b/0079-Support-UEFI-networking-protocols.patch new file mode 100644 index 0000000..740a9f8 --- /dev/null +++ b/0079-Support-UEFI-networking-protocols.patch @@ -0,0 +1,5053 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 22 Feb 2017 14:27:50 +0800 +Subject: [PATCH] Support UEFI networking protocols + +References: fate#320130, bsc#1015589, bsc#1076132 +Patch-Mainline: no + +V1: + * Add preliminary support of UEFI networking protocols + * Support UEFI HTTPS Boot + +V2: + * Workaround http data access in firmware + * Fix DNS device path parsing for efinet device + * Relaxed UEFI Protocol requirement + * Support Intel OPA (Omni-Path Architecture) PXE Boot + +V3: + * Fix bufio in calculating address of next_buf + * Check HTTP respond code + * Use HEAD request method to test before GET + * Finish HTTP transaction in one go + * Fix bsc#1076132 + +Signed-off-by: Michael Chang +[pjones: make efi_netfs not duplicate symbols from efinet] +Signed-off-by: Peter Jones +--- + grub-core/Makefile.core.def | 12 + + grub-core/io/bufio.c | 2 +- + grub-core/kern/efi/efi.c | 96 ++- + grub-core/net/drivers/efi/efinet.c | 27 + + grub-core/net/efi/dhcp.c | 397 ++++++++++ + grub-core/net/efi/efi_netfs.c | 57 ++ + grub-core/net/efi/http.c | 419 +++++++++++ + grub-core/net/efi/ip4_config.c | 398 ++++++++++ + grub-core/net/efi/ip6_config.c | 422 +++++++++++ + grub-core/net/efi/net.c | 1428 ++++++++++++++++++++++++++++++++++++ + grub-core/net/efi/pxe.c | 424 +++++++++++ + grub-core/net/net.c | 74 ++ + util/grub-mknetdir.c | 23 +- + include/grub/efi/api.h | 180 ++++- + include/grub/efi/dhcp.h | 343 +++++++++ + include/grub/efi/http.h | 215 ++++++ + include/grub/net/efi.h | 144 ++++ + 17 files changed, 4620 insertions(+), 41 deletions(-) + create mode 100644 grub-core/net/efi/dhcp.c + create mode 100644 grub-core/net/efi/efi_netfs.c + create mode 100644 grub-core/net/efi/http.c + create mode 100644 grub-core/net/efi/ip4_config.c + create mode 100644 grub-core/net/efi/ip6_config.c + create mode 100644 grub-core/net/efi/net.c + create mode 100644 grub-core/net/efi/pxe.c + create mode 100644 include/grub/efi/dhcp.h + create mode 100644 include/grub/efi/http.h + create mode 100644 include/grub/net/efi.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 4b7c45a7b0..c40170f2dd 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2299,6 +2299,12 @@ module = { + common = hook/datehook.c; + }; + ++module = { ++ name = efi_netfs; ++ common = net/efi/efi_netfs.c; ++ enable = efi; ++}; ++ + module = { + name = net; + common = net/net.c; +@@ -2312,6 +2318,12 @@ module = { + common = net/ethernet.c; + common = net/arp.c; + common = net/netbuff.c; ++ efi = net/efi/net.c; ++ efi = net/efi/http.c; ++ efi = net/efi/pxe.c; ++ efi = net/efi/ip4_config.c; ++ efi = net/efi/ip6_config.c; ++ efi = net/efi/dhcp.c; + }; + + module = { +diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c +index a458c3aca7..1637731535 100644 +--- a/grub-core/io/bufio.c ++++ b/grub-core/io/bufio.c +@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len) + return res; + + /* Need to read some more. */ +- next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1); ++ next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size; + /* Now read between file->offset + res and bufio->buffer_at. */ + if (file->offset + res < next_buf) + { +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index d6a2fb5778..2a446f5031 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -755,7 +755,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + { + grub_efi_ipv4_device_path_t *ipv4 + = (grub_efi_ipv4_device_path_t *) dp; +- grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", ++ grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x", + (unsigned) ipv4->local_ip_address[0], + (unsigned) ipv4->local_ip_address[1], + (unsigned) ipv4->local_ip_address[2], +@@ -768,33 +768,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + (unsigned) ipv4->remote_port, + (unsigned) ipv4->protocol, + (unsigned) ipv4->static_ip_address); ++ if (len == sizeof (*ipv4)) ++ { ++ grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u", ++ (unsigned) ipv4->gateway_ip_address[0], ++ (unsigned) ipv4->gateway_ip_address[1], ++ (unsigned) ipv4->gateway_ip_address[2], ++ (unsigned) ipv4->gateway_ip_address[3], ++ (unsigned) ipv4->subnet_mask[0], ++ (unsigned) ipv4->subnet_mask[1], ++ (unsigned) ipv4->subnet_mask[2], ++ (unsigned) ipv4->subnet_mask[3]); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: + { + grub_efi_ipv6_device_path_t *ipv6 + = (grub_efi_ipv6_device_path_t *) dp; +- grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", +- (unsigned) ipv6->local_ip_address[0], +- (unsigned) ipv6->local_ip_address[1], +- (unsigned) ipv6->local_ip_address[2], +- (unsigned) ipv6->local_ip_address[3], +- (unsigned) ipv6->local_ip_address[4], +- (unsigned) ipv6->local_ip_address[5], +- (unsigned) ipv6->local_ip_address[6], +- (unsigned) ipv6->local_ip_address[7], +- (unsigned) ipv6->remote_ip_address[0], +- (unsigned) ipv6->remote_ip_address[1], +- (unsigned) ipv6->remote_ip_address[2], +- (unsigned) ipv6->remote_ip_address[3], +- (unsigned) ipv6->remote_ip_address[4], +- (unsigned) ipv6->remote_ip_address[5], +- (unsigned) ipv6->remote_ip_address[6], +- (unsigned) ipv6->remote_ip_address[7], ++ grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x", ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]), + (unsigned) ipv6->local_port, + (unsigned) ipv6->remote_port, + (unsigned) ipv6->protocol, + (unsigned) ipv6->static_ip_address); ++ if (len == sizeof (*ipv6)) ++ { ++ grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ++ (unsigned) ipv6->prefix_length, ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7])); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: +@@ -834,6 +861,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + dump_vendor_path ("Messaging", + (grub_efi_vendor_device_path_t *) dp); + break; ++ case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_uri_device_path_t *uri ++ = (grub_efi_uri_device_path_t *) dp; ++ grub_printf ("/URI(%s)", uri->uri); ++ } ++ break; ++ case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_dns_device_path_t *dns ++ = (grub_efi_dns_device_path_t *) dp; ++ if (dns->is_ipv6) ++ { ++ grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)", ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]))); ++ } ++ else ++ { ++ grub_printf ("/DNS(%d.%d.%d.%d)", ++ dns->dns_server_ip[0].v4.addr[0], ++ dns->dns_server_ip[0].v4.addr[1], ++ dns->dns_server_ip[0].v4.addr[2], ++ dns->dns_server_ip[0].v4.addr[3]); ++ } ++ } ++ break; + default: + grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); + break; +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 715a6168d7..e11d759f19 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -491,6 +492,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + + ldp = grub_efi_find_last_device_path (ddp); + ++ /* Skip the DNS Device */ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ } ++ + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) +@@ -760,6 +772,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); +@@ -774,6 +787,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + dup_ldp->length = sizeof (*dup_ldp); + } + ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ + dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +@@ -845,6 +867,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + + GRUB_MOD_INIT(efinet) + { ++ if (grub_efi_net_config) ++ return; ++ + grub_efinet_findcards (); + grub_efi_net_config = grub_efi_net_config_real; + } +@@ -856,5 +881,7 @@ GRUB_MOD_FINI(efinet) + FOR_NET_CARDS_SAFE (card, next) + if (card->driver == &efidriver) + grub_net_card_unregister (card); ++ ++ grub_efi_net_config = NULL; + } + +diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c +new file mode 100644 +index 0000000000..dbef63d8c0 +--- /dev/null ++++ b/grub-core/net/efi/dhcp.c +@@ -0,0 +1,397 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef GRUB_EFI_NET_DEBUG ++static void ++dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode) ++{ ++ switch (mode->state) ++ { ++ case GRUB_EFI_DHCP4_STOPPED: ++ grub_printf ("STATE: STOPPED\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT: ++ grub_printf ("STATE: INIT\n"); ++ break; ++ case GRUB_EFI_DHCP4_SELECTING: ++ grub_printf ("STATE: SELECTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REQUESTING: ++ grub_printf ("STATE: REQUESTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_BOUND: ++ grub_printf ("STATE: BOUND\n"); ++ break; ++ case GRUB_EFI_DHCP4_RENEWING: ++ grub_printf ("STATE: RENEWING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBINDING: ++ grub_printf ("STATE: REBINDING\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT_REBOOT: ++ grub_printf ("STATE: INIT_REBOOT\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBOOTING: ++ grub_printf ("STATE: REBOOTING\n"); ++ break; ++ default: ++ grub_printf ("STATE: UNKNOWN\n"); ++ break; ++ } ++ ++ grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n", ++ mode->client_address[0], ++ mode->client_address[1], ++ mode->client_address[2], ++ mode->client_address[3]); ++ grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n", ++ mode->server_address[0], ++ mode->server_address[1], ++ mode->server_address[2], ++ mode->server_address[3]); ++ grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n", ++ mode->subnet_mask[0], ++ mode->subnet_mask[1], ++ mode->subnet_mask[2], ++ mode->subnet_mask[3]); ++ grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n", ++ mode->router_address[0], ++ mode->router_address[1], ++ mode->router_address[2], ++ mode->router_address[3]); ++} ++#endif ++ ++static grub_efi_ipv4_address_t * ++grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet) ++{ ++ grub_efi_dhcp4_packet_option_t **option_list; ++ grub_efi_status_t status; ++ grub_efi_uint32_t option_count = 0; ++ grub_efi_uint32_t i; ++ ++ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL); ++ ++ if (status != GRUB_EFI_BUFFER_TOO_SMALL) ++ return NULL; ++ ++ option_list = grub_malloc (option_count * sizeof(*option_list)); ++ if (!option_list) ++ return NULL; ++ ++ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ ++ for (i = 0; i < option_count; ++i) ++ { ++ if (option_list[i]->op_code == 6) ++ { ++ grub_efi_ipv4_address_t *dns_address; ++ ++ if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0)) ++ continue; ++ ++ /* We only contact primary dns */ ++ dns_address = grub_malloc (sizeof (*dns_address)); ++ if (!dns_address) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address)); ++ grub_free (option_list); ++ return dns_address; ++ } ++ } ++ ++ grub_free (option_list); ++ return NULL; ++} ++ ++#if 0 ++/* Somehow this doesn't work ... */ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_pxe_t *pxe = dev->ip4_pxe; ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ grub_efi_status_t status; ++ ++ if (!mode->started) ++ { ++ status = efi_call_2 (pxe->start, pxe, 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++ status = efi_call_2 (pxe->dhcp, pxe, 0); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ dev->prefer_ip6 = 0; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++#endif ++ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ grub_efi_status_t status; ++ grub_efi_dhcp4_mode_data_t mode; ++ grub_efi_dhcp4_config_data_t config; ++ grub_efi_dhcp4_packet_option_t *options; ++ grub_efi_ipv4_address_t *dns_address; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_net_ip_address_t ip_addr; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0) ++ continue; ++ ++ grub_memset (&config, 0, sizeof(config)); ++ ++ config.option_count = 1; ++ options = grub_malloc (sizeof(*options) + 2); ++ /* Parameter request list */ ++ options->op_code = 55; ++ options->length = 3; ++ /* subnet mask */ ++ options->data[0] = 1; ++ /* router */ ++ options->data[1] = 3; ++ /* DNS */ ++ options->data[2] = 6; ++ config.option_list = &options; ++ ++ /* FIXME: What if the dhcp has bounded */ ++ status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config); ++ grub_free (options); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++#ifdef GRUB_EFI_NET_DEBUG ++ dhcp4_mode_print (&mode); ++#endif ++ ++ for (inf = netdev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 0) ++ break; ++ ++ grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", netdev->card_name); ++ ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4)); ++ efi_net_interface_set_gateway (inf, &ip_addr); ++ ++ dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet); ++ if (dns_address) ++ efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address); ++ ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++static grub_err_t ++grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_uint32_t ia_id; ++ ++ for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++) ++ { ++ grub_efi_dhcp6_config_data_t config; ++ grub_efi_dhcp6_packet_option_t *option_list[1]; ++ grub_efi_dhcp6_packet_option_t *opt; ++ grub_efi_status_t status; ++ grub_efi_dhcp6_mode_data_t mode; ++ grub_efi_dhcp6_retransmission_t retrans; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0) ++ continue; ++ ++ opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_ORO 6 ++ ++ opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO); ++ opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59 ++#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23 ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL)); ++ grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t), ++ grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)); ++ ++ option_list[0] = opt; ++ retrans.irt = 4; ++ retrans.mrc = 4; ++ retrans.mrt = 32; ++ retrans.mrd = 60; ++ ++ config.dhcp6_callback = NULL; ++ config.callback_context = NULL; ++ config.option_count = 1; ++ config.option_list = option_list; ++ config.ia_descriptor.ia_id = ia_id; ++ config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA; ++ config.ia_info_event = NULL; ++ config.reconfigure_accept = 0; ++ config.rapid_commit = 0; ++ config.solicit_retransmission = &retrans; ++ ++ status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config); ++ grub_free (opt); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 configure failed, %d\n", (int)status); ++ continue; ++ } ++ status = efi_call_1 (dev->dhcp6->start, dev->dhcp6); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 1) ++ break; ++ ++ grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = 64; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", dev->card_name); ++ ++ inf = grub_efi_net_create_interface (dev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ { ++ grub_efi_uint32_t count = 0; ++ grub_efi_dhcp6_packet_option_t **options = NULL; ++ grub_efi_uint32_t i; ++ ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) ++ { ++ options = grub_malloc (count * sizeof(*options)); ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (options) ++ grub_free (options); ++ continue; ++ } ++ ++ for (i = 0; i < count; ++i) ++ { ++ if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)) ++ { ++ grub_efi_net_ip_address_t dns; ++ grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6)); ++ efi_net_interface_set_dns (inf, &dns); ++ break; ++ } ++ } ++ ++ if (options) ++ grub_free (options); ++ } ++ ++ efi_call_1 (b->free_pool, mode.client_id); ++ efi_call_1 (b->free_pool, mode.ia); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp; ++grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6; +diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c +new file mode 100644 +index 0000000000..ef371d885e +--- /dev/null ++++ b/grub-core/net/efi/efi_netfs.c +@@ -0,0 +1,57 @@ ++#include ++#include ++#define EFI_NET_CMD_PREFIX "net_efi" ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_command_t cmd_efi_lsroutes; ++static grub_command_t cmd_efi_lscards; ++static grub_command_t cmd_efi_lsaddrs; ++static grub_command_t cmd_efi_addaddr; ++static grub_command_t cmd_efi_bootp; ++static grub_command_t cmd_efi_bootp6; ++ ++static int initialized; ++ ++GRUB_MOD_INIT(efi_netfs) ++{ ++ if (grub_net_open) ++ return; ++ ++ if (grub_efi_net_fs_init ()) ++ { ++ cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes, ++ "", N_("list network routes")); ++ cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards, ++ "", N_("list network cards")); ++ cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs, ++ "", N_("list network addresses")); ++ cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr, ++ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), ++ N_("Add a network address.")); ++ cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ initialized = 1; ++ } ++} ++ ++GRUB_MOD_FINI(efi_netfs) ++{ ++ if (initialized) ++ { ++ grub_unregister_command (cmd_efi_lsroutes); ++ grub_unregister_command (cmd_efi_lscards); ++ grub_unregister_command (cmd_efi_lsaddrs); ++ grub_unregister_command (cmd_efi_addaddr); ++ grub_unregister_command (cmd_efi_bootp); ++ grub_unregister_command (cmd_efi_bootp6); ++ grub_efi_net_fs_fini (); ++ initialized = 0; ++ return; ++ } ++} +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +new file mode 100644 +index 0000000000..3f61fd2fa5 +--- /dev/null ++++ b/grub-core/net/efi/http.c +@@ -0,0 +1,419 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++http_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_http_config_data_t http_config; ++ grub_efi_httpv4_access_point_t httpv4_node; ++ grub_efi_httpv6_access_point_t httpv6_node; ++ grub_efi_status_t status; ++ ++ grub_efi_http_t *http = dev->http; ++ ++ grub_memset (&http_config, 0, sizeof(http_config)); ++ http_config.http_version = GRUB_EFI_HTTPVERSION11; ++ http_config.timeout_millisec = 5000; ++ ++ if (prefer_ip6) ++ { ++ grub_efi_uintn_t sz; ++ grub_efi_ip6_config_manual_address_t manual_address; ++ ++ http_config.local_address_is_ipv6 = 1; ++ sz = sizeof (manual_address); ++ status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, &manual_address); ++ ++ if (status == GRUB_EFI_NOT_FOUND) ++ { ++ grub_printf ("The MANUAL ADDRESS is not found\n"); ++ } ++ ++ /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("??? %d\n",(int) status); ++ return; ++ } ++ ++ grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address)); ++ httpv6_node.local_port = 0; ++ http_config.access_point.ipv6_node = &httpv6_node; ++ } ++ else ++ { ++ http_config.local_address_is_ipv6 = 0; ++ grub_memset (&httpv4_node, 0, sizeof(httpv4_node)); ++ httpv4_node.use_default_address = 1; ++ ++ /* Use random port here */ ++ /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */ ++ httpv4_node.local_port = 0; ++ http_config.access_point.ipv4_node = &httpv4_node; ++ } ++ ++ status = efi_call_2 (http->configure, http, &http_config); ++ ++ if (status == GRUB_EFI_ALREADY_STARTED) ++ { ++ /* XXX: This hangs HTTPS boot */ ++#if 0 ++ if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't reset http instance")); ++ grub_print_error (); ++ return; ++ } ++ status = efi_call_2 (http->configure, http, &http_config); ++#endif ++ return; ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status); ++ grub_print_error (); ++ return ; ++ } ++} ++ ++static grub_efi_boolean_t request_callback_done; ++static grub_efi_boolean_t response_callback_done; ++ ++static void ++grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ request_callback_done = 1; ++} ++ ++static void ++grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ response_callback_done = 1; ++} ++ ++static grub_err_t ++efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size) ++{ ++ grub_efi_http_request_data_t request_data; ++ grub_efi_http_message_t request_message; ++ grub_efi_http_token_t request_token; ++ grub_efi_http_response_data_t response_data; ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ grub_efi_http_header_t request_headers[3]; ++ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ char *url = NULL; ++ ++ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; ++ request_headers[0].field_value = (grub_efi_char8_t *)server; ++ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; ++ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; ++ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; ++ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ ++ { ++ grub_efi_ipv6_address_t address; ++ const char *rest; ++ grub_efi_char16_t *ucs2_url; ++ grub_size_t url_len, ucs2_url_len; ++ const char *protocol = (use_https == 1) ? "https" : "http"; ++ ++ if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) ++ url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); ++ else ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ ++ if (!url) ++ { ++ return grub_errno; ++ } ++ ++ url_len = grub_strlen (url); ++ ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8; ++ ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0])); ++ ++ if (!ucs2_url) ++ { ++ grub_free (url); ++ return grub_errno; ++ } ++ ++ ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ ++ ucs2_url[ucs2_url_len] = 0; ++ grub_free (url); ++ request_data.url = ucs2_url; ++ } ++ ++ request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; ++ ++ request_message.data.request = &request_data; ++ request_message.header_count = 3; ++ request_message.headers = request_headers; ++ request_message.body_length = 0; ++ request_message.body = NULL; ++ ++ /* request token */ ++ request_token.event = NULL; ++ request_token.status = GRUB_EFI_NOT_READY; ++ request_token.message = &request_message; ++ ++ request_callback_done = 0; ++ status = efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_request_callback, ++ NULL, ++ &request_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); ++ } ++ ++ status = efi_call_2 (http->request, http, &request_token); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status); ++ } ++ /* TODO: Add Timeout */ ++ while (!request_callback_done) ++ efi_call_1(http->poll, http); ++ ++ response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; ++ response_message.data.response = &response_data; ++ /* herader_count will be updated by the HTTP driver on response */ ++ response_message.header_count = 0; ++ /* headers will be populated by the driver on response */ ++ response_message.headers = NULL; ++ /* use zero BodyLength to only receive the response headers */ ++ response_message.body_length = 0; ++ response_message.body = NULL; ++ response_token.event = NULL; ++ ++ status = efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, ++ NULL, ++ &response_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); ++ } ++ ++ response_token.status = GRUB_EFI_SUCCESS; ++ response_token.message = &response_message; ++ ++ /* wait for HTTP response */ ++ response_callback_done = 0; ++ status = efi_call_2 (http->response, http, &response_token); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status); ++ } ++ ++ /* TODO: Add Timeout */ ++ while (!response_callback_done) ++ efi_call_1 (http->poll, http); ++ ++ if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK) ++ { ++ grub_efi_http_status_code_t status_code = response_message.data.response->status_code; ++ ++ if (response_message.headers) ++ efi_call_1 (b->free_pool, response_message.headers); ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND) ++ { ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name); ++ } ++ else ++ { ++ return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR, ++ _("unsupported uefi http status code 0x%x"), status_code); ++ } ++ } ++ ++ if (file_size) ++ { ++ int i; ++ /* parse the length of the file from the ContentLength header */ ++ for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i) ++ { ++ if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length")) ++ { ++ *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10); ++ break; ++ } ++ } ++ } ++ ++ if (response_message.headers) ++ efi_call_1 (b->free_pool, response_message.headers); ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++efihttp_read (struct grub_efi_net_device *dev, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ ++ grub_efi_status_t status; ++ grub_size_t sum = 0; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_http_t *http = dev->http; ++ ++ if (!len) ++ { ++ grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read"); ++ return -1; ++ } ++ ++ efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, ++ NULL, ++ &response_token.event); ++ ++ while (len) ++ { ++ response_message.data.response = NULL; ++ response_message.header_count = 0; ++ response_message.headers = NULL; ++ response_message.body_length = len; ++ response_message.body = buf; ++ ++ response_token.message = &response_message; ++ response_token.status = GRUB_EFI_NOT_READY; ++ ++ response_callback_done = 0; ++ ++ status = efi_call_2 (http->response, http, &response_token); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, response_token.event); ++ grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status); ++ return -1; ++ } ++ ++ while (!response_callback_done) ++ efi_call_1(http->poll, http); ++ ++ sum += response_message.body_length; ++ buf += response_message.body_length; ++ len -= response_message.body_length; ++ } ++ ++ efi_call_1 (b->close_event, response_token.event); ++ ++ return sum; ++} ++ ++static grub_err_t ++grub_efihttp_open (struct grub_efi_net_device *dev, ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file, ++ const char *filename __attribute__ ((unused)), ++ int type) ++{ ++ grub_err_t err; ++ grub_off_t size; ++ char *buf; ++ ++ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ buf = grub_malloc (size); ++ efihttp_read (dev, buf, size); ++ ++ file->size = size; ++ file->data = buf; ++ file->not_easily_seekable = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)), ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file) ++{ ++ if (file->data) ++ grub_free (file->data); ++ ++ file->data = 0; ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_size_t r = len; ++ ++ if (!file->data || !buf || !len) ++ return 0; ++ ++ if ((file->device->net->offset + len) > file->size) ++ r = file->size - file->device->net->offset; ++ ++ if (r) ++ { ++ grub_memcpy (buf, (char *)file->data + file->device->net->offset, r); ++ file->device->net->offset += r; ++ } ++ ++ return r; ++} ++ ++struct grub_efi_net_io io_http = ++ { ++ .configure = http_configure, ++ .open = grub_efihttp_open, ++ .read = grub_efihttp_read, ++ .close = grub_efihttp_close ++ }; +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +new file mode 100644 +index 0000000000..b711a5d945 +--- /dev/null ++++ b/grub-core/net/efi/ip4_config.c +@@ -0,0 +1,398 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) ++{ ++ char *hw_addr, *p; ++ int sz, s; ++ int i; ++ ++ sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1; ++ ++ hw_addr = grub_malloc (sz); ++ if (!hw_addr) ++ return NULL; ++ ++ p = hw_addr; ++ s = sz; ++ for (i = 0; i < (int)hw_address_size; i++) ++ { ++ grub_snprintf (p, sz, "%02x:", hw_address[i]); ++ p += sizeof ("XX:") - 1; ++ s -= sizeof ("XX:") - 1; ++ } ++ ++ hw_addr[sz - 2] = '\0'; ++ return hw_addr; ++} ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address) ++{ ++ char *addr; ++ ++ addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX")); ++ if (!addr) ++ return NULL; ++ ++ /* FIXME: Use grub_xasprintf ? */ ++ grub_snprintf (addr, ++ sizeof ("XXX.XXX.XXX.XXX"), ++ "%u.%u.%u.%u", ++ (*address)[0], ++ (*address)[1], ++ (*address)[2], ++ (*address)[3]); ++ ++ return addr; ++} ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) ++{ ++ grub_uint32_t newip = 0; ++ int i; ++ const char *ptr = val; ++ ++ for (i = 0; i < 4; i++) ++ { ++ unsigned long t; ++ t = grub_strtoul (ptr, (char **) &ptr, 0); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (*ptr != '.' && i == 0) ++ { ++ /* XXX: t is in host byte order */ ++ newip = t; ++ break; ++ } ++ if (t & ~0xff) ++ return 0; ++ newip <<= 8; ++ newip |= t; ++ if (i != 3 && *ptr != '.') ++ return 0; ++ ptr++; ++ } ++ ++ newip = grub_cpu_to_be32 (newip); ++ ++ grub_memcpy (address, &newip, sizeof(*address)); ++ ++ if (rest) ++ *rest = (ptr - 1); ++ return 1; ++} ++ ++static grub_efi_ip4_config2_interface_info_t * ++efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ if (!interface_info) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip4_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip4_address_to_string (&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++ ++static int ++address_mask_size (grub_efi_ipv4_address_t *address) ++{ ++ grub_uint8_t i; ++ grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address)); ++ ++ if (u32_addr == 0) ++ return 0; ++ ++ for (i = 0; i < 32 ; ++i) ++ { ++ if (u32_addr == ((0xffffffff >> i) << i)) ++ return (32 - i); ++ } ++ ++ return -1; ++} ++ ++static char ** ++grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char **ret; ++ int i, id; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1)); ++ ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < (int)interface_info->route_table_size; i++) ++ { ++ char *subnet, *gateway, *mask; ++ grub_uint32_t u32_subnet, u32_gateway; ++ int mask_size; ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ u32_gateway = grub_get_unaligned32 (&route_table->gateway_address); ++ gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address); ++ u32_subnet = grub_get_unaligned32 (&route_table->subnet_address); ++ subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address); ++ mask_size = address_mask_size (&route_table->subnet_mask); ++ mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask); ++ if (u32_subnet && !u32_gateway && interface_name) ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); ++ else if (u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ else if (!u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ grub_free (subnet); ++ grub_free (gateway); ++ grub_free (mask); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv4_address_t *address = &ip_address->ip4; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_table_size; i++) ++ { ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_uint32_t u32_address, u32_mask, u32_subnet; ++ ++ u32_address = grub_get_unaligned32 (address); ++ u32_subnet = grub_get_unaligned32 (route_table->subnet_address); ++ u32_mask = grub_get_unaligned32 (route_table->subnet_mask); ++ ++ /* SKIP Default GATEWAY */ ++ if (!u32_subnet && !u32_mask) ++ continue; ++ ++ if ((u32_address & u32_mask) == u32_subnet) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address = ++ efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address) ++ { ++ grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask)); ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->subnet_mask[0] = 0xff; ++ address->subnet_mask[1] = 0xff; ++ address->subnet_mask[2] = 0xff; ++ address->subnet_mask[3] = 0; ++ } ++ } ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++/* FIXME: Multiple DNS */ ++static int ++grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip4_interface_hw_address, ++ .get_address = grub_efi_ip4_interface_address, ++ .get_route_table = grub_efi_ip4_interface_route_table, ++ .best_interface = grub_efi_ip4_interface_match, ++ .set_address = grub_efi_ip4_interface_set_manual_address, ++ .set_gateway = grub_efi_ip4_interface_set_gateway, ++ .set_dns = grub_efi_ip4_interface_set_dns ++ }; +diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c +new file mode 100644 +index 0000000000..017c4d05bc +--- /dev/null ++++ b/grub-core/net/efi/ip6_config.c +@@ -0,0 +1,422 @@ ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) ++{ ++ char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); ++ char *p; ++ int i; ++ int squash; ++ ++ if (!str) ++ return NULL; ++ ++ p = str; ++ squash = 0; ++ for (i = 0; i < 8; ++i) ++ { ++ grub_uint16_t addr; ++ ++ if (i == 7) ++ squash = 2; ++ ++ addr = grub_get_unaligned16 (address->addr + i * 2); ++ ++ if (grub_be_to_cpu16 (addr)) ++ { ++ char buf[sizeof ("XXXX")]; ++ if (i > 0) ++ *p++ = ':'; ++ grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr)); ++ grub_strcpy (p, buf); ++ p += grub_strlen (buf); ++ ++ if (squash == 1) ++ squash = 2; ++ } ++ else ++ { ++ if (squash == 0) ++ { ++ *p++ = ':'; ++ squash = 1; ++ } ++ else if (squash == 2) ++ { ++ *p++ = ':'; ++ *p++ = '0'; ++ } ++ } ++ } ++ *p = '\0'; ++ return str; ++} ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, (char **) &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (address, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_efi_ip6_config_interface_info_t * ++efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip6_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++static char ** ++grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char **ret; ++ int i, id; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1)); ++ ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < (int)interface_info->route_count ; i++) ++ { ++ char *gateway, *destination; ++ grub_uint64_t u64_gateway[2]; ++ grub_uint64_t u64_destination[2]; ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ gateway = grub_efi_ip6_address_to_string (&route_table->gateway); ++ destination = grub_efi_ip6_address_to_string (&route_table->destination); ++ ++ u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr); ++ u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8); ++ u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ if ((!u64_gateway[0] && !u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ { ++ if (interface_name) ++ { ++ if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL) ++ && (!u64_destination[1]) ++ && (route_table->prefix_length == 64)) ++ ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ else ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ } ++ } ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (!u64_destination[0] && !u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ ++ grub_free (gateway); ++ grub_free (destination); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv6_address_t *address = &ip_address->ip6; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_count ; i++) ++ { ++ grub_uint64_t u64_addr[2]; ++ grub_uint64_t u64_subnet[2]; ++ grub_uint64_t u64_mask[2]; ++ ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ ++ /* SKIP Default GATEWAY */ ++ if (route_table->prefix_length == 0) ++ continue; ++ ++ u64_addr[0] = grub_get_unaligned64 (address); ++ u64_addr[1] = grub_get_unaligned64 (address + 4); ++ u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ u64_mask[0] = (route_table->prefix_length <= 64) ? ++ 0xffffffffffffffffULL << (64 - route_table->prefix_length) : ++ 0xffffffffffffffffULL; ++ u64_mask[1] = (route_table->prefix_length <= 64) ? ++ 0 : ++ 0xffffffffffffffffULL << (128 - route_table->prefix_length); ++ ++ if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0]) ++ && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1])) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address = ++ efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address) ++ { ++ address->prefix_length = manual_address->prefix_length; ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->prefix_length = 64; ++ } ++ } ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip6_interface_hw_address, ++ .get_address = grub_efi_ip6_interface_address, ++ .get_route_table = grub_efi_ip6_interface_route_table, ++ .best_interface = grub_efi_ip6_interface_match, ++ .set_address = grub_efi_ip6_interface_set_manual_address, ++ .set_gateway = grub_efi_ip6_interface_set_gateway, ++ .set_dns = grub_efi_ip6_interface_set_dns ++ }; +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +new file mode 100644 +index 0000000000..86bce6535d +--- /dev/null ++++ b/grub-core/net/efi/net.c +@@ -0,0 +1,1428 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define GRUB_EFI_IP6_PREFIX_LENGTH 64 ++ ++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; ++static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; ++static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID; ++ ++struct grub_efi_net_device *net_devices; ++ ++static char *default_server; ++static grub_efi_net_interface_t *net_interface; ++static grub_efi_net_interface_t *net_default_interface; ++ ++#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6) ++#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type) ++#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz) ++#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file) ++#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__) ++ ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static int ++url_parse_fields (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} ++ ++static void ++url_get_boot_location (const char *url, char **device, char **path, int is_default) ++{ ++ char *protocol, *server, *file; ++ char *slash; ++ ++ if (!url_parse_fields (url, &protocol, &server, &file)) ++ return; ++ ++ if ((slash = grub_strrchr (file, '/'))) ++ *slash = 0; ++ else ++ *file = 0; ++ ++ *device = grub_xasprintf ("%s,%s", protocol, server); ++ *path = grub_strdup(file); ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++ ++ grub_free (protocol); ++ grub_free (file); ++} ++ ++static void ++pxe_get_boot_location (const struct grub_net_bootp_packet *bp, ++ char **device, ++ char **path, ++ int is_default) ++{ ++ char *server = grub_xasprintf ("%d.%d.%d.%d", ++ ((grub_uint8_t *) &bp->server_ip)[0], ++ ((grub_uint8_t *) &bp->server_ip)[1], ++ ((grub_uint8_t *) &bp->server_ip)[2], ++ ((grub_uint8_t *) &bp->server_ip)[3]); ++ ++ *device = grub_xasprintf ("tftp,%s", server); ++ ++ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); ++ ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++} ++ ++static void ++pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp, ++ grub_size_t dhcp_size, ++ char **device, ++ char **path) ++{ ++ ++ struct grub_net_dhcp6_option *dhcp_opt; ++ grub_size_t dhcp_remain_size; ++ *device = *path = 0; ++ ++ if (dhcp_size < sizeof (*dp)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return; ++ } ++ ++ dhcp_remain_size = dhcp_size - sizeof (*dp); ++ dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options; ++ ++ while (dhcp_remain_size) ++ { ++ grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len); ++ grub_uint16_t option_size = sizeof (*dhcp_opt) + len; ++ ++ if (dhcp_remain_size < option_size || code == 0) ++ break; ++ ++ if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL) ++ { ++ char *url = grub_malloc (len + 1); ++ ++ grub_memcpy (url, dhcp_opt->data, len); ++ url[len] = 0; ++ ++ url_get_boot_location ((const char *)url, device, path, 1); ++ grub_free (url); ++ break; ++ } ++ ++ dhcp_remain_size -= option_size; ++ dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size); ++ } ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_net_interface_t *inf = NULL; ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ { ++ if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_uri_device_path_t *uri_dp; ++ uri_dp = (grub_efi_uri_device_path_t *) dp; ++ /* Beware that uri_dp->uri may not be null terminated */ ++ url_get_boot_location ((const char *)uri_dp->uri, device, path, 1); ++ } ++ else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return inf; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_pxe_t *pxe = NULL; ++ ++ if (hnd == netdev->ip4_pxe_handle) ++ pxe = netdev->ip4_pxe; ++ else if (hnd == netdev->ip6_pxe_handle) ++ pxe = netdev->ip6_pxe; ++ ++ if (!pxe) ++ return (grub_efi_net_config_from_device_path ( ++ grub_efi_get_device_path (hnd), ++ netdev, ++ device, ++ path)); ++ ++ if (pxe->mode->using_ipv6) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location_v6 ( ++ (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack, ++ sizeof (pxe->mode->dhcp_ack), ++ device, ++ path); ++ ++ grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++ else ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location ( ++ (const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack, ++ device, ++ path, ++ 1); ++ ++ grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++} ++ ++static const char * ++grub_efi_net_var_get_address (struct grub_env_var *var, ++ const char *val __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var_name; ++ ++ var_name = grub_xasprintf ("net_%s_ip", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_address (inf); ++ grub_free (var_name); ++ var_name = grub_xasprintf ("net_%s_mac", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_hw_address (inf); ++ grub_free (var_name); ++ } ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (grub_strcmp (inf->name, val) == 0) ++ { ++ net_default_interface = inf; ++ return grub_strdup (val); ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (default_server); ++ default_server = grub_strdup (val); ++ return grub_strdup (val); ++} ++ ++static const char * ++grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return default_server ? : ""; ++} ++ ++static const char * ++grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_ip", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static const char * ++grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_mac", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static void ++grub_efi_net_export_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ } ++ } ++} ++ ++static void ++grub_efi_net_unset_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ } ++ } ++} ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet) ++{ ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ if (inf->prefer_ip6 == net_ip->is_ip6) ++ break; ++ } ++ ++ if (!inf) ++ { ++ inf = grub_malloc (sizeof(*inf)); ++ inf->name = grub_strdup (interface_name); ++ inf->prefer_ip6 = net_ip->is_ip6; ++ inf->dev = dev; ++ inf->next = dev->net_interfaces; ++ inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ; ++ dev->net_interfaces = inf; ++ } ++ else ++ { ++ grub_free (inf->name); ++ inf->name = grub_strdup (interface_name); ++ } ++ ++ if (!efi_net_interface_set_address (inf, net_ip, has_subnet)) ++ { ++ grub_error (GRUB_ERR_BUG, N_("Set Address Failed")); ++ return NULL; ++ } ++ ++ return inf; ++} ++ ++static void ++grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, ++ char **path) ++{ ++ grub_efi_handle_t config_hnd; ++ ++ struct grub_efi_net_device *netdev; ++ grub_efi_net_interface_t *inf; ++ ++ config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL); ++ ++ if (!config_hnd) ++ return; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ if (netdev->handle == config_hnd) ++ break; ++ ++ if (!netdev) ++ return; ++ ++ if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path))) ++ return; ++ ++ grub_env_set ("net_default_interface", inf->name); ++ grub_efi_net_export_interface_vars (); ++} ++ ++static grub_err_t ++grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)), ++ grub_fs_dir_hook_t hook __attribute__ ((unused)), ++ void *hook_data __attribute__ ((unused))) ++{ ++ if (!device->net) ++ return grub_error (GRUB_ERR_BUG, "invalid net device"); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)), ++ const char *name __attribute__ ((unused))) ++{ ++ struct grub_file *file, *bufio; ++ ++ file = grub_malloc (sizeof (*file)); ++ if (!file) ++ return grub_errno; ++ ++ grub_memcpy (file, file_out, sizeof (struct grub_file)); ++ file->device->net->name = grub_strdup (name); ++ ++ if (!file->device->net->name) ++ { ++ grub_free (file); ++ return grub_errno; ++ } ++ ++ efi_net_interface(open, file, name); ++ grub_print_error (); ++ ++ bufio = grub_bufio_open (file, 32768); ++ if (!bufio) ++ { ++ grub_free (file->device->net->name); ++ grub_free (file); ++ return grub_errno; ++ } ++ grub_memcpy (file_out, bufio, sizeof (struct grub_file)); ++ grub_free (bufio); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_chunk_read (grub_file_t file, char *buf, ++ grub_size_t len, grub_size_t chunk_size) ++{ ++ char *chunk = grub_malloc (chunk_size); ++ grub_size_t sum = 0; ++ ++ while (len) ++ { ++ grub_ssize_t rd; ++ grub_size_t sz = (len > chunk_size) ? chunk_size : len; ++ ++ rd = efi_net_interface (read, file, chunk, sz); ++ ++ if (rd <= 0) ++ return rd; ++ ++ if (buf) ++ { ++ grub_memcpy (buf, chunk, rd); ++ buf += rd; ++ } ++ sum += rd; ++ len -= rd; ++ } ++ ++ grub_free (chunk); ++ return sum; ++} ++ ++static grub_ssize_t ++grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)), ++ char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) ++{ ++ if (file->offset > file->device->net->offset) ++ { ++ grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240); ++ } ++ else if (file->offset < file->device->net->offset) ++ { ++ efi_net_interface (close, file); ++ efi_net_interface (open, file, file->device->net->name); ++ if (file->offset) ++ grub_efihttp_chunk_read (file, NULL, file->offset, 10240); ++ } ++ ++ return efi_net_interface (read, file, buf, len); ++} ++ ++static grub_err_t ++grub_efi_netfs_close (grub_file_t file) ++{ ++ efi_net_interface (close, file); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_efi_handle_t ++grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid) ++{ ++ grub_efi_service_binding_t *service; ++ grub_efi_status_t status; ++ grub_efi_handle_t child_dev = NULL; ++ ++ service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!service) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol")); ++ return NULL; ++ } ++ ++ status = efi_call_2 (service->create_child, service, &child_dev); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status); ++ return NULL; ++ } ++ ++ return child_dev; ++} ++ ++static grub_err_t ++grub_efi_net_parse_address (const char *address, ++ grub_efi_ip4_config2_manual_address_t *ip4, ++ grub_efi_ip6_config_manual_address_t *ip6, ++ int *is_ip6, ++ int *has_cidr) ++{ ++ const char *rest; ++ ++ if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest)) ++ { ++ *is_ip6 = 0; ++ if (*rest == '/') ++ { ++ grub_uint32_t subnet_mask_size; ++ ++ subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0); ++ ++ if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) ++ { ++ grub_uint32_t subnet_mask; ++ ++ subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size))); ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0) ++ { ++ grub_uint32_t subnet_mask = 0xffffffffU; ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest)) ++ { ++ *is_ip6 = 1; ++ if (*rest == '/') ++ { ++ grub_efi_uint8_t prefix_length; ++ ++ prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0); ++ if (!grub_errno && prefix_length <= 128 && *rest == 0) ++ { ++ ip6->prefix_length = prefix_length; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0) ++ { ++ ip6->prefix_length = 128; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ ++ return grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("unrecognised network address `%s'"), ++ address); ++} ++ ++static grub_efi_net_interface_t * ++match_route (const char *server) ++{ ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_interface_t *inf; ++ int is_ip6 = 0; ++ ++ err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); ++ ++ if (err) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ ++ if (is_ip6) ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip6_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ else ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip4_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ ++ return 0; ++} ++ ++static void ++grub_efi_net_add_pxebc_to_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (handle = handles; num_handles--; handle++) ++ { ++ grub_efi_device_path_t *dp, *ddp, *ldp; ++ grub_efi_pxe_t *pxe; ++ struct grub_efi_net_device *d; ++ int is_ip6 = 0; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ is_ip6 = 1; ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ ++ for (d = net_devices; d; d = d->next) ++ if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0) ++ break; ++ ++ if (!d) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ pxe = grub_efi_open_protocol (*handle, &pxe_io_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!pxe) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ if (is_ip6) ++ { ++ d->ip6_pxe_handle = *handle; ++ d->ip6_pxe = pxe; ++ } ++ else ++ { ++ d->ip4_pxe_handle = *handle; ++ d->ip4_pxe = pxe; ++ } ++ ++ grub_free (ddp); ++ } ++ ++ grub_free (handles); ++} ++ ++static void ++set_ip_policy_to_static (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC; ++ ++ if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name); ++ ++ if (dev->ip6_config) ++ { ++ grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL; ++ ++ if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name); ++ } ++ } ++} ++ ++/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */ ++static void ++grub_efi_net_find_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ int id; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (id = 0, handle = handles; num_handles--; handle++, id++) ++ { ++ grub_efi_device_path_t *dp; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ ++ struct grub_efi_net_device *d; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!ip4_config) ++ continue; ++ ++ ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ http = (http_handle) ++ ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp4 = (dhcp4_handle) ++ ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ ++ dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp6 = (dhcp6_handle) ++ ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ d = grub_malloc (sizeof (*d)); ++ if (!d) ++ { ++ grub_free (handles); ++ while (net_devices) ++ { ++ d = net_devices->next; ++ grub_free (net_devices); ++ net_devices = d; ++ } ++ return; ++ } ++ d->handle = *handle; ++ d->ip4_config = ip4_config; ++ d->ip6_config = ip6_config; ++ d->http_handle = http_handle; ++ d->http = http; ++ d->dhcp4_handle = dhcp4_handle; ++ d->dhcp4 = dhcp4; ++ d->dhcp6_handle = dhcp6_handle; ++ d->dhcp6 = dhcp6; ++ d->next = net_devices; ++ d->card_name = grub_xasprintf ("efinet%d", id); ++ d->net_interfaces = NULL; ++ net_devices = d; ++ } ++ ++ grub_efi_net_add_pxebc_to_cards (); ++ grub_free (handles); ++ set_ip_policy_to_static (); ++} ++ ++static void ++listroutes_ip4 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip4_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static void ++listroutes_ip6 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip6_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static grub_err_t ++grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ listroutes_ip4 (netdev); ++ listroutes_ip6 (netdev); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++static grub_err_t ++grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ char *hw_addr; ++ ++ hw_addr = efi_net_ip4_config->get_hw_address (dev); ++ ++ if (hw_addr) ++ { ++ grub_printf ("%s %s\n", dev->card_name, hw_addr); ++ grub_free (hw_addr); ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *hw_addr = NULL; ++ char *addr = NULL; ++ ++ if ((hw_addr = efi_net_interface_get_hw_address (inf)) ++ && (addr = efi_net_interface_get_address (inf))) ++ grub_printf ("%s %s %s\n", inf->name, hw_addr, addr); ++ ++ if (hw_addr) ++ grub_free (hw_addr); ++ if (addr) ++ grub_free (addr); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* FIXME: support MAC specifying. */ ++static grub_err_t ++grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_ip_manual_address_t net_ip; ++ int is_ip6 = 0; ++ int cidr = 0; ++ ++ if (argc != 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ if (grub_strcmp (dev->card_name, args[1]) == 0) ++ break; ++ } ++ ++ if (!dev) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); ++ ++ err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr); ++ ++ if (err) ++ return err; ++ ++ net_ip.is_ip6 = is_ip6; ++ if (is_ip6) ++ grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6)); ++ else ++ grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4)); ++ ++ if (!grub_efi_net_create_interface (dev, ++ args[0], ++ &net_ip, ++ cidr)) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_fs grub_efi_netfs; ++ ++static grub_net_t ++grub_net_open_real (const char *name __attribute__ ((unused))) ++{ ++ grub_size_t protnamelen; ++ const char *protname, *server; ++ grub_net_t ret; ++ ++ net_interface = NULL; ++ ++ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = name + sizeof ("pxe:") - 1; ++ } ++ else if (grub_strcmp (name, "pxe") == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = default_server; ++ } ++ else ++ { ++ const char *comma; ++ ++ comma = grub_strchr (name, ','); ++ if (comma) ++ { ++ protnamelen = comma - name; ++ server = comma + 1; ++ protname = name; ++ } ++ else ++ { ++ protnamelen = grub_strlen (name); ++ server = default_server; ++ protname = name; ++ } ++ } ++ ++ if (!server) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("no server is specified")); ++ return NULL; ++ } ++ ++ /*FIXME: Use DNS translate name to address */ ++ net_interface = match_route (server); ++ ++ /*XXX: should we check device with default gateway ? */ ++ if (!net_interface && !(net_interface = net_default_interface)) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), ++ name); ++ return NULL; ++ } ++ ++ if ((protnamelen == (sizeof ("https") - 1) ++ && grub_memcmp ("https", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 1; ++ } ++ else if ((protnamelen == (sizeof ("http") - 1) ++ && grub_memcmp ("http", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 0; ++ } ++ else if (protnamelen == (sizeof ("tftp") - 1) ++ && grub_memcmp ("tftp", protname, protnamelen) == 0) ++ { ++ net_interface->io = &io_pxe; ++ net_interface->io_type = 0; ++ } ++ else ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), ++ name); ++ return NULL; ++ } ++ ++ /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */ ++ efi_net_interface (configure); ++ ++ ret = grub_zalloc (sizeof (*ret)); ++ if (!ret) ++ return NULL; ++ ++ ret->server = grub_strdup (server); ++ if (!ret->server) ++ { ++ grub_free (ret); ++ return NULL; ++ } ++ ++ ret->fs = &grub_efi_netfs; ++ return ret; ++} ++#if 0 ++static grub_command_t cmd_efi_lsaddr; ++static grub_command_t cmd_efi_lscards; ++static grub_command_t cmd_efi_lsroutes; ++static grub_command_t cmd_efi_addaddr; ++#endif ++ ++static struct grub_fs grub_efi_netfs = ++ { ++ .name = "efi netfs", ++ .fs_dir = grub_efi_netfs_dir, ++ .fs_open = grub_efi_netfs_open, ++ .fs_read = grub_efi_netfs_read, ++ .fs_close = grub_efi_netfs_close, ++ .fs_label = NULL, ++ .fs_uuid = NULL, ++ .fs_mtime = NULL, ++ }; ++ ++int ++grub_efi_net_boot_from_https (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; ++ return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++int ++grub_efi_net_boot_from_opa (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_mac_address_device_path_t *mac_dp = (grub_efi_mac_address_device_path_t *)dp; ++ return (mac_dp->if_type == 0xC7) ? 1 : 0; ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++static char * ++grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return NULL; ++} ++ ++grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes; ++grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards; ++grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs; ++grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr; ++ ++int ++grub_efi_net_fs_init () ++{ ++ grub_efi_net_find_cards (); ++ grub_efi_net_config = grub_efi_net_config_real; ++ grub_net_open = grub_net_open_real; ++ grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("net_default_server"); ++ grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, ++ grub_efi_net_var_set_interface); ++ grub_env_export ("net_default_interface"); ++ grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip, ++ 0); ++ grub_env_export ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac, ++ 0); ++ grub_env_export ("net_default_mac"); ++ ++ grub_env_set ("grub_netfs_type", "efi"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ ++ return 1; ++} ++ ++void ++grub_efi_net_fs_fini (void) ++{ ++ grub_env_unset ("grub_netfs_type"); ++ grub_efi_net_unset_interface_vars (); ++ grub_register_variable_hook ("net_default_server", 0, 0); ++ grub_env_unset ("net_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, 0); ++ grub_env_unset ("net_default_interface"); ++ grub_register_variable_hook ("pxe_default_server", 0, 0); ++ grub_env_unset ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_ip", 0, 0); ++ grub_env_unset ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", 0, 0); ++ grub_env_unset ("net_default_mac"); ++ grub_efi_net_config = NULL; ++ grub_net_open = NULL; ++ grub_fs_unregister (&grub_efi_netfs); ++} +diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c +new file mode 100644 +index 0000000000..531949cba5 +--- /dev/null ++++ b/grub-core/net/efi/pxe.c +@@ -0,0 +1,424 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static void ++pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ ++ if (!mode->started) ++ { ++ grub_efi_status_t status; ++ status = efi_call_2 (pxe->start, pxe, prefer_ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++#if 0 ++ grub_printf ("PXE STARTED: %u\n", mode->started); ++ grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6); ++#endif ++ ++ if (mode->using_ipv6) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ ++ grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr)); ++ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ else ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ ++ grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr)); ++ grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr)); ++ ++ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ ++#if 0 ++ if (mode->using_ipv6) ++ { ++ grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ mode->station_ip.v6.addr[0], ++ mode->station_ip.v6.addr[1], ++ mode->station_ip.v6.addr[2], ++ mode->station_ip.v6.addr[3], ++ mode->station_ip.v6.addr[4], ++ mode->station_ip.v6.addr[5], ++ mode->station_ip.v6.addr[6], ++ mode->station_ip.v6.addr[7], ++ mode->station_ip.v6.addr[8], ++ mode->station_ip.v6.addr[9], ++ mode->station_ip.v6.addr[10], ++ mode->station_ip.v6.addr[11], ++ mode->station_ip.v6.addr[12], ++ mode->station_ip.v6.addr[13], ++ mode->station_ip.v6.addr[14], ++ mode->station_ip.v6.addr[15]); ++ } ++ else ++ { ++ grub_printf ("PXE STATION IP: %d.%d.%d.%d\n", ++ mode->station_ip.v4.addr[0], ++ mode->station_ip.v4.addr[1], ++ mode->station_ip.v4.addr[2], ++ mode->station_ip.v4.addr[3]); ++ grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n", ++ mode->subnet_mask.v4.addr[0], ++ mode->subnet_mask.v4.addr[1], ++ mode->subnet_mask.v4.addr[2], ++ mode->subnet_mask.v4.addr[3]); ++ } ++#endif ++ ++ /* TODO: Set The Station IP to the IP2 Config */ ++} ++ ++static int ++parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, (char **) &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_err_t ++pxe_open (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type __attribute__((unused))) ++{ ++ int i; ++ char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t server_ip; ++ grub_efi_uint64_t file_size = 0; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++#if 0 ++ grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ server_ip.v6.addr[0], ++ server_ip.v6.addr[1], ++ server_ip.v6.addr[2], ++ server_ip.v6.addr[3], ++ server_ip.v6.addr[4], ++ server_ip.v6.addr[5], ++ server_ip.v6.addr[6], ++ server_ip.v6.addr[7], ++ server_ip.v6.addr[8], ++ server_ip.v6.addr[9], ++ server_ip.v6.addr[10], ++ server_ip.v6.addr[11], ++ server_ip.v6.addr[12], ++ server_ip.v6.addr[13], ++ server_ip.v6.addr[14], ++ server_ip.v6.addr[15]); ++#endif ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ NULL, ++ 0, ++ &file_size, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)filename, ++ NULL, ++ 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return grub_error (GRUB_ERR_IO, "Couldn't get file size"); ++ ++ file->size = (grub_off_t)file_size; ++ file->not_easily_seekable = 0; ++ file->data = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++pxe_close (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file __attribute__((unused))) ++{ ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ ++ if (file->data) ++ { ++ grub_free (file->data); ++ file->data = NULL; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++pxe_read (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ int i; ++ char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ grub_efi_uint64_t bufsz = len; ++ grub_efi_pxe_ip_address_t server_ip; ++ char *buf2 = NULL; ++ ++ if (file->data) ++ { ++ /* TODO: RANGE Check for offset and file size */ ++ grub_memcpy (buf, (char*)file->data + file->device->net->offset, len); ++ file->device->net->offset += len; ++ return len; ++ } ++ ++ if (file->device->net->offset) ++ { ++ grub_error (GRUB_ERR_BUG, "No Offet Read Possible"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ ++ if (bufsz != file->size) ++ { ++ grub_error (GRUB_ERR_BUG, "Short read should not happen here"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ ++ buf2 = grub_malloc (bufsz); ++ ++ if (!buf2) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf2, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (buf2) ++ grub_free (buf2); ++ ++ grub_error (GRUB_ERR_IO, "Failed to Read File"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (buf2) ++ grub_memcpy (buf, buf2, len); ++ ++ file->device->net->offset = len; ++ ++ if (buf2) ++ file->data = buf2; ++ ++ return len; ++} ++ ++struct grub_efi_net_io io_pxe = ++ { ++ .configure = pxe_configure, ++ .open = pxe_open, ++ .read = pxe_read, ++ .close = pxe_close ++ }; ++ +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 0ce5e675ed..55aed92722 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -32,6 +32,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -2033,8 +2036,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; + static grub_command_t cmd_lsroutes, cmd_lscards; + static grub_command_t cmd_lsaddr, cmd_slaac; + ++#ifdef GRUB_MACHINE_EFI ++ ++static enum { ++ INIT_MODE_NONE, ++ INIT_MODE_GRUB, ++ INIT_MODE_EFI ++} init_mode; ++ ++static grub_command_t cmd_bootp, cmd_bootp6; ++ ++#endif ++ + GRUB_MOD_INIT(net) + { ++#ifdef GRUB_MACHINE_EFI ++ if (grub_net_open) ++ return; ++ ++ if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ()) ++ && grub_efi_net_fs_init ()) ++ { ++ cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes, ++ "", N_("list network routes")); ++ cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards, ++ "", N_("list network cards")); ++ cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs, ++ "", N_("list network addresses")); ++ cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr, ++ /* TRANSLATORS: HWADDRESS stands for ++ "hardware address". */ ++ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), ++ N_("Add a network address.")); ++ cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ init_mode = INIT_MODE_EFI; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", defserver_get_env, + defserver_set_env); + grub_env_export ("net_default_server"); +@@ -2082,10 +2126,37 @@ GRUB_MOD_INIT(net) + grub_net_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; ++ ++#ifdef GRUB_MACHINE_EFI ++ grub_env_set ("grub_netfs_type", "grub"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ init_mode = INIT_MODE_GRUB; ++#endif ++ + } + + GRUB_MOD_FINI(net) + { ++ ++#ifdef GRUB_MACHINE_EFI ++ if (init_mode == INIT_MODE_NONE) ++ return; ++ ++ if (init_mode == INIT_MODE_EFI) ++ { ++ grub_unregister_command (cmd_lsroutes); ++ grub_unregister_command (cmd_lscards); ++ grub_unregister_command (cmd_lsaddr); ++ grub_unregister_command (cmd_addaddr); ++ grub_unregister_command (cmd_bootp); ++ grub_unregister_command (cmd_bootp6); ++ grub_efi_net_fs_fini (); ++ init_mode = INIT_MODE_NONE; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", 0, 0); + grub_register_variable_hook ("pxe_default_server", 0, 0); + +@@ -2104,4 +2175,7 @@ GRUB_MOD_FINI(net) + grub_net_fini_hw (0); + grub_loader_unregister_preboot_hook (fini_hnd); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; ++#ifdef GRUB_MACHINE_EFI ++ init_mode = INIT_MODE_NONE; ++#endif + } +diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c +index a2461cda1c..77958dd9dd 100644 +--- a/util/grub-mknetdir.c ++++ b/util/grub-mknetdir.c +@@ -32,13 +32,15 @@ + + static char *rootdir = NULL, *subdir = NULL; + static char *debug_image = NULL; ++static char efi_netfs = 0; + + enum + { + OPTION_NET_DIRECTORY = 0x301, + OPTION_SUBDIR, + OPTION_DEBUG, +- OPTION_DEBUG_IMAGE ++ OPTION_DEBUG_IMAGE, ++ OPTION_DEBUG_EFI_NETFS + }; + + static struct argp_option options[] = { +@@ -49,6 +51,7 @@ static struct argp_option options[] = { + 0, N_("relative subdirectory on network server"), 2}, + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, ++ {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + free (subdir); + subdir = xstrdup (arg); + return 0; ++ case OPTION_DEBUG_EFI_NETFS: ++ efi_netfs = 1; ++ return 0; + /* This is an undocumented feature... */ + case OPTION_DEBUG: + verbosity++; +@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state) + } + } + +- + struct argp argp = { + options, argp_parser, NULL, + "\v"N_("Prepares GRUB network boot images at net_directory/subdir " +@@ -92,7 +97,7 @@ struct argp argp = { + + static char *base; + +-static const struct ++static struct + { + const char *mkimage_target; + const char *netmodule; +@@ -156,6 +161,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform) + grub_install_push_module (targets[platform].netmodule); + + output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext); ++ + grub_install_make_image_wrap (input_dir, prefix, output, + 0, load_cfg, + targets[platform].mkimage_target, 0); +@@ -195,7 +201,16 @@ main (int argc, char *argv[]) + + grub_install_mkdir_p (base); + +- grub_install_push_module ("tftp"); ++ if (!efi_netfs) ++ { ++ grub_install_push_module ("tftp"); ++ grub_install_push_module ("http"); ++ } ++ else ++ { ++ targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs"; ++ targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs"; ++ } + + if (!grub_install_source_directory) + { +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 0b490195ad..f431f49973 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -622,6 +622,23 @@ typedef union + + typedef grub_efi_uint64_t grub_efi_physical_address_t; + typedef grub_efi_uint64_t grub_efi_virtual_address_t; ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; + + struct grub_efi_guid + { +@@ -889,6 +906,8 @@ struct grub_efi_ipv6_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_uint8_t prefix_length; ++ grub_efi_ipv6_address_t gateway_ip_address; + } GRUB_PACKED; + typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; + +@@ -938,6 +957,15 @@ struct grub_efi_uri_device_path + } GRUB_PACKED; + typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; + ++#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE 31 ++struct grub_efi_dns_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t is_ipv6; ++ grub_efi_pxe_ip_address_t dns_server_ip[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ +@@ -1020,6 +1048,23 @@ struct grub_efi_bios_device_path + } GRUB_PACKED; + typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; + ++/* Service Binding definitions */ ++struct grub_efi_service_binding; ++ ++typedef grub_efi_status_t ++(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef grub_efi_status_t ++(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef struct grub_efi_service_binding ++{ ++ grub_efi_service_binding_create_child create_child; ++ grub_efi_service_binding_destroy_child destroy_child; ++} grub_efi_service_binding_t; ++ + struct grub_efi_open_protocol_information_entry + { + grub_efi_handle_t agent_handle; +@@ -1569,23 +1614,27 @@ typedef struct grub_efi_pxe_tftp_error + grub_efi_char8_t error_string[127]; + } grub_efi_pxe_tftp_error_t; + +-typedef struct { +- grub_uint8_t addr[4]; +-} grub_efi_pxe_ipv4_address_t; ++typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t; + +-typedef struct { +- grub_uint8_t addr[16]; +-} grub_efi_pxe_ipv6_address_t; ++typedef enum { ++ GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST ++} grub_efi_pxe_base_code_tftp_opcode_t; + + typedef struct { +- grub_uint8_t addr[32]; +-} grub_efi_pxe_mac_address_t; +- +-typedef union { +- grub_uint32_t addr[4]; +- grub_efi_pxe_ipv4_address_t v4; +- grub_efi_pxe_ipv6_address_t v6; +-} grub_efi_pxe_ip_address_t; ++ grub_efi_ip_address_t mcast_ip; ++ grub_efi_pxe_base_code_udp_port_t c_port; ++ grub_efi_pxe_base_code_udp_port_t s_port; ++ grub_efi_uint16_t listen_timeout; ++ grub_efi_uint16_t transmit_timeout; ++} grub_efi_pxe_base_code_mtftp_info_t; + + #define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 + typedef struct grub_efi_pxe_ip_filter +@@ -1652,17 +1701,31 @@ typedef struct grub_efi_pxe_mode + typedef struct grub_efi_pxe + { + grub_uint64_t rev; +- void (*start) (void); ++ grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6); + void (*stop) (void); +- void (*dhcp) (void); ++ grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this, ++ grub_efi_boolean_t sort_offers); + void (*discover) (void); +- void (*mftp) (void); ++ grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this, ++ grub_efi_pxe_base_code_tftp_opcode_t operation, ++ void *buffer_ptr, ++ grub_efi_boolean_t overwrite, ++ grub_efi_uint64_t *buffer_size, ++ grub_efi_uintn_t *block_size, ++ grub_efi_pxe_ip_address_t *server_ip, ++ //grub_efi_ip_address_t *server_ip, ++ grub_efi_char8_t *filename, ++ grub_efi_pxe_base_code_mtftp_info_t *info, ++ grub_efi_boolean_t dont_use_buffer); + void (*udpwrite) (void); + void (*udpread) (void); + void (*setipfilter) (void); + void (*arp) (void); + void (*setparams) (void); +- void (*setstationip) (void); ++ grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this, ++ grub_efi_pxe_ip_address_t *new_station_ip, ++ grub_efi_pxe_ip_address_t *new_subnet_mask); ++ //void (*setstationip) (void); + void (*setpackets) (void); + struct grub_efi_pxe_mode *mode; + } grub_efi_pxe_t; +@@ -1924,6 +1987,44 @@ struct grub_efi_ip4_config2_protocol + }; + typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; + ++struct grub_efi_ip4_route_table { ++ grub_efi_ipv4_address_t subnet_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_ipv4_address_t gateway_address; ++}; ++ ++typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t; ++ ++#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 ++ ++struct grub_efi_ip4_config2_interface_info { ++ grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_ipv4_address_t station_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t route_table_size; ++ grub_efi_ip4_route_table_t *route_table; ++}; ++ ++typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t; ++ ++enum grub_efi_ip4_config2_policy { ++ GRUB_EFI_IP4_CONFIG2_POLICY_STATIC, ++ GRUB_EFI_IP4_CONFIG2_POLICY_DHCP, ++ GRUB_EFI_IP4_CONFIG2_POLICY_MAX ++}; ++ ++typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t; ++ ++struct grub_efi_ip4_config2_manual_address { ++ grub_efi_ipv4_address_t address; ++ grub_efi_ipv4_address_t subnet_mask; ++}; ++ ++typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t; ++ + enum grub_efi_ip6_config_data_type { + GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, +@@ -1958,6 +2059,49 @@ struct grub_efi_ip6_config_protocol + }; + typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; + ++enum grub_efi_ip6_config_policy { ++ GRUB_EFI_IP6_CONFIG_POLICY_MANUAL, ++ GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC ++}; ++typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t; ++ ++struct grub_efi_ip6_address_info { ++ grub_efi_ipv6_address_t address; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t; ++ ++struct grub_efi_ip6_route_table { ++ grub_efi_pxe_ipv6_address_t gateway; ++ grub_efi_pxe_ipv6_address_t destination; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t; ++ ++struct grub_efi_ip6_config_interface_info { ++ grub_efi_char16_t name[32]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_uint32_t address_info_count; ++ grub_efi_ip6_address_info_t *address_info; ++ grub_efi_uint32_t route_count; ++ grub_efi_ip6_route_table_t *route_table; ++}; ++typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t; ++ ++struct grub_efi_ip6_config_dup_addr_detect_transmits { ++ grub_efi_uint32_t dup_addr_detect_transmits; ++}; ++typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t; ++ ++struct grub_efi_ip6_config_manual_address { ++ grub_efi_ipv6_address_t address; ++ grub_efi_boolean_t is_anycast; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) +diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h +new file mode 100644 +index 0000000000..fdb88eb810 +--- /dev/null ++++ b/include/grub/efi/dhcp.h +@@ -0,0 +1,343 @@ ++#ifndef GRUB_EFI_DHCP_HEADER ++#define GRUB_EFI_DHCP_HEADER 1 ++ ++#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9d9a39d8, 0xbd42, 0x4a73, \ ++ { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \ ++ } ++ ++#define GRUB_EFI_DHCP4_PROTOCOL_GUID \ ++ { 0x8a219718, 0x4ef5, 0x4761, \ ++ { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9fb9a8a1, 0x2f4a, 0x43a6, \ ++ { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_PROTOCOL_GUID \ ++ { 0x87c8bad7, 0x595, 0x4053, \ ++ { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \ ++ } ++ ++typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t; ++ ++enum grub_efi_dhcp4_state { ++ GRUB_EFI_DHCP4_STOPPED, ++ GRUB_EFI_DHCP4_INIT, ++ GRUB_EFI_DHCP4_SELECTING, ++ GRUB_EFI_DHCP4_REQUESTING, ++ GRUB_EFI_DHCP4_BOUND, ++ GRUB_EFI_DHCP4_RENEWING, ++ GRUB_EFI_DHCP4_REBINDING, ++ GRUB_EFI_DHCP4_INIT_REBOOT, ++ GRUB_EFI_DHCP4_REBOOTING ++}; ++ ++typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t; ++ ++struct grub_efi_dhcp4_header { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t hw_type; ++ grub_efi_uint8_t hw_addr_len; ++ grub_efi_uint8_t hops; ++ grub_efi_uint32_t xid; ++ grub_efi_uint16_t seconds; ++ grub_efi_uint16_t reserved; ++ grub_efi_ipv4_address_t client_addr; ++ grub_efi_ipv4_address_t your_addr; ++ grub_efi_ipv4_address_t server_addr; ++ grub_efi_ipv4_address_t gateway_addr; ++ grub_efi_uint8_t client_hw_addr[16]; ++ grub_efi_char8_t server_name[64]; ++ grub_efi_char8_t boot_file_name[128]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t; ++ ++struct grub_efi_dhcp4_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp4_header_t header; ++ grub_efi_uint32_t magik; ++ grub_efi_uint8_t option[1]; ++ } dhcp4; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t; ++ ++struct grub_efi_dhcp4_listen_point { ++ grub_efi_ipv4_address_t listen_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint16_t listen_port; ++}; ++ ++typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t; ++ ++struct grub_efi_dhcp4_transmit_receive_token { ++ grub_efi_status_t status; ++ grub_efi_event_t completion_event; ++ grub_efi_ipv4_address_t remote_address; ++ grub_efi_uint16_t remote_port; ++ grub_efi_ipv4_address_t gateway_address; ++ grub_efi_uint32_t listen_point_count; ++ grub_efi_dhcp4_listen_point_t *listen_points; ++ grub_efi_uint32_t timeout_value; ++ grub_efi_dhcp4_packet_t *packet; ++ grub_efi_uint32_t response_count; ++ grub_efi_dhcp4_packet_t *response_list; ++}; ++ ++typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t; ++ ++enum grub_efi_dhcp4_event { ++ GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01, ++ GRUB_EFI_DHCP4_RCVD_OFFER, ++ GRUB_EFI_DHCP4_SELECT_OFFER, ++ GRUB_EFI_DHCP4_SEND_REQUEST, ++ GRUB_EFI_DHCP4_RCVD_ACK, ++ GRUB_EFI_DHCP4_RCVD_NAK, ++ GRUB_EFI_DHCP4_SEND_DECLINE, ++ GRUB_EFI_DHCP4_BOUND_COMPLETED, ++ GRUB_EFI_DHCP4_ENTER_RENEWING, ++ GRUB_EFI_DHCP4_ENTER_REBINDING, ++ GRUB_EFI_DHCP4_ADDRESS_LOST, ++ GRUB_EFI_DHCP4_FAIL ++}; ++ ++typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t; ++ ++struct grub_efi_dhcp4_packet_option { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t length; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t; ++ ++struct grub_efi_dhcp4_config_data { ++ grub_efi_uint32_t discover_try_count; ++ grub_efi_uint32_t *discover_timeout; ++ grub_efi_uint32_t request_try_count; ++ grub_efi_uint32_t *request_timeout; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_status_t (*dhcp4_callback) ( ++ grub_efi_dhcp4_protocol_t *this, ++ void *context, ++ grub_efi_dhcp4_state_t current_state, ++ grub_efi_dhcp4_event_t dhcp4_event, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_dhcp4_packet_t **new_packet ++ ); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp4_packet_option_t **option_list; ++}; ++ ++typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t; ++ ++struct grub_efi_dhcp4_mode_data { ++ grub_efi_dhcp4_state_t state; ++ grub_efi_dhcp4_config_data_t config_data; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_mac_address_t client_mac_address; ++ grub_efi_ipv4_address_t server_address; ++ grub_efi_ipv4_address_t router_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t lease_time; ++ grub_efi_dhcp4_packet_t *reply_packet; ++}; ++ ++typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t; ++ ++struct grub_efi_dhcp4_protocol { ++ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_mode_data_t *dhcp4_mode_data); ++ grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_config_data_t *dhcp4_cfg_data); ++ grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_boolean_t rebind_request, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *seed_packet, ++ grub_efi_uint32_t delete_count, ++ grub_efi_uint8_t *delete_list, ++ grub_efi_uint32_t append_count, ++ grub_efi_dhcp4_packet_option_t *append_list[], ++ grub_efi_dhcp4_packet_t **new_packet); ++ grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_transmit_receive_token_t *token); ++ grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp4_packet_option_t *packet_option_list[]); ++}; ++ ++typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t; ++ ++struct grub_efi_dhcp6_retransmission { ++ grub_efi_uint32_t irt; ++ grub_efi_uint32_t mrc; ++ grub_efi_uint32_t mrt; ++ grub_efi_uint32_t mrd; ++}; ++ ++typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t; ++ ++enum grub_efi_dhcp6_event { ++ GRUB_EFI_DHCP6_SEND_SOLICIT, ++ GRUB_EFI_DHCP6_RCVD_ADVERTISE, ++ GRUB_EFI_DHCP6_SELECT_ADVERTISE, ++ GRUB_EFI_DHCP6_SEND_REQUEST, ++ GRUB_EFI_DHCP6_RCVD_REPLY, ++ GRUB_EFI_DHCP6_RCVD_RECONFIGURE, ++ GRUB_EFI_DHCP6_SEND_DECLINE, ++ GRUB_EFI_DHCP6_SEND_CONFIRM, ++ GRUB_EFI_DHCP6_SEND_RELEASE, ++ GRUB_EFI_DHCP6_SEND_RENEW, ++ GRUB_EFI_DHCP6_SEND_REBIND ++}; ++ ++typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t; ++ ++struct grub_efi_dhcp6_packet_option { ++ grub_efi_uint16_t op_code; ++ grub_efi_uint16_t op_len; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t; ++ ++struct grub_efi_dhcp6_header { ++ grub_efi_uint32_t transaction_id:24; ++ grub_efi_uint32_t message_type:8; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t; ++ ++struct grub_efi_dhcp6_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp6_header_t header; ++ grub_efi_uint8_t option[1]; ++ } dhcp6; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t; ++ ++struct grub_efi_dhcp6_ia_address { ++ grub_efi_ipv6_address_t ip_address; ++ grub_efi_uint32_t preferred_lifetime; ++ grub_efi_uint32_t valid_lifetime; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t; ++ ++enum grub_efi_dhcp6_state { ++ GRUB_EFI_DHCP6_INIT, ++ GRUB_EFI_DHCP6_SELECTING, ++ GRUB_EFI_DHCP6_REQUESTING, ++ GRUB_EFI_DHCP6_DECLINING, ++ GRUB_EFI_DHCP6_CONFIRMING, ++ GRUB_EFI_DHCP6_RELEASING, ++ GRUB_EFI_DHCP6_BOUND, ++ GRUB_EFI_DHCP6_RENEWING, ++ GRUB_EFI_DHCP6_REBINDING ++}; ++ ++typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t; ++ ++#define GRUB_EFI_DHCP6_IA_TYPE_NA 3 ++#define GRUB_EFI_DHCP6_IA_TYPE_TA 4 ++ ++struct grub_efi_dhcp6_ia_descriptor { ++ grub_efi_uint16_t type; ++ grub_efi_uint32_t ia_id; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t; ++ ++struct grub_efi_dhcp6_ia { ++ grub_efi_dhcp6_ia_descriptor_t descriptor; ++ grub_efi_dhcp6_state_t state; ++ grub_efi_dhcp6_packet_t *reply_packet; ++ grub_efi_uint32_t ia_address_count; ++ grub_efi_dhcp6_ia_address_t ia_address[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t; ++ ++struct grub_efi_dhcp6_duid { ++ grub_efi_uint16_t length; ++ grub_efi_uint8_t duid[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t; ++ ++struct grub_efi_dhcp6_mode_data { ++ grub_efi_dhcp6_duid_t *client_id; ++ grub_efi_dhcp6_ia_t *ia; ++}; ++ ++typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t; ++ ++struct grub_efi_dhcp6_config_data { ++ grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this, ++ void *context, ++ grub_efi_dhcp6_state_t current_state, ++ grub_efi_dhcp6_event_t dhcp6_event, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_dhcp6_packet_t **new_packet); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp6_packet_option_t **option_list; ++ grub_efi_dhcp6_ia_descriptor_t ia_descriptor; ++ grub_efi_event_t ia_info_event; ++ grub_efi_boolean_t reconfigure_accept; ++ grub_efi_boolean_t rapid_commit; ++ grub_efi_dhcp6_retransmission_t *solicit_retransmission; ++}; ++ ++typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t; ++ ++struct grub_efi_dhcp6_protocol { ++ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_mode_data_t *dhcp6_mode_data, ++ grub_efi_dhcp6_config_data_t *dhcp6_config_data); ++ grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_config_data_t *dhcp6_cfg_data); ++ grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t send_client_id, ++ grub_efi_dhcp6_packet_option_t *option_request, ++ grub_efi_uint32_t option_count, ++ grub_efi_dhcp6_packet_option_t *option_list[], ++ grub_efi_dhcp6_retransmission_t *retransmission, ++ grub_efi_event_t timeout_event, ++ grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this, ++ void *context, ++ grub_efi_dhcp6_packet_t *packet), ++ void *callback_context); ++ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t rebind_request); ++ grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp6_packet_option_t *packet_option_list[]); ++}; ++ ++#endif /* ! GRUB_EFI_DHCP_HEADER */ +diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h +new file mode 100644 +index 0000000000..c5e9a89f50 +--- /dev/null ++++ b/include/grub/efi/http.h +@@ -0,0 +1,215 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_HTTP_HEADER ++#define GRUB_EFI_HTTP_HEADER 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0xbdc8e6af, 0xd9bc, 0x4379, \ ++ { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ ++ } ++ ++#define GRUB_EFI_HTTP_PROTOCOL_GUID \ ++ { 0x7A59B29B, 0x910B, 0x4171, \ ++ { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \ ++ } ++ ++#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s ++#define EFIHTTP_RX_BUF_LEN 10240 ++ ++//****************************************** ++// Protocol Interface Structure ++//****************************************** ++struct grub_efi_http; ++ ++//****************************************** ++// EFI_HTTP_VERSION ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPVERSION10, ++ GRUB_EFI_HTTPVERSION11, ++ GRUB_EFI_HTTPVERSIONUNSUPPORTED ++} grub_efi_http_version_t; ++ ++//****************************************** ++// EFI_HTTPv4_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_boolean_t use_default_address; ++ grub_efi_ipv4_address_t local_address; ++ grub_efi_ipv4_address_t local_subnet; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv4_access_point_t; ++ ++//****************************************** ++// EFI_HTTPv6_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_ipv6_address_t local_address; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv6_access_point_t; ++ ++//****************************************** ++// EFI_HTTP_CONFIG_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_version_t http_version; ++ grub_efi_uint32_t timeout_millisec; ++ grub_efi_boolean_t local_address_is_ipv6; ++ union { ++ grub_efi_httpv4_access_point_t *ipv4_node; ++ grub_efi_httpv6_access_point_t *ipv6_node; ++ } access_point; ++} grub_efi_http_config_data_t; ++ ++//****************************************** ++// EFI_HTTP_METHOD ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPMETHODGET, ++ GRUB_EFI_HTTPMETHODPOST, ++ GRUB_EFI_HTTPMETHODPATCH, ++ GRUB_EFI_HTTPMETHODOPTIONS, ++ GRUB_EFI_HTTPMETHODCONNECT, ++ GRUB_EFI_HTTPMETHODHEAD, ++ GRUB_EFI_HTTPMETHODPUT, ++ GRUB_EFI_HTTPMETHODDELETE, ++ GRUB_EFI_HTTPMETHODTRACE, ++} grub_efi_http_method_t; ++ ++//****************************************** ++// EFI_HTTP_REQUEST_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_method_t method; ++ grub_efi_char16_t *url; ++} grub_efi_http_request_data_t; ++ ++typedef enum { ++ GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, ++ GRUB_EFI_HTTP_STATUS_100_CONTINUE, ++ GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS, ++ GRUB_EFI_HTTP_STATUS_200_OK, ++ GRUB_EFI_HTTP_STATUS_201_CREATED, ++ GRUB_EFI_HTTP_STATUS_202_ACCEPTED, ++ GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, ++ GRUB_EFI_HTTP_STATUS_204_NO_CONTENT, ++ GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT, ++ GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT, ++ GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES, ++ GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY, ++ GRUB_EFI_HTTP_STATUS_302_FOUND, ++ GRUB_EFI_HTTP_STATUS_303_SEE_OTHER, ++ GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED, ++ GRUB_EFI_HTTP_STATUS_305_USE_PROXY, ++ GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT, ++ GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST, ++ GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED, ++ GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_403_FORBIDDEN, ++ GRUB_EFI_HTTP_STATUS_404_NOT_FOUND, ++ GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED, ++ GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE, ++ GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_409_CONFLICT, ++ GRUB_EFI_HTTP_STATUS_410_GONE, ++ GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED, ++ GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, ++ GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, ++ GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED, ++ GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR, ++ GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED, ++ GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY, ++ GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE, ++ GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED ++} grub_efi_http_status_code_t; ++ ++//****************************************** ++// EFI_HTTP_RESPONSE_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_status_code_t status_code; ++} grub_efi_http_response_data_t; ++ ++//****************************************** ++// EFI_HTTP_HEADER ++//****************************************** ++typedef struct { ++ grub_efi_char8_t *field_name; ++ grub_efi_char8_t *field_value; ++} grub_efi_http_header_t; ++ ++//****************************************** ++// EFI_HTTP_MESSAGE ++//****************************************** ++typedef struct { ++ union { ++ grub_efi_http_request_data_t *request; ++ grub_efi_http_response_data_t *response; ++ } data; ++ grub_efi_uint32_t header_count; ++ grub_efi_http_header_t *headers; ++ grub_efi_uint32_t body_length; ++ void *body; ++} grub_efi_http_message_t; ++ ++//****************************************** ++// EFI_HTTP_TOKEN ++//****************************************** ++typedef struct { ++ grub_efi_event_t event; ++ grub_efi_status_t status; ++ grub_efi_http_message_t *message; ++} grub_efi_http_token_t; ++ ++struct grub_efi_http { ++ grub_efi_status_t ++ (*get_mode_data) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (*configure) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (*request) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*cancel) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*response) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*poll) (struct grub_efi_http *this); ++}; ++typedef struct grub_efi_http grub_efi_http_t; ++ ++#endif /* !GRUB_EFI_HTTP_HEADER */ +diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h +new file mode 100644 +index 0000000000..de90d223e8 +--- /dev/null ++++ b/include/grub/net/efi.h +@@ -0,0 +1,144 @@ ++#ifndef GRUB_NET_EFI_HEADER ++#define GRUB_NET_EFI_HEADER 1 ++ ++#include ++#include ++#include ++#include ++ ++typedef struct grub_efi_net_interface grub_efi_net_interface_t; ++typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t; ++typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t; ++typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t; ++ ++struct grub_efi_net_interface ++{ ++ char *name; ++ int prefer_ip6; ++ struct grub_efi_net_device *dev; ++ struct grub_efi_net_io *io; ++ grub_efi_net_ip_config_t *ip_config; ++ int io_type; ++ struct grub_efi_net_interface *next; ++}; ++ ++#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev) ++#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev) ++#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev) ++#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet) ++#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr) ++#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr) ++ ++struct grub_efi_net_ip_config ++{ ++ char * (*get_hw_address) (struct grub_efi_net_device *dev); ++ char * (*get_address) (struct grub_efi_net_device *dev); ++ char ** (*get_route_table) (struct grub_efi_net_device *dev); ++ grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet); ++ int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns); ++}; ++ ++union grub_efi_net_ip_address ++{ ++ grub_efi_ipv4_address_t ip4; ++ grub_efi_ipv6_address_t ip6; ++}; ++ ++struct grub_efi_net_ip_manual_address ++{ ++ int is_ip6; ++ union ++ { ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ }; ++}; ++ ++struct grub_efi_net_device ++{ ++ grub_efi_handle_t handle; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t ip4_pxe_handle; ++ grub_efi_pxe_t *ip4_pxe; ++ grub_efi_handle_t ip6_pxe_handle; ++ grub_efi_pxe_t *ip6_pxe; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ char *card_name; ++ grub_efi_net_interface_t *net_interfaces; ++ struct grub_efi_net_device *next; ++}; ++ ++struct grub_efi_net_io ++{ ++ void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6); ++ grub_err_t (*open) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type); ++ grub_ssize_t (*read) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len); ++ grub_err_t (*close) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file); ++}; ++ ++extern struct grub_efi_net_device *net_devices; ++ ++extern struct grub_efi_net_io io_http; ++extern struct grub_efi_net_io io_pxe; ++ ++extern grub_efi_net_ip_config_t *efi_net_ip4_config; ++extern grub_efi_net_ip_config_t *efi_net_ip6_config; ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address); ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address); ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address); ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest); ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest); ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev); ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev); ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet); ++ ++int grub_efi_net_fs_init (void); ++void grub_efi_net_fs_fini (void); ++int grub_efi_net_boot_from_https (void); ++int grub_efi_net_boot_from_opa (void); ++ ++extern grub_command_func_t grub_efi_net_list_routes; ++extern grub_command_func_t grub_efi_net_list_cards; ++extern grub_command_func_t grub_efi_net_list_addrs; ++extern grub_command_func_t grub_efi_net_add_addr; ++extern grub_command_func_t grub_efi_net_bootp; ++extern grub_command_func_t grub_efi_net_bootp6; ++ ++#endif /* ! GRUB_NET_EFI_HEADER */ diff --git a/0079-efinet-Setting-DNS-server-from-UEFI-protocol.patch b/0079-efinet-Setting-DNS-server-from-UEFI-protocol.patch deleted file mode 100644 index 2d92ff0..0000000 --- a/0079-efinet-Setting-DNS-server-from-UEFI-protocol.patch +++ /dev/null @@ -1,336 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Thu, 14 Jul 2016 17:48:45 +0800 -Subject: [PATCH] efinet: Setting DNS server from UEFI protocol - -In the URI device path node, any name rahter than address can be used for -looking up the resources so that DNS service become needed to get answer of the -name's address. Unfortunately the DNS is not defined in any of the device path -nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL -to obtain it. - -These two protcols are defined the sections of UEFI specification. - - 27.5 EFI IPv4 Configuration II Protocol - 27.7 EFI IPv6 Configuration Protocol - -include/grub/efi/api.h: -Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and -EFI_IP6_CONFIG_PROTOCOL. - -grub-core/net/drivers/efi/efinet.c: -Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list -of DNS server address for IPv4 and IPv6 respectively. The address of DNS -servers is structured into DHCPACK packet and feed into the same DHCP packet -processing functions to ensure the network interface is setting up the same way -it used to be. - -Signed-off-by: Michael Chang -Signed-off-by: Ken Lin ---- - grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++ - include/grub/efi/api.h | 75 +++++++++++++++++ - 2 files changed, 238 insertions(+) - -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index 8171ecaa5e..715a6168d7 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -33,6 +33,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); - /* GUID. */ - static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; - static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; -+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; -+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; - - static grub_err_t - send_card_buffer (struct grub_net_card *dev, -@@ -332,6 +334,125 @@ grub_efinet_findcards (void) - grub_free (handles); - } - -+static grub_efi_handle_t -+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, -+ grub_efi_device_path_t **r_device_path) -+{ -+ grub_efi_handle_t handle; -+ grub_efi_status_t status; -+ -+ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, -+ protocol, &device_path, &handle); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ -+ if (r_device_path) -+ *r_device_path = device_path; -+ -+ return handle; -+} -+ -+static grub_efi_ipv4_address_t * -+grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) -+{ -+ grub_efi_handle_t hnd; -+ grub_efi_status_t status; -+ grub_efi_ip4_config2_protocol_t *conf; -+ grub_efi_ipv4_address_t *addrs; -+ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t); -+ -+ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL); -+ -+ if (!hnd) -+ return 0; -+ -+ conf = grub_efi_open_protocol (hnd, &ip4_config_guid, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ -+ if (!conf) -+ return 0; -+ -+ addrs = grub_malloc (data_size); -+ if (!addrs) -+ return 0; -+ -+ status = efi_call_4 (conf->get_data, conf, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, -+ &data_size, addrs); -+ -+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) -+ { -+ grub_free (addrs); -+ addrs = grub_malloc (data_size); -+ if (!addrs) -+ return 0; -+ -+ status = efi_call_4 (conf->get_data, conf, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, -+ &data_size, addrs); -+ } -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (addrs); -+ return 0; -+ } -+ -+ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t); -+ return addrs; -+} -+ -+static grub_efi_ipv6_address_t * -+grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) -+{ -+ grub_efi_handle_t hnd; -+ grub_efi_status_t status; -+ grub_efi_ip6_config_protocol_t *conf; -+ grub_efi_ipv6_address_t *addrs; -+ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t); -+ -+ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL); -+ -+ if (!hnd) -+ return 0; -+ -+ conf = grub_efi_open_protocol (hnd, &ip6_config_guid, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ -+ if (!conf) -+ return 0; -+ -+ addrs = grub_malloc (data_size); -+ if (!addrs) -+ return 0; -+ -+ status = efi_call_4 (conf->get_data, conf, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, -+ &data_size, addrs); -+ -+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) -+ { -+ grub_free (addrs); -+ addrs = grub_malloc (data_size); -+ if (!addrs) -+ return 0; -+ -+ status = efi_call_4 (conf->get_data, conf, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, -+ &data_size, addrs); -+ } -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (addrs); -+ return 0; -+ } -+ -+ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t); -+ return addrs; -+} -+ - static struct grub_net_buff * - grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) - { -@@ -390,6 +511,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u - grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; - struct grub_net_bootp_packet *bp; - grub_uint8_t *ptr; -+ grub_efi_ipv4_address_t *dns; -+ grub_efi_uintn_t num_dns; - - bp = (struct grub_net_bootp_packet *) nb->tail; - err = grub_netbuff_put (nb, sizeof (*bp) + 4); -@@ -451,6 +574,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u - *ptr++ = sizeof ("HTTPClient") - 1; - grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); - -+ dns = grub_dns_server_ip4_address (dp, &num_dns); -+ if (dns) -+ { -+ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; -+ -+ ptr = nb->tail; -+ err = grub_netbuff_put (nb, size_dns + 2); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ *ptr++ = GRUB_NET_BOOTP_DNS; -+ *ptr++ = size_dns; -+ grub_memcpy (ptr, dns, size_dns); -+ grub_free (dns); -+ } -+ - ptr = nb->tail; - err = grub_netbuff_put (nb, 1); - if (err) -@@ -483,6 +625,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u - struct grub_net_dhcp6_option *opt; - struct grub_net_dhcp6_option_iana *iana; - struct grub_net_dhcp6_option_iaaddr *iaaddr; -+ grub_efi_ipv6_address_t *dns; -+ grub_efi_uintn_t num_dns; - - d6p = (struct grub_net_dhcp6_packet *)nb->tail; - err = grub_netbuff_put (nb, sizeof(*d6p)); -@@ -546,6 +690,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u - opt->len = grub_cpu_to_be16 (uri_len); - grub_memcpy (opt->data, uri_dp->uri, uri_len); - -+ dns = grub_dns_server_ip6_address (dp, &num_dns); -+ if (dns) -+ { -+ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; -+ -+ opt = (struct grub_net_dhcp6_option *)nb->tail; -+ err = grub_netbuff_put (nb, sizeof(*opt) + size_dns); -+ if (err) -+ { -+ grub_free (ddp); -+ grub_netbuff_free (nb); -+ return NULL; -+ } -+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS); -+ opt->len = grub_cpu_to_be16 (size_dns); -+ grub_memcpy (opt->data, dns, size_dns); -+ grub_free (dns); -+ } -+ - *use_ipv6 = 1; - } - -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index 4a51667adb..0b490195ad 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -352,6 +352,15 @@ - #define GRUB_EFI_RNG_PROTOCOL_GUID \ - { 0x3152bca5, 0xeade, 0x433d, \ - { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ -+ -+#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \ -+ { 0x5b446ed1, 0xe30b, 0x4faa, \ -+ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ -+ } -+ -+#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \ -+ { 0x937fe521, 0x95ae, 0x4d1a, \ -+ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ - } - - struct grub_efi_sal_system_table -@@ -1883,6 +1892,72 @@ struct grub_efi_rng_protocol - }; - typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; - -+enum grub_efi_ip4_config2_data_type { -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM -+}; -+typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t; -+ -+struct grub_efi_ip4_config2_protocol -+{ -+ grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this, -+ grub_efi_ip4_config2_data_type_t data_type, -+ grub_efi_uintn_t data_size, -+ void *data); -+ -+ grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this, -+ grub_efi_ip4_config2_data_type_t data_type, -+ grub_efi_uintn_t *data_size, -+ void *data); -+ -+ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this, -+ grub_efi_ip4_config2_data_type_t data_type, -+ grub_efi_event_t event); -+ -+ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this, -+ grub_efi_ip4_config2_data_type_t data_type, -+ grub_efi_event_t event); -+}; -+typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; -+ -+enum grub_efi_ip6_config_data_type { -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM -+}; -+typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t; -+ -+struct grub_efi_ip6_config_protocol -+{ -+ grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this, -+ grub_efi_ip6_config_data_type_t data_type, -+ grub_efi_uintn_t data_size, -+ void *data); -+ -+ grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this, -+ grub_efi_ip6_config_data_type_t data_type, -+ grub_efi_uintn_t *data_size, -+ void *data); -+ -+ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this, -+ grub_efi_ip6_config_data_type_t data_type, -+ grub_efi_event_t event); -+ -+ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this, -+ grub_efi_ip6_config_data_type_t data_type, -+ grub_efi_event_t event); -+}; -+typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; -+ - #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ - || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ - || defined(__riscv) diff --git a/0080-AUDIT-0-http-boot-tracker-bug.patch b/0080-AUDIT-0-http-boot-tracker-bug.patch new file mode 100644 index 0000000..b487271 --- /dev/null +++ b/0080-AUDIT-0-http-boot-tracker-bug.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sebastian Krahmer +Date: Tue, 28 Nov 2017 17:24:38 +0800 +Subject: [PATCH] AUDIT-0: http boot tracker bug + +Fixing a memory leak in case of error, and a integer overflow, leading to a +heap overflow due to overly large chunk sizes. + +We need to check against some maximum value, otherwise values like 0xffffffff +will eventually lead in the allocation functions to small sized buffers, since +the len is rounded up to the next reasonable alignment. The following memcpy +will then smash the heap, leading to RCE. + +This is no big issue for pure http boot, since its going to execute an +untrusted kernel anyway, but it will break trusted boot scenarios, where only +signed code is allowed to be executed. + +Signed-off-by: Michael Chang +--- + grub-core/net/efi/net.c | 4 +++- + grub-core/net/http.c | 5 ++++- + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 86bce6535d..4bb308026c 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -645,8 +645,10 @@ grub_efihttp_chunk_read (grub_file_t file, char *buf, + + rd = efi_net_interface (read, file, chunk, sz); + +- if (rd <= 0) ++ if (rd <= 0) { ++ grub_free (chunk); + return rd; ++ } + + if (buf) + { +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 12a2632ea5..b52b558d63 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -31,7 +31,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + enum + { +- HTTP_PORT = 80 ++ HTTP_PORT = 80, ++ HTTP_MAX_CHUNK_SIZE = 0x80000000 + }; + + +@@ -78,6 +79,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + if (data->in_chunk_len == 2) + { + data->chunk_rem = grub_strtoul (ptr, 0, 16); ++ if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE) ++ return GRUB_ERR_NET_PACKET_TOO_BIG; + grub_errno = GRUB_ERR_NONE; + if (data->chunk_rem == 0) + { diff --git a/0080-Support-UEFI-networking-protocols.patch b/0080-Support-UEFI-networking-protocols.patch deleted file mode 100644 index 740a9f8..0000000 --- a/0080-Support-UEFI-networking-protocols.patch +++ /dev/null @@ -1,5053 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Wed, 22 Feb 2017 14:27:50 +0800 -Subject: [PATCH] Support UEFI networking protocols - -References: fate#320130, bsc#1015589, bsc#1076132 -Patch-Mainline: no - -V1: - * Add preliminary support of UEFI networking protocols - * Support UEFI HTTPS Boot - -V2: - * Workaround http data access in firmware - * Fix DNS device path parsing for efinet device - * Relaxed UEFI Protocol requirement - * Support Intel OPA (Omni-Path Architecture) PXE Boot - -V3: - * Fix bufio in calculating address of next_buf - * Check HTTP respond code - * Use HEAD request method to test before GET - * Finish HTTP transaction in one go - * Fix bsc#1076132 - -Signed-off-by: Michael Chang -[pjones: make efi_netfs not duplicate symbols from efinet] -Signed-off-by: Peter Jones ---- - grub-core/Makefile.core.def | 12 + - grub-core/io/bufio.c | 2 +- - grub-core/kern/efi/efi.c | 96 ++- - grub-core/net/drivers/efi/efinet.c | 27 + - grub-core/net/efi/dhcp.c | 397 ++++++++++ - grub-core/net/efi/efi_netfs.c | 57 ++ - grub-core/net/efi/http.c | 419 +++++++++++ - grub-core/net/efi/ip4_config.c | 398 ++++++++++ - grub-core/net/efi/ip6_config.c | 422 +++++++++++ - grub-core/net/efi/net.c | 1428 ++++++++++++++++++++++++++++++++++++ - grub-core/net/efi/pxe.c | 424 +++++++++++ - grub-core/net/net.c | 74 ++ - util/grub-mknetdir.c | 23 +- - include/grub/efi/api.h | 180 ++++- - include/grub/efi/dhcp.h | 343 +++++++++ - include/grub/efi/http.h | 215 ++++++ - include/grub/net/efi.h | 144 ++++ - 17 files changed, 4620 insertions(+), 41 deletions(-) - create mode 100644 grub-core/net/efi/dhcp.c - create mode 100644 grub-core/net/efi/efi_netfs.c - create mode 100644 grub-core/net/efi/http.c - create mode 100644 grub-core/net/efi/ip4_config.c - create mode 100644 grub-core/net/efi/ip6_config.c - create mode 100644 grub-core/net/efi/net.c - create mode 100644 grub-core/net/efi/pxe.c - create mode 100644 include/grub/efi/dhcp.h - create mode 100644 include/grub/efi/http.h - create mode 100644 include/grub/net/efi.h - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 4b7c45a7b0..c40170f2dd 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -2299,6 +2299,12 @@ module = { - common = hook/datehook.c; - }; - -+module = { -+ name = efi_netfs; -+ common = net/efi/efi_netfs.c; -+ enable = efi; -+}; -+ - module = { - name = net; - common = net/net.c; -@@ -2312,6 +2318,12 @@ module = { - common = net/ethernet.c; - common = net/arp.c; - common = net/netbuff.c; -+ efi = net/efi/net.c; -+ efi = net/efi/http.c; -+ efi = net/efi/pxe.c; -+ efi = net/efi/ip4_config.c; -+ efi = net/efi/ip6_config.c; -+ efi = net/efi/dhcp.c; - }; - - module = { -diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c -index a458c3aca7..1637731535 100644 ---- a/grub-core/io/bufio.c -+++ b/grub-core/io/bufio.c -@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len) - return res; - - /* Need to read some more. */ -- next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1); -+ next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size; - /* Now read between file->offset + res and bufio->buffer_at. */ - if (file->offset + res < next_buf) - { -diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c -index d6a2fb5778..2a446f5031 100644 ---- a/grub-core/kern/efi/efi.c -+++ b/grub-core/kern/efi/efi.c -@@ -755,7 +755,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) - { - grub_efi_ipv4_device_path_t *ipv4 - = (grub_efi_ipv4_device_path_t *) dp; -- grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", -+ grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x", - (unsigned) ipv4->local_ip_address[0], - (unsigned) ipv4->local_ip_address[1], - (unsigned) ipv4->local_ip_address[2], -@@ -768,33 +768,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) - (unsigned) ipv4->remote_port, - (unsigned) ipv4->protocol, - (unsigned) ipv4->static_ip_address); -+ if (len == sizeof (*ipv4)) -+ { -+ grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u", -+ (unsigned) ipv4->gateway_ip_address[0], -+ (unsigned) ipv4->gateway_ip_address[1], -+ (unsigned) ipv4->gateway_ip_address[2], -+ (unsigned) ipv4->gateway_ip_address[3], -+ (unsigned) ipv4->subnet_mask[0], -+ (unsigned) ipv4->subnet_mask[1], -+ (unsigned) ipv4->subnet_mask[2], -+ (unsigned) ipv4->subnet_mask[3]); -+ } -+ grub_printf (")"); - } - break; - case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: - { - grub_efi_ipv6_device_path_t *ipv6 - = (grub_efi_ipv6_device_path_t *) dp; -- grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", -- (unsigned) ipv6->local_ip_address[0], -- (unsigned) ipv6->local_ip_address[1], -- (unsigned) ipv6->local_ip_address[2], -- (unsigned) ipv6->local_ip_address[3], -- (unsigned) ipv6->local_ip_address[4], -- (unsigned) ipv6->local_ip_address[5], -- (unsigned) ipv6->local_ip_address[6], -- (unsigned) ipv6->local_ip_address[7], -- (unsigned) ipv6->remote_ip_address[0], -- (unsigned) ipv6->remote_ip_address[1], -- (unsigned) ipv6->remote_ip_address[2], -- (unsigned) ipv6->remote_ip_address[3], -- (unsigned) ipv6->remote_ip_address[4], -- (unsigned) ipv6->remote_ip_address[5], -- (unsigned) ipv6->remote_ip_address[6], -- (unsigned) ipv6->remote_ip_address[7], -+ grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x", -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]), -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]), -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]), -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]), -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]), -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]), -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]), -+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]), -+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]), - (unsigned) ipv6->local_port, - (unsigned) ipv6->remote_port, - (unsigned) ipv6->protocol, - (unsigned) ipv6->static_ip_address); -+ if (len == sizeof (*ipv6)) -+ { -+ grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", -+ (unsigned) ipv6->prefix_length, -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]), -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]), -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]), -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]), -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]), -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]), -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]), -+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7])); -+ } -+ grub_printf (")"); - } - break; - case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: -@@ -834,6 +861,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) - dump_vendor_path ("Messaging", - (grub_efi_vendor_device_path_t *) dp); - break; -+ case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE: -+ { -+ grub_efi_uri_device_path_t *uri -+ = (grub_efi_uri_device_path_t *) dp; -+ grub_printf ("/URI(%s)", uri->uri); -+ } -+ break; -+ case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE: -+ { -+ grub_efi_dns_device_path_t *dns -+ = (grub_efi_dns_device_path_t *) dp; -+ if (dns->is_ipv6) -+ { -+ grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)", -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16), -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])), -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16), -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])), -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16), -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])), -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16), -+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]))); -+ } -+ else -+ { -+ grub_printf ("/DNS(%d.%d.%d.%d)", -+ dns->dns_server_ip[0].v4.addr[0], -+ dns->dns_server_ip[0].v4.addr[1], -+ dns->dns_server_ip[0].v4.addr[2], -+ dns->dns_server_ip[0].v4.addr[3]); -+ } -+ } -+ break; - default: - grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); - break; -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index 715a6168d7..e11d759f19 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -491,6 +492,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u - - ldp = grub_efi_find_last_device_path (ddp); - -+ /* Skip the DNS Device */ -+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE -+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) -+ { -+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; -+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -+ ldp->length = sizeof (*ldp); -+ -+ ldp = grub_efi_find_last_device_path (ddp); -+ } -+ - if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE - || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE - && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) -@@ -760,6 +772,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE - || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE - && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE -+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE - && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) - continue; - dup_dp = grub_efi_duplicate_device_path (dp); -@@ -774,6 +787,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - dup_ldp->length = sizeof (*dup_ldp); - } - -+ dup_ldp = grub_efi_find_last_device_path (dup_dp); -+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) -+ { -+ dup_ldp = grub_efi_find_last_device_path (dup_dp); -+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; -+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -+ dup_ldp->length = sizeof (*dup_ldp); -+ } -+ - dup_ldp = grub_efi_find_last_device_path (dup_dp); - dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; - dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -@@ -845,6 +867,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - - GRUB_MOD_INIT(efinet) - { -+ if (grub_efi_net_config) -+ return; -+ - grub_efinet_findcards (); - grub_efi_net_config = grub_efi_net_config_real; - } -@@ -856,5 +881,7 @@ GRUB_MOD_FINI(efinet) - FOR_NET_CARDS_SAFE (card, next) - if (card->driver == &efidriver) - grub_net_card_unregister (card); -+ -+ grub_efi_net_config = NULL; - } - -diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c -new file mode 100644 -index 0000000000..dbef63d8c0 ---- /dev/null -+++ b/grub-core/net/efi/dhcp.c -@@ -0,0 +1,397 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef GRUB_EFI_NET_DEBUG -+static void -+dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode) -+{ -+ switch (mode->state) -+ { -+ case GRUB_EFI_DHCP4_STOPPED: -+ grub_printf ("STATE: STOPPED\n"); -+ break; -+ case GRUB_EFI_DHCP4_INIT: -+ grub_printf ("STATE: INIT\n"); -+ break; -+ case GRUB_EFI_DHCP4_SELECTING: -+ grub_printf ("STATE: SELECTING\n"); -+ break; -+ case GRUB_EFI_DHCP4_REQUESTING: -+ grub_printf ("STATE: REQUESTING\n"); -+ break; -+ case GRUB_EFI_DHCP4_BOUND: -+ grub_printf ("STATE: BOUND\n"); -+ break; -+ case GRUB_EFI_DHCP4_RENEWING: -+ grub_printf ("STATE: RENEWING\n"); -+ break; -+ case GRUB_EFI_DHCP4_REBINDING: -+ grub_printf ("STATE: REBINDING\n"); -+ break; -+ case GRUB_EFI_DHCP4_INIT_REBOOT: -+ grub_printf ("STATE: INIT_REBOOT\n"); -+ break; -+ case GRUB_EFI_DHCP4_REBOOTING: -+ grub_printf ("STATE: REBOOTING\n"); -+ break; -+ default: -+ grub_printf ("STATE: UNKNOWN\n"); -+ break; -+ } -+ -+ grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n", -+ mode->client_address[0], -+ mode->client_address[1], -+ mode->client_address[2], -+ mode->client_address[3]); -+ grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n", -+ mode->server_address[0], -+ mode->server_address[1], -+ mode->server_address[2], -+ mode->server_address[3]); -+ grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n", -+ mode->subnet_mask[0], -+ mode->subnet_mask[1], -+ mode->subnet_mask[2], -+ mode->subnet_mask[3]); -+ grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n", -+ mode->router_address[0], -+ mode->router_address[1], -+ mode->router_address[2], -+ mode->router_address[3]); -+} -+#endif -+ -+static grub_efi_ipv4_address_t * -+grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet) -+{ -+ grub_efi_dhcp4_packet_option_t **option_list; -+ grub_efi_status_t status; -+ grub_efi_uint32_t option_count = 0; -+ grub_efi_uint32_t i; -+ -+ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL); -+ -+ if (status != GRUB_EFI_BUFFER_TOO_SMALL) -+ return NULL; -+ -+ option_list = grub_malloc (option_count * sizeof(*option_list)); -+ if (!option_list) -+ return NULL; -+ -+ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (option_list); -+ return NULL; -+ } -+ -+ for (i = 0; i < option_count; ++i) -+ { -+ if (option_list[i]->op_code == 6) -+ { -+ grub_efi_ipv4_address_t *dns_address; -+ -+ if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0)) -+ continue; -+ -+ /* We only contact primary dns */ -+ dns_address = grub_malloc (sizeof (*dns_address)); -+ if (!dns_address) -+ { -+ grub_free (option_list); -+ return NULL; -+ } -+ grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address)); -+ grub_free (option_list); -+ return dns_address; -+ } -+ } -+ -+ grub_free (option_list); -+ return NULL; -+} -+ -+#if 0 -+/* Somehow this doesn't work ... */ -+static grub_err_t -+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), -+ int argc __attribute__ ((unused)), -+ char **args __attribute__ ((unused))) -+{ -+ struct grub_efi_net_device *dev; -+ for (dev = net_devices; dev; dev = dev->next) -+ { -+ grub_efi_pxe_t *pxe = dev->ip4_pxe; -+ grub_efi_pxe_mode_t *mode = pxe->mode; -+ grub_efi_status_t status; -+ -+ if (!mode->started) -+ { -+ status = efi_call_2 (pxe->start, pxe, 0); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ grub_printf ("Couldn't start PXE\n"); -+ } -+ -+ status = efi_call_2 (pxe->dhcp, pxe, 0); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("dhcp4 configure failed, %d\n", (int)status); -+ continue; -+ } -+ -+ dev->prefer_ip6 = 0; -+ } -+ -+ return GRUB_ERR_NONE; -+} -+#endif -+ -+static grub_err_t -+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), -+ int argc, -+ char **args) -+{ -+ struct grub_efi_net_device *netdev; -+ -+ for (netdev = net_devices; netdev; netdev = netdev->next) -+ { -+ grub_efi_status_t status; -+ grub_efi_dhcp4_mode_data_t mode; -+ grub_efi_dhcp4_config_data_t config; -+ grub_efi_dhcp4_packet_option_t *options; -+ grub_efi_ipv4_address_t *dns_address; -+ grub_efi_net_ip_manual_address_t net_ip; -+ grub_efi_net_ip_address_t ip_addr; -+ grub_efi_net_interface_t *inf = NULL; -+ -+ if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0) -+ continue; -+ -+ grub_memset (&config, 0, sizeof(config)); -+ -+ config.option_count = 1; -+ options = grub_malloc (sizeof(*options) + 2); -+ /* Parameter request list */ -+ options->op_code = 55; -+ options->length = 3; -+ /* subnet mask */ -+ options->data[0] = 1; -+ /* router */ -+ options->data[1] = 3; -+ /* DNS */ -+ options->data[2] = 6; -+ config.option_list = &options; -+ -+ /* FIXME: What if the dhcp has bounded */ -+ status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config); -+ grub_free (options); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("dhcp4 configure failed, %d\n", (int)status); -+ continue; -+ } -+ -+ status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("dhcp4 start failed, %d\n", (int)status); -+ continue; -+ } -+ -+ status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); -+ continue; -+ } -+ -+#ifdef GRUB_EFI_NET_DEBUG -+ dhcp4_mode_print (&mode); -+#endif -+ -+ for (inf = netdev->net_interfaces; inf; inf = inf->next) -+ if (inf->prefer_ip6 == 0) -+ break; -+ -+ grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address)); -+ grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask)); -+ -+ if (!inf) -+ { -+ char *name = grub_xasprintf ("%s:dhcp", netdev->card_name); -+ -+ net_ip.is_ip6 = 0; -+ inf = grub_efi_net_create_interface (netdev, -+ name, -+ &net_ip, -+ 1); -+ grub_free (name); -+ } -+ else -+ { -+ efi_net_interface_set_address (inf, &net_ip, 1); -+ } -+ -+ grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4)); -+ efi_net_interface_set_gateway (inf, &ip_addr); -+ -+ dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet); -+ if (dns_address) -+ efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address); -+ -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+ -+static grub_err_t -+grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), -+ int argc, -+ char **args) -+{ -+ struct grub_efi_net_device *dev; -+ grub_efi_uint32_t ia_id; -+ -+ for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++) -+ { -+ grub_efi_dhcp6_config_data_t config; -+ grub_efi_dhcp6_packet_option_t *option_list[1]; -+ grub_efi_dhcp6_packet_option_t *opt; -+ grub_efi_status_t status; -+ grub_efi_dhcp6_mode_data_t mode; -+ grub_efi_dhcp6_retransmission_t retrans; -+ grub_efi_net_ip_manual_address_t net_ip; -+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; -+ grub_efi_net_interface_t *inf = NULL; -+ -+ if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0) -+ continue; -+ -+ opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t)); -+ -+#define GRUB_EFI_DHCP6_OPT_ORO 6 -+ -+ opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO); -+ opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t)); -+ -+#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59 -+#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23 -+ -+ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL)); -+ grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t), -+ grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)); -+ -+ option_list[0] = opt; -+ retrans.irt = 4; -+ retrans.mrc = 4; -+ retrans.mrt = 32; -+ retrans.mrd = 60; -+ -+ config.dhcp6_callback = NULL; -+ config.callback_context = NULL; -+ config.option_count = 1; -+ config.option_list = option_list; -+ config.ia_descriptor.ia_id = ia_id; -+ config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA; -+ config.ia_info_event = NULL; -+ config.reconfigure_accept = 0; -+ config.rapid_commit = 0; -+ config.solicit_retransmission = &retrans; -+ -+ status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config); -+ grub_free (opt); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("dhcp6 configure failed, %d\n", (int)status); -+ continue; -+ } -+ status = efi_call_1 (dev->dhcp6->start, dev->dhcp6); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("dhcp6 start failed, %d\n", (int)status); -+ continue; -+ } -+ -+ status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); -+ continue; -+ } -+ -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ if (inf->prefer_ip6 == 1) -+ break; -+ -+ grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address)); -+ net_ip.ip6.prefix_length = 64; -+ net_ip.ip6.is_anycast = 0; -+ net_ip.is_ip6 = 1; -+ -+ if (!inf) -+ { -+ char *name = grub_xasprintf ("%s:dhcp", dev->card_name); -+ -+ inf = grub_efi_net_create_interface (dev, -+ name, -+ &net_ip, -+ 1); -+ grub_free (name); -+ } -+ else -+ { -+ efi_net_interface_set_address (inf, &net_ip, 1); -+ } -+ -+ { -+ grub_efi_uint32_t count = 0; -+ grub_efi_dhcp6_packet_option_t **options = NULL; -+ grub_efi_uint32_t i; -+ -+ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL); -+ -+ if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) -+ { -+ options = grub_malloc (count * sizeof(*options)); -+ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); -+ } -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ if (options) -+ grub_free (options); -+ continue; -+ } -+ -+ for (i = 0; i < count; ++i) -+ { -+ if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)) -+ { -+ grub_efi_net_ip_address_t dns; -+ grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6)); -+ efi_net_interface_set_dns (inf, &dns); -+ break; -+ } -+ } -+ -+ if (options) -+ grub_free (options); -+ } -+ -+ efi_call_1 (b->free_pool, mode.client_id); -+ efi_call_1 (b->free_pool, mode.ia); -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp; -+grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6; -diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c -new file mode 100644 -index 0000000000..ef371d885e ---- /dev/null -+++ b/grub-core/net/efi/efi_netfs.c -@@ -0,0 +1,57 @@ -+#include -+#include -+#define EFI_NET_CMD_PREFIX "net_efi" -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static grub_command_t cmd_efi_lsroutes; -+static grub_command_t cmd_efi_lscards; -+static grub_command_t cmd_efi_lsaddrs; -+static grub_command_t cmd_efi_addaddr; -+static grub_command_t cmd_efi_bootp; -+static grub_command_t cmd_efi_bootp6; -+ -+static int initialized; -+ -+GRUB_MOD_INIT(efi_netfs) -+{ -+ if (grub_net_open) -+ return; -+ -+ if (grub_efi_net_fs_init ()) -+ { -+ cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes, -+ "", N_("list network routes")); -+ cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards, -+ "", N_("list network cards")); -+ cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs, -+ "", N_("list network addresses")); -+ cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr, -+ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), -+ N_("Add a network address.")); -+ cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp, -+ N_("[CARD]"), -+ N_("perform a bootp autoconfiguration")); -+ cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6, -+ N_("[CARD]"), -+ N_("perform a bootp autoconfiguration")); -+ initialized = 1; -+ } -+} -+ -+GRUB_MOD_FINI(efi_netfs) -+{ -+ if (initialized) -+ { -+ grub_unregister_command (cmd_efi_lsroutes); -+ grub_unregister_command (cmd_efi_lscards); -+ grub_unregister_command (cmd_efi_lsaddrs); -+ grub_unregister_command (cmd_efi_addaddr); -+ grub_unregister_command (cmd_efi_bootp); -+ grub_unregister_command (cmd_efi_bootp6); -+ grub_efi_net_fs_fini (); -+ initialized = 0; -+ return; -+ } -+} -diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c -new file mode 100644 -index 0000000000..3f61fd2fa5 ---- /dev/null -+++ b/grub-core/net/efi/http.c -@@ -0,0 +1,419 @@ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static void -+http_configure (struct grub_efi_net_device *dev, int prefer_ip6) -+{ -+ grub_efi_http_config_data_t http_config; -+ grub_efi_httpv4_access_point_t httpv4_node; -+ grub_efi_httpv6_access_point_t httpv6_node; -+ grub_efi_status_t status; -+ -+ grub_efi_http_t *http = dev->http; -+ -+ grub_memset (&http_config, 0, sizeof(http_config)); -+ http_config.http_version = GRUB_EFI_HTTPVERSION11; -+ http_config.timeout_millisec = 5000; -+ -+ if (prefer_ip6) -+ { -+ grub_efi_uintn_t sz; -+ grub_efi_ip6_config_manual_address_t manual_address; -+ -+ http_config.local_address_is_ipv6 = 1; -+ sz = sizeof (manual_address); -+ status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, -+ &sz, &manual_address); -+ -+ if (status == GRUB_EFI_NOT_FOUND) -+ { -+ grub_printf ("The MANUAL ADDRESS is not found\n"); -+ } -+ -+ /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_printf ("??? %d\n",(int) status); -+ return; -+ } -+ -+ grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address)); -+ httpv6_node.local_port = 0; -+ http_config.access_point.ipv6_node = &httpv6_node; -+ } -+ else -+ { -+ http_config.local_address_is_ipv6 = 0; -+ grub_memset (&httpv4_node, 0, sizeof(httpv4_node)); -+ httpv4_node.use_default_address = 1; -+ -+ /* Use random port here */ -+ /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */ -+ httpv4_node.local_port = 0; -+ http_config.access_point.ipv4_node = &httpv4_node; -+ } -+ -+ status = efi_call_2 (http->configure, http, &http_config); -+ -+ if (status == GRUB_EFI_ALREADY_STARTED) -+ { -+ /* XXX: This hangs HTTPS boot */ -+#if 0 -+ if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS) -+ { -+ grub_error (GRUB_ERR_IO, N_("couldn't reset http instance")); -+ grub_print_error (); -+ return; -+ } -+ status = efi_call_2 (http->configure, http, &http_config); -+#endif -+ return; -+ } -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status); -+ grub_print_error (); -+ return ; -+ } -+} -+ -+static grub_efi_boolean_t request_callback_done; -+static grub_efi_boolean_t response_callback_done; -+ -+static void -+grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), -+ void *context __attribute__ ((unused))) -+{ -+ request_callback_done = 1; -+} -+ -+static void -+grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)), -+ void *context __attribute__ ((unused))) -+{ -+ response_callback_done = 1; -+} -+ -+static grub_err_t -+efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size) -+{ -+ grub_efi_http_request_data_t request_data; -+ grub_efi_http_message_t request_message; -+ grub_efi_http_token_t request_token; -+ grub_efi_http_response_data_t response_data; -+ grub_efi_http_message_t response_message; -+ grub_efi_http_token_t response_token; -+ grub_efi_http_header_t request_headers[3]; -+ -+ grub_efi_status_t status; -+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; -+ char *url = NULL; -+ -+ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; -+ request_headers[0].field_value = (grub_efi_char8_t *)server; -+ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; -+ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; -+ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; -+ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; -+ -+ { -+ grub_efi_ipv6_address_t address; -+ const char *rest; -+ grub_efi_char16_t *ucs2_url; -+ grub_size_t url_len, ucs2_url_len; -+ const char *protocol = (use_https == 1) ? "https" : "http"; -+ -+ if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) -+ url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); -+ else -+ url = grub_xasprintf ("%s://%s%s", protocol, server, name); -+ -+ if (!url) -+ { -+ return grub_errno; -+ } -+ -+ url_len = grub_strlen (url); -+ ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8; -+ ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0])); -+ -+ if (!ucs2_url) -+ { -+ grub_free (url); -+ return grub_errno; -+ } -+ -+ ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ -+ ucs2_url[ucs2_url_len] = 0; -+ grub_free (url); -+ request_data.url = ucs2_url; -+ } -+ -+ request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; -+ -+ request_message.data.request = &request_data; -+ request_message.header_count = 3; -+ request_message.headers = request_headers; -+ request_message.body_length = 0; -+ request_message.body = NULL; -+ -+ /* request token */ -+ request_token.event = NULL; -+ request_token.status = GRUB_EFI_NOT_READY; -+ request_token.message = &request_message; -+ -+ request_callback_done = 0; -+ status = efi_call_5 (b->create_event, -+ GRUB_EFI_EVT_NOTIFY_SIGNAL, -+ GRUB_EFI_TPL_CALLBACK, -+ grub_efi_http_request_callback, -+ NULL, -+ &request_token.event); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (request_data.url); -+ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); -+ } -+ -+ status = efi_call_2 (http->request, http, &request_token); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ efi_call_1 (b->close_event, request_token.event); -+ grub_free (request_data.url); -+ return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status); -+ } -+ /* TODO: Add Timeout */ -+ while (!request_callback_done) -+ efi_call_1(http->poll, http); -+ -+ response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; -+ response_message.data.response = &response_data; -+ /* herader_count will be updated by the HTTP driver on response */ -+ response_message.header_count = 0; -+ /* headers will be populated by the driver on response */ -+ response_message.headers = NULL; -+ /* use zero BodyLength to only receive the response headers */ -+ response_message.body_length = 0; -+ response_message.body = NULL; -+ response_token.event = NULL; -+ -+ status = efi_call_5 (b->create_event, -+ GRUB_EFI_EVT_NOTIFY_SIGNAL, -+ GRUB_EFI_TPL_CALLBACK, -+ grub_efi_http_response_callback, -+ NULL, -+ &response_token.event); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ efi_call_1 (b->close_event, request_token.event); -+ grub_free (request_data.url); -+ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); -+ } -+ -+ response_token.status = GRUB_EFI_SUCCESS; -+ response_token.message = &response_message; -+ -+ /* wait for HTTP response */ -+ response_callback_done = 0; -+ status = efi_call_2 (http->response, http, &response_token); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ efi_call_1 (b->close_event, response_token.event); -+ efi_call_1 (b->close_event, request_token.event); -+ grub_free (request_data.url); -+ return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status); -+ } -+ -+ /* TODO: Add Timeout */ -+ while (!response_callback_done) -+ efi_call_1 (http->poll, http); -+ -+ if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK) -+ { -+ grub_efi_http_status_code_t status_code = response_message.data.response->status_code; -+ -+ if (response_message.headers) -+ efi_call_1 (b->free_pool, response_message.headers); -+ efi_call_1 (b->close_event, response_token.event); -+ efi_call_1 (b->close_event, request_token.event); -+ grub_free (request_data.url); -+ if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND) -+ { -+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name); -+ } -+ else -+ { -+ return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR, -+ _("unsupported uefi http status code 0x%x"), status_code); -+ } -+ } -+ -+ if (file_size) -+ { -+ int i; -+ /* parse the length of the file from the ContentLength header */ -+ for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i) -+ { -+ if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length")) -+ { -+ *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10); -+ break; -+ } -+ } -+ } -+ -+ if (response_message.headers) -+ efi_call_1 (b->free_pool, response_message.headers); -+ efi_call_1 (b->close_event, response_token.event); -+ efi_call_1 (b->close_event, request_token.event); -+ grub_free (request_data.url); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_ssize_t -+efihttp_read (struct grub_efi_net_device *dev, -+ char *buf, -+ grub_size_t len) -+{ -+ grub_efi_http_message_t response_message; -+ grub_efi_http_token_t response_token; -+ -+ grub_efi_status_t status; -+ grub_size_t sum = 0; -+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; -+ grub_efi_http_t *http = dev->http; -+ -+ if (!len) -+ { -+ grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read"); -+ return -1; -+ } -+ -+ efi_call_5 (b->create_event, -+ GRUB_EFI_EVT_NOTIFY_SIGNAL, -+ GRUB_EFI_TPL_CALLBACK, -+ grub_efi_http_response_callback, -+ NULL, -+ &response_token.event); -+ -+ while (len) -+ { -+ response_message.data.response = NULL; -+ response_message.header_count = 0; -+ response_message.headers = NULL; -+ response_message.body_length = len; -+ response_message.body = buf; -+ -+ response_token.message = &response_message; -+ response_token.status = GRUB_EFI_NOT_READY; -+ -+ response_callback_done = 0; -+ -+ status = efi_call_2 (http->response, http, &response_token); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ efi_call_1 (b->close_event, response_token.event); -+ grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status); -+ return -1; -+ } -+ -+ while (!response_callback_done) -+ efi_call_1(http->poll, http); -+ -+ sum += response_message.body_length; -+ buf += response_message.body_length; -+ len -= response_message.body_length; -+ } -+ -+ efi_call_1 (b->close_event, response_token.event); -+ -+ return sum; -+} -+ -+static grub_err_t -+grub_efihttp_open (struct grub_efi_net_device *dev, -+ int prefer_ip6 __attribute__ ((unused)), -+ grub_file_t file, -+ const char *filename __attribute__ ((unused)), -+ int type) -+{ -+ grub_err_t err; -+ grub_off_t size; -+ char *buf; -+ -+ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); -+ if (err != GRUB_ERR_NONE) -+ return err; -+ -+ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); -+ if (err != GRUB_ERR_NONE) -+ return err; -+ -+ buf = grub_malloc (size); -+ efihttp_read (dev, buf, size); -+ -+ file->size = size; -+ file->data = buf; -+ file->not_easily_seekable = 0; -+ file->device->net->offset = 0; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)), -+ int prefer_ip6 __attribute__ ((unused)), -+ grub_file_t file) -+{ -+ if (file->data) -+ grub_free (file->data); -+ -+ file->data = 0; -+ file->offset = 0; -+ file->size = 0; -+ file->device->net->offset = 0; -+ return GRUB_ERR_NONE; -+} -+ -+static grub_ssize_t -+grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)), -+ int prefer_ip6 __attribute__((unused)), -+ grub_file_t file, -+ char *buf, -+ grub_size_t len) -+{ -+ grub_size_t r = len; -+ -+ if (!file->data || !buf || !len) -+ return 0; -+ -+ if ((file->device->net->offset + len) > file->size) -+ r = file->size - file->device->net->offset; -+ -+ if (r) -+ { -+ grub_memcpy (buf, (char *)file->data + file->device->net->offset, r); -+ file->device->net->offset += r; -+ } -+ -+ return r; -+} -+ -+struct grub_efi_net_io io_http = -+ { -+ .configure = http_configure, -+ .open = grub_efihttp_open, -+ .read = grub_efihttp_read, -+ .close = grub_efihttp_close -+ }; -diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c -new file mode 100644 -index 0000000000..b711a5d945 ---- /dev/null -+++ b/grub-core/net/efi/ip4_config.c -@@ -0,0 +1,398 @@ -+ -+#include -+#include -+#include -+#include -+#include -+ -+char * -+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) -+{ -+ char *hw_addr, *p; -+ int sz, s; -+ int i; -+ -+ sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1; -+ -+ hw_addr = grub_malloc (sz); -+ if (!hw_addr) -+ return NULL; -+ -+ p = hw_addr; -+ s = sz; -+ for (i = 0; i < (int)hw_address_size; i++) -+ { -+ grub_snprintf (p, sz, "%02x:", hw_address[i]); -+ p += sizeof ("XX:") - 1; -+ s -= sizeof ("XX:") - 1; -+ } -+ -+ hw_addr[sz - 2] = '\0'; -+ return hw_addr; -+} -+ -+char * -+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address) -+{ -+ char *addr; -+ -+ addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX")); -+ if (!addr) -+ return NULL; -+ -+ /* FIXME: Use grub_xasprintf ? */ -+ grub_snprintf (addr, -+ sizeof ("XXX.XXX.XXX.XXX"), -+ "%u.%u.%u.%u", -+ (*address)[0], -+ (*address)[1], -+ (*address)[2], -+ (*address)[3]); -+ -+ return addr; -+} -+ -+int -+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) -+{ -+ grub_uint32_t newip = 0; -+ int i; -+ const char *ptr = val; -+ -+ for (i = 0; i < 4; i++) -+ { -+ unsigned long t; -+ t = grub_strtoul (ptr, (char **) &ptr, 0); -+ if (grub_errno) -+ { -+ grub_errno = GRUB_ERR_NONE; -+ return 0; -+ } -+ if (*ptr != '.' && i == 0) -+ { -+ /* XXX: t is in host byte order */ -+ newip = t; -+ break; -+ } -+ if (t & ~0xff) -+ return 0; -+ newip <<= 8; -+ newip |= t; -+ if (i != 3 && *ptr != '.') -+ return 0; -+ ptr++; -+ } -+ -+ newip = grub_cpu_to_be32 (newip); -+ -+ grub_memcpy (address, &newip, sizeof(*address)); -+ -+ if (rest) -+ *rest = (ptr - 1); -+ return 1; -+} -+ -+static grub_efi_ip4_config2_interface_info_t * -+efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config) -+{ -+ grub_efi_uintn_t sz; -+ grub_efi_status_t status; -+ grub_efi_ip4_config2_interface_info_t *interface_info; -+ -+ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); -+ interface_info = grub_malloc (sz); -+ if (!interface_info) -+ return NULL; -+ -+ status = efi_call_4 (ip4_config->get_data, ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, -+ &sz, interface_info); -+ -+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) -+ { -+ grub_free (interface_info); -+ interface_info = grub_malloc (sz); -+ status = efi_call_4 (ip4_config->get_data, ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, -+ &sz, interface_info); -+ } -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (interface_info); -+ return NULL; -+ } -+ -+ return interface_info; -+} -+ -+static grub_efi_ip4_config2_manual_address_t * -+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) -+{ -+ grub_efi_uintn_t sz; -+ grub_efi_status_t status; -+ grub_efi_ip4_config2_manual_address_t *manual_address; -+ -+ sz = sizeof (*manual_address); -+ manual_address = grub_malloc (sz); -+ if (!manual_address) -+ return NULL; -+ -+ status = efi_call_4 (ip4_config->get_data, ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, -+ &sz, manual_address); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (manual_address); -+ return NULL; -+ } -+ -+ return manual_address; -+} -+ -+char * -+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip4_config2_interface_info_t *interface_info; -+ char *name; -+ -+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); -+ -+ if (!interface_info) -+ return NULL; -+ -+ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE -+ * GRUB_MAX_UTF8_PER_UTF16 + 1); -+ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, -+ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; -+ grub_free (interface_info); -+ return name; -+} -+ -+static char * -+grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip4_config2_interface_info_t *interface_info; -+ char *hw_addr; -+ -+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); -+ -+ if (!interface_info) -+ return NULL; -+ -+ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); -+ grub_free (interface_info); -+ -+ return hw_addr; -+} -+ -+static char * -+grub_efi_ip4_interface_address (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip4_config2_manual_address_t *manual_address; -+ char *addr; -+ -+ manual_address = efi_ip4_config_manual_address (dev->ip4_config); -+ -+ if (!manual_address) -+ return NULL; -+ -+ addr = grub_efi_ip4_address_to_string (&manual_address->address); -+ grub_free (manual_address); -+ return addr; -+} -+ -+ -+static int -+address_mask_size (grub_efi_ipv4_address_t *address) -+{ -+ grub_uint8_t i; -+ grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address)); -+ -+ if (u32_addr == 0) -+ return 0; -+ -+ for (i = 0; i < 32 ; ++i) -+ { -+ if (u32_addr == ((0xffffffff >> i) << i)) -+ return (32 - i); -+ } -+ -+ return -1; -+} -+ -+static char ** -+grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip4_config2_interface_info_t *interface_info; -+ char **ret; -+ int i, id; -+ -+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); -+ if (!interface_info) -+ return NULL; -+ -+ ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1)); -+ -+ if (!ret) -+ { -+ grub_free (interface_info); -+ return NULL; -+ } -+ -+ id = 0; -+ for (i = 0; i < (int)interface_info->route_table_size; i++) -+ { -+ char *subnet, *gateway, *mask; -+ grub_uint32_t u32_subnet, u32_gateway; -+ int mask_size; -+ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; -+ grub_efi_net_interface_t *inf; -+ char *interface_name = NULL; -+ -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ if (!inf->prefer_ip6) -+ interface_name = inf->name; -+ -+ u32_gateway = grub_get_unaligned32 (&route_table->gateway_address); -+ gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address); -+ u32_subnet = grub_get_unaligned32 (&route_table->subnet_address); -+ subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address); -+ mask_size = address_mask_size (&route_table->subnet_mask); -+ mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask); -+ if (u32_subnet && !u32_gateway && interface_name) -+ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); -+ else if (u32_subnet && u32_gateway) -+ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); -+ else if (!u32_subnet && u32_gateway) -+ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); -+ grub_free (subnet); -+ grub_free (gateway); -+ grub_free (mask); -+ } -+ -+ ret[id] = NULL; -+ grub_free (interface_info); -+ return ret; -+} -+ -+static grub_efi_net_interface_t * -+grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) -+{ -+ grub_efi_ip4_config2_interface_info_t *interface_info; -+ grub_efi_net_interface_t *inf; -+ int i; -+ grub_efi_ipv4_address_t *address = &ip_address->ip4; -+ -+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); -+ if (!interface_info) -+ return NULL; -+ -+ for (i = 0; i < (int)interface_info->route_table_size; i++) -+ { -+ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; -+ grub_uint32_t u32_address, u32_mask, u32_subnet; -+ -+ u32_address = grub_get_unaligned32 (address); -+ u32_subnet = grub_get_unaligned32 (route_table->subnet_address); -+ u32_mask = grub_get_unaligned32 (route_table->subnet_mask); -+ -+ /* SKIP Default GATEWAY */ -+ if (!u32_subnet && !u32_mask) -+ continue; -+ -+ if ((u32_address & u32_mask) == u32_subnet) -+ { -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ if (!inf->prefer_ip6) -+ { -+ grub_free (interface_info); -+ return inf; -+ } -+ } -+ } -+ -+ grub_free (interface_info); -+ return NULL; -+} -+ -+static int -+grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, -+ grub_efi_net_ip_manual_address_t *net_ip, -+ int with_subnet) -+{ -+ grub_efi_status_t status; -+ grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4; -+ -+ if (!with_subnet) -+ { -+ grub_efi_ip4_config2_manual_address_t *manual_address = -+ efi_ip4_config_manual_address (dev->ip4_config); -+ -+ if (manual_address) -+ { -+ grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask)); -+ grub_free (manual_address); -+ } -+ else -+ { -+ /* XXX: */ -+ address->subnet_mask[0] = 0xff; -+ address->subnet_mask[1] = 0xff; -+ address->subnet_mask[2] = 0xff; -+ address->subnet_mask[3] = 0; -+ } -+ } -+ -+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, -+ sizeof(*address), address); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ -+ return 1; -+} -+ -+static int -+grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev, -+ grub_efi_net_ip_address_t *address) -+{ -+ grub_efi_status_t status; -+ -+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, -+ sizeof (address->ip4), &address->ip4); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ return 1; -+} -+ -+/* FIXME: Multiple DNS */ -+static int -+grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev, -+ grub_efi_net_ip_address_t *address) -+{ -+ grub_efi_status_t status; -+ -+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, -+ sizeof (address->ip4), &address->ip4); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ return 1; -+} -+ -+grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t) -+ { -+ .get_hw_address = grub_efi_ip4_interface_hw_address, -+ .get_address = grub_efi_ip4_interface_address, -+ .get_route_table = grub_efi_ip4_interface_route_table, -+ .best_interface = grub_efi_ip4_interface_match, -+ .set_address = grub_efi_ip4_interface_set_manual_address, -+ .set_gateway = grub_efi_ip4_interface_set_gateway, -+ .set_dns = grub_efi_ip4_interface_set_dns -+ }; -diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c -new file mode 100644 -index 0000000000..017c4d05bc ---- /dev/null -+++ b/grub-core/net/efi/ip6_config.c -@@ -0,0 +1,422 @@ -+#include -+#include -+#include -+#include -+#include -+ -+char * -+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) -+{ -+ char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); -+ char *p; -+ int i; -+ int squash; -+ -+ if (!str) -+ return NULL; -+ -+ p = str; -+ squash = 0; -+ for (i = 0; i < 8; ++i) -+ { -+ grub_uint16_t addr; -+ -+ if (i == 7) -+ squash = 2; -+ -+ addr = grub_get_unaligned16 (address->addr + i * 2); -+ -+ if (grub_be_to_cpu16 (addr)) -+ { -+ char buf[sizeof ("XXXX")]; -+ if (i > 0) -+ *p++ = ':'; -+ grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr)); -+ grub_strcpy (p, buf); -+ p += grub_strlen (buf); -+ -+ if (squash == 1) -+ squash = 2; -+ } -+ else -+ { -+ if (squash == 0) -+ { -+ *p++ = ':'; -+ squash = 1; -+ } -+ else if (squash == 2) -+ { -+ *p++ = ':'; -+ *p++ = '0'; -+ } -+ } -+ } -+ *p = '\0'; -+ return str; -+} -+ -+int -+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest) -+{ -+ grub_uint16_t newip[8]; -+ const char *ptr = val; -+ int word, quaddot = -1; -+ int bracketed = 0; -+ -+ if (ptr[0] == '[') { -+ bracketed = 1; -+ ptr++; -+ } -+ -+ if (ptr[0] == ':' && ptr[1] != ':') -+ return 0; -+ if (ptr[0] == ':') -+ ptr++; -+ -+ for (word = 0; word < 8; word++) -+ { -+ unsigned long t; -+ if (*ptr == ':') -+ { -+ quaddot = word; -+ word--; -+ ptr++; -+ continue; -+ } -+ t = grub_strtoul (ptr, (char **) &ptr, 16); -+ if (grub_errno) -+ { -+ grub_errno = GRUB_ERR_NONE; -+ break; -+ } -+ if (t & ~0xffff) -+ return 0; -+ newip[word] = grub_cpu_to_be16 (t); -+ if (*ptr != ':') -+ break; -+ ptr++; -+ } -+ if (quaddot == -1 && word < 7) -+ return 0; -+ if (quaddot != -1) -+ { -+ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], -+ (word - quaddot + 1) * sizeof (newip[0])); -+ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); -+ } -+ grub_memcpy (address, newip, 16); -+ if (bracketed && *ptr == ']') { -+ ptr++; -+ } -+ if (rest) -+ *rest = ptr; -+ return 1; -+} -+ -+static grub_efi_ip6_config_interface_info_t * -+efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config) -+{ -+ grub_efi_uintn_t sz; -+ grub_efi_status_t status; -+ grub_efi_ip6_config_interface_info_t *interface_info; -+ -+ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); -+ interface_info = grub_malloc (sz); -+ -+ status = efi_call_4 (ip6_config->get_data, ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, -+ &sz, interface_info); -+ -+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) -+ { -+ grub_free (interface_info); -+ interface_info = grub_malloc (sz); -+ status = efi_call_4 (ip6_config->get_data, ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, -+ &sz, interface_info); -+ } -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (interface_info); -+ return NULL; -+ } -+ -+ return interface_info; -+} -+ -+static grub_efi_ip6_config_manual_address_t * -+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) -+{ -+ grub_efi_uintn_t sz; -+ grub_efi_status_t status; -+ grub_efi_ip6_config_manual_address_t *manual_address; -+ -+ sz = sizeof (*manual_address); -+ manual_address = grub_malloc (sz); -+ if (!manual_address) -+ return NULL; -+ -+ status = efi_call_4 (ip6_config->get_data, ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, -+ &sz, manual_address); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (manual_address); -+ return NULL; -+ } -+ -+ return manual_address; -+} -+ -+char * -+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip6_config_interface_info_t *interface_info; -+ char *name; -+ -+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); -+ -+ if (!interface_info) -+ return NULL; -+ -+ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE -+ * GRUB_MAX_UTF8_PER_UTF16 + 1); -+ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, -+ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; -+ grub_free (interface_info); -+ return name; -+} -+ -+static char * -+grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip6_config_interface_info_t *interface_info; -+ char *hw_addr; -+ -+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); -+ -+ if (!interface_info) -+ return NULL; -+ -+ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); -+ grub_free (interface_info); -+ -+ return hw_addr; -+} -+ -+static char * -+grub_efi_ip6_interface_address (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip6_config_manual_address_t *manual_address; -+ char *addr; -+ -+ manual_address = efi_ip6_config_manual_address (dev->ip6_config); -+ -+ if (!manual_address) -+ return NULL; -+ -+ addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address); -+ grub_free (manual_address); -+ return addr; -+} -+ -+static char ** -+grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) -+{ -+ grub_efi_ip6_config_interface_info_t *interface_info; -+ char **ret; -+ int i, id; -+ -+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); -+ if (!interface_info) -+ return NULL; -+ -+ ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1)); -+ -+ if (!ret) -+ { -+ grub_free (interface_info); -+ return NULL; -+ } -+ -+ id = 0; -+ for (i = 0; i < (int)interface_info->route_count ; i++) -+ { -+ char *gateway, *destination; -+ grub_uint64_t u64_gateway[2]; -+ grub_uint64_t u64_destination[2]; -+ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; -+ grub_efi_net_interface_t *inf; -+ char *interface_name = NULL; -+ -+ gateway = grub_efi_ip6_address_to_string (&route_table->gateway); -+ destination = grub_efi_ip6_address_to_string (&route_table->destination); -+ -+ u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr); -+ u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8); -+ u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr); -+ u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8); -+ -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ if (inf->prefer_ip6) -+ interface_name = inf->name; -+ -+ if ((!u64_gateway[0] && !u64_gateway[1]) -+ && (u64_destination[0] || u64_destination[1])) -+ { -+ if (interface_name) -+ { -+ if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL) -+ && (!u64_destination[1]) -+ && (route_table->prefix_length == 64)) -+ ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); -+ else -+ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); -+ } -+ } -+ else if ((u64_gateway[0] || u64_gateway[1]) -+ && (u64_destination[0] || u64_destination[1])) -+ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); -+ else if ((u64_gateway[0] || u64_gateway[1]) -+ && (!u64_destination[0] && !u64_destination[1])) -+ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); -+ -+ grub_free (gateway); -+ grub_free (destination); -+ } -+ -+ ret[id] = NULL; -+ grub_free (interface_info); -+ return ret; -+} -+ -+static grub_efi_net_interface_t * -+grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) -+{ -+ grub_efi_ip6_config_interface_info_t *interface_info; -+ grub_efi_net_interface_t *inf; -+ int i; -+ grub_efi_ipv6_address_t *address = &ip_address->ip6; -+ -+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); -+ if (!interface_info) -+ return NULL; -+ -+ for (i = 0; i < (int)interface_info->route_count ; i++) -+ { -+ grub_uint64_t u64_addr[2]; -+ grub_uint64_t u64_subnet[2]; -+ grub_uint64_t u64_mask[2]; -+ -+ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; -+ -+ /* SKIP Default GATEWAY */ -+ if (route_table->prefix_length == 0) -+ continue; -+ -+ u64_addr[0] = grub_get_unaligned64 (address); -+ u64_addr[1] = grub_get_unaligned64 (address + 4); -+ u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr); -+ u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8); -+ u64_mask[0] = (route_table->prefix_length <= 64) ? -+ 0xffffffffffffffffULL << (64 - route_table->prefix_length) : -+ 0xffffffffffffffffULL; -+ u64_mask[1] = (route_table->prefix_length <= 64) ? -+ 0 : -+ 0xffffffffffffffffULL << (128 - route_table->prefix_length); -+ -+ if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0]) -+ && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1])) -+ { -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ if (inf->prefer_ip6) -+ { -+ grub_free (interface_info); -+ return inf; -+ } -+ } -+ } -+ -+ grub_free (interface_info); -+ return NULL; -+} -+ -+static int -+grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev, -+ grub_efi_net_ip_manual_address_t *net_ip, -+ int with_subnet) -+{ -+ grub_efi_status_t status; -+ grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6; -+ -+ if (!with_subnet) -+ { -+ grub_efi_ip6_config_manual_address_t *manual_address = -+ efi_ip6_config_manual_address (dev->ip6_config); -+ -+ if (manual_address) -+ { -+ address->prefix_length = manual_address->prefix_length; -+ grub_free (manual_address); -+ } -+ else -+ { -+ /* XXX: */ -+ address->prefix_length = 64; -+ } -+ } -+ -+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, -+ sizeof(*address), address); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ -+ return 1; -+} -+ -+static int -+grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev, -+ grub_efi_net_ip_address_t *address) -+{ -+ grub_efi_status_t status; -+ -+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, -+ sizeof (address->ip6), &address->ip6); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ return 1; -+} -+ -+static int -+grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev, -+ grub_efi_net_ip_address_t *address) -+{ -+ -+ grub_efi_status_t status; -+ -+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, -+ sizeof (address->ip6), &address->ip6); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ return 1; -+} -+ -+grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t) -+ { -+ .get_hw_address = grub_efi_ip6_interface_hw_address, -+ .get_address = grub_efi_ip6_interface_address, -+ .get_route_table = grub_efi_ip6_interface_route_table, -+ .best_interface = grub_efi_ip6_interface_match, -+ .set_address = grub_efi_ip6_interface_set_manual_address, -+ .set_gateway = grub_efi_ip6_interface_set_gateway, -+ .set_dns = grub_efi_ip6_interface_set_dns -+ }; -diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c -new file mode 100644 -index 0000000000..86bce6535d ---- /dev/null -+++ b/grub-core/net/efi/net.c -@@ -0,0 +1,1428 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+#define GRUB_EFI_IP6_PREFIX_LENGTH 64 -+ -+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; -+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; -+static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; -+static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; -+static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; -+static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; -+static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; -+static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; -+static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID; -+ -+struct grub_efi_net_device *net_devices; -+ -+static char *default_server; -+static grub_efi_net_interface_t *net_interface; -+static grub_efi_net_interface_t *net_default_interface; -+ -+#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6) -+#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type) -+#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz) -+#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file) -+#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__) -+ -+static grub_efi_handle_t -+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, -+ grub_efi_device_path_t **r_device_path) -+{ -+ grub_efi_handle_t handle; -+ grub_efi_status_t status; -+ -+ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, -+ protocol, &device_path, &handle); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return 0; -+ -+ if (r_device_path) -+ *r_device_path = device_path; -+ -+ return handle; -+} -+ -+static int -+url_parse_fields (const char *url, char **proto, char **host, char **path) -+{ -+ const char *p, *ps; -+ grub_size_t l; -+ -+ *proto = *host = *path = NULL; -+ ps = p = url; -+ -+ while ((p = grub_strchr (p, ':'))) -+ { -+ if (grub_strlen (p) < sizeof ("://") - 1) -+ break; -+ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) -+ { -+ l = p - ps; -+ *proto = grub_malloc (l + 1); -+ if (!*proto) -+ { -+ grub_print_error (); -+ return 0; -+ } -+ -+ grub_memcpy (*proto, ps, l); -+ (*proto)[l] = '\0'; -+ p += sizeof ("://") - 1; -+ break; -+ } -+ ++p; -+ } -+ -+ if (!*proto) -+ { -+ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); -+ return 0; -+ } -+ -+ ps = p; -+ p = grub_strchr (p, '/'); -+ -+ if (!p) -+ { -+ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); -+ grub_free (*proto); -+ *proto = NULL; -+ return 0; -+ } -+ -+ l = p - ps; -+ -+ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') -+ { -+ *host = grub_malloc (l - 1); -+ if (!*host) -+ { -+ grub_print_error (); -+ grub_free (*proto); -+ *proto = NULL; -+ return 0; -+ } -+ grub_memcpy (*host, ps + 1, l - 2); -+ (*host)[l - 2] = 0; -+ } -+ else -+ { -+ *host = grub_malloc (l + 1); -+ if (!*host) -+ { -+ grub_print_error (); -+ grub_free (*proto); -+ *proto = NULL; -+ return 0; -+ } -+ grub_memcpy (*host, ps, l); -+ (*host)[l] = 0; -+ } -+ -+ *path = grub_strdup (p); -+ if (!*path) -+ { -+ grub_print_error (); -+ grub_free (*host); -+ grub_free (*proto); -+ *host = NULL; -+ *proto = NULL; -+ return 0; -+ } -+ return 1; -+} -+ -+static void -+url_get_boot_location (const char *url, char **device, char **path, int is_default) -+{ -+ char *protocol, *server, *file; -+ char *slash; -+ -+ if (!url_parse_fields (url, &protocol, &server, &file)) -+ return; -+ -+ if ((slash = grub_strrchr (file, '/'))) -+ *slash = 0; -+ else -+ *file = 0; -+ -+ *device = grub_xasprintf ("%s,%s", protocol, server); -+ *path = grub_strdup(file); -+ -+ if (is_default) -+ default_server = server; -+ else -+ grub_free (server); -+ -+ grub_free (protocol); -+ grub_free (file); -+} -+ -+static void -+pxe_get_boot_location (const struct grub_net_bootp_packet *bp, -+ char **device, -+ char **path, -+ int is_default) -+{ -+ char *server = grub_xasprintf ("%d.%d.%d.%d", -+ ((grub_uint8_t *) &bp->server_ip)[0], -+ ((grub_uint8_t *) &bp->server_ip)[1], -+ ((grub_uint8_t *) &bp->server_ip)[2], -+ ((grub_uint8_t *) &bp->server_ip)[3]); -+ -+ *device = grub_xasprintf ("tftp,%s", server); -+ -+ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); -+ -+ if (*path) -+ { -+ char *slash; -+ slash = grub_strrchr (*path, '/'); -+ if (slash) -+ *slash = 0; -+ else -+ **path = 0; -+ } -+ -+ if (is_default) -+ default_server = server; -+ else -+ grub_free (server); -+} -+ -+static void -+pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp, -+ grub_size_t dhcp_size, -+ char **device, -+ char **path) -+{ -+ -+ struct grub_net_dhcp6_option *dhcp_opt; -+ grub_size_t dhcp_remain_size; -+ *device = *path = 0; -+ -+ if (dhcp_size < sizeof (*dp)) -+ { -+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); -+ return; -+ } -+ -+ dhcp_remain_size = dhcp_size - sizeof (*dp); -+ dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options; -+ -+ while (dhcp_remain_size) -+ { -+ grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code); -+ grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len); -+ grub_uint16_t option_size = sizeof (*dhcp_opt) + len; -+ -+ if (dhcp_remain_size < option_size || code == 0) -+ break; -+ -+ if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL) -+ { -+ char *url = grub_malloc (len + 1); -+ -+ grub_memcpy (url, dhcp_opt->data, len); -+ url[len] = 0; -+ -+ url_get_boot_location ((const char *)url, device, path, 1); -+ grub_free (url); -+ break; -+ } -+ -+ dhcp_remain_size -= option_size; -+ dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size); -+ } -+} -+ -+static grub_efi_net_interface_t * -+grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp, -+ struct grub_efi_net_device *netdev, -+ char **device, -+ char **path) -+{ -+ grub_efi_net_interface_t *inf = NULL; -+ -+ while (1) -+ { -+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); -+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); -+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); -+ -+ if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) -+ { -+ if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) -+ { -+ grub_efi_uri_device_path_t *uri_dp; -+ uri_dp = (grub_efi_uri_device_path_t *) dp; -+ /* Beware that uri_dp->uri may not be null terminated */ -+ url_get_boot_location ((const char *)uri_dp->uri, device, path, 1); -+ } -+ else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) -+ { -+ grub_efi_net_ip_manual_address_t net_ip; -+ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp; -+ -+ if (inf) -+ continue; -+ grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address)); -+ grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask)); -+ net_ip.is_ip6 = 0; -+ inf = grub_efi_net_create_interface (netdev, -+ netdev->card_name, -+ &net_ip, -+ 1); -+ } -+ else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) -+ { -+ grub_efi_net_ip_manual_address_t net_ip; -+ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp; -+ -+ if (inf) -+ continue; -+ grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address)); -+ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; -+ net_ip.ip6.is_anycast = 0; -+ net_ip.is_ip6 = 1; -+ inf = grub_efi_net_create_interface (netdev, -+ netdev->card_name, -+ &net_ip, -+ 1); -+ } -+ } -+ -+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) -+ break; -+ dp = (grub_efi_device_path_t *) ((char *) dp + len); -+ } -+ -+ return inf; -+} -+ -+static grub_efi_net_interface_t * -+grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, -+ struct grub_efi_net_device *netdev, -+ char **device, -+ char **path) -+{ -+ grub_efi_pxe_t *pxe = NULL; -+ -+ if (hnd == netdev->ip4_pxe_handle) -+ pxe = netdev->ip4_pxe; -+ else if (hnd == netdev->ip6_pxe_handle) -+ pxe = netdev->ip6_pxe; -+ -+ if (!pxe) -+ return (grub_efi_net_config_from_device_path ( -+ grub_efi_get_device_path (hnd), -+ netdev, -+ device, -+ path)); -+ -+ if (pxe->mode->using_ipv6) -+ { -+ grub_efi_net_ip_manual_address_t net_ip; -+ -+ pxe_get_boot_location_v6 ( -+ (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack, -+ sizeof (pxe->mode->dhcp_ack), -+ device, -+ path); -+ -+ grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address)); -+ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; -+ net_ip.ip6.is_anycast = 0; -+ net_ip.is_ip6 = 1; -+ return (grub_efi_net_create_interface (netdev, -+ netdev->card_name, -+ &net_ip, -+ 1)); -+ } -+ else -+ { -+ grub_efi_net_ip_manual_address_t net_ip; -+ -+ pxe_get_boot_location ( -+ (const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack, -+ device, -+ path, -+ 1); -+ -+ grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address)); -+ grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask)); -+ net_ip.is_ip6 = 0; -+ return (grub_efi_net_create_interface (netdev, -+ netdev->card_name, -+ &net_ip, -+ 1)); -+ } -+} -+ -+static const char * -+grub_efi_net_var_get_address (struct grub_env_var *var, -+ const char *val __attribute__ ((unused))) -+{ -+ struct grub_efi_net_device *dev; -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ { -+ grub_efi_net_interface_t *inf; -+ -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ { -+ char *var_name; -+ -+ var_name = grub_xasprintf ("net_%s_ip", inf->name); -+ if (grub_strcmp (var_name, var->name) == 0) -+ return efi_net_interface_get_address (inf); -+ grub_free (var_name); -+ var_name = grub_xasprintf ("net_%s_mac", inf->name); -+ if (grub_strcmp (var_name, var->name) == 0) -+ return efi_net_interface_get_hw_address (inf); -+ grub_free (var_name); -+ } -+ } -+ -+ return NULL; -+} -+ -+static char * -+grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val) -+{ -+ struct grub_efi_net_device *dev; -+ grub_efi_net_interface_t *inf; -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ if (grub_strcmp (inf->name, val) == 0) -+ { -+ net_default_interface = inf; -+ return grub_strdup (val); -+ } -+ -+ return NULL; -+} -+ -+static char * -+grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val) -+{ -+ grub_free (default_server); -+ default_server = grub_strdup (val); -+ return grub_strdup (val); -+} -+ -+static const char * -+grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val __attribute__ ((unused))) -+{ -+ return default_server ? : ""; -+} -+ -+static const char * -+grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val __attribute__ ((unused))) -+{ -+ const char *intf = grub_env_get ("net_default_interface"); -+ const char *ret = NULL; -+ if (intf) -+ { -+ char *buf = grub_xasprintf ("net_%s_ip", intf); -+ if (buf) -+ ret = grub_env_get (buf); -+ grub_free (buf); -+ } -+ return ret; -+} -+ -+static const char * -+grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val __attribute__ ((unused))) -+{ -+ const char *intf = grub_env_get ("net_default_interface"); -+ const char *ret = NULL; -+ if (intf) -+ { -+ char *buf = grub_xasprintf ("net_%s_mac", intf); -+ if (buf) -+ ret = grub_env_get (buf); -+ grub_free (buf); -+ } -+ return ret; -+} -+ -+static void -+grub_efi_net_export_interface_vars (void) -+{ -+ struct grub_efi_net_device *dev; -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ { -+ grub_efi_net_interface_t *inf; -+ -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ { -+ char *var; -+ -+ var = grub_xasprintf ("net_%s_ip", inf->name); -+ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); -+ grub_env_export (var); -+ grub_free (var); -+ var = grub_xasprintf ("net_%s_mac", inf->name); -+ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); -+ grub_env_export (var); -+ grub_free (var); -+ } -+ } -+} -+ -+static void -+grub_efi_net_unset_interface_vars (void) -+{ -+ struct grub_efi_net_device *dev; -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ { -+ grub_efi_net_interface_t *inf; -+ -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ { -+ char *var; -+ -+ var = grub_xasprintf ("net_%s_ip", inf->name); -+ grub_register_variable_hook (var, 0, 0); -+ grub_env_unset (var); -+ grub_free (var); -+ var = grub_xasprintf ("net_%s_mac", inf->name); -+ grub_register_variable_hook (var, 0, 0); -+ grub_env_unset (var); -+ grub_free (var); -+ } -+ } -+} -+ -+grub_efi_net_interface_t * -+grub_efi_net_create_interface (struct grub_efi_net_device *dev, -+ const char *interface_name, -+ grub_efi_net_ip_manual_address_t *net_ip, -+ int has_subnet) -+{ -+ grub_efi_net_interface_t *inf; -+ -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ { -+ if (inf->prefer_ip6 == net_ip->is_ip6) -+ break; -+ } -+ -+ if (!inf) -+ { -+ inf = grub_malloc (sizeof(*inf)); -+ inf->name = grub_strdup (interface_name); -+ inf->prefer_ip6 = net_ip->is_ip6; -+ inf->dev = dev; -+ inf->next = dev->net_interfaces; -+ inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ; -+ dev->net_interfaces = inf; -+ } -+ else -+ { -+ grub_free (inf->name); -+ inf->name = grub_strdup (interface_name); -+ } -+ -+ if (!efi_net_interface_set_address (inf, net_ip, has_subnet)) -+ { -+ grub_error (GRUB_ERR_BUG, N_("Set Address Failed")); -+ return NULL; -+ } -+ -+ return inf; -+} -+ -+static void -+grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, -+ char **path) -+{ -+ grub_efi_handle_t config_hnd; -+ -+ struct grub_efi_net_device *netdev; -+ grub_efi_net_interface_t *inf; -+ -+ config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL); -+ -+ if (!config_hnd) -+ return; -+ -+ for (netdev = net_devices; netdev; netdev = netdev->next) -+ if (netdev->handle == config_hnd) -+ break; -+ -+ if (!netdev) -+ return; -+ -+ if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path))) -+ return; -+ -+ grub_env_set ("net_default_interface", inf->name); -+ grub_efi_net_export_interface_vars (); -+} -+ -+static grub_err_t -+grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)), -+ grub_fs_dir_hook_t hook __attribute__ ((unused)), -+ void *hook_data __attribute__ ((unused))) -+{ -+ if (!device->net) -+ return grub_error (GRUB_ERR_BUG, "invalid net device"); -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)), -+ const char *name __attribute__ ((unused))) -+{ -+ struct grub_file *file, *bufio; -+ -+ file = grub_malloc (sizeof (*file)); -+ if (!file) -+ return grub_errno; -+ -+ grub_memcpy (file, file_out, sizeof (struct grub_file)); -+ file->device->net->name = grub_strdup (name); -+ -+ if (!file->device->net->name) -+ { -+ grub_free (file); -+ return grub_errno; -+ } -+ -+ efi_net_interface(open, file, name); -+ grub_print_error (); -+ -+ bufio = grub_bufio_open (file, 32768); -+ if (!bufio) -+ { -+ grub_free (file->device->net->name); -+ grub_free (file); -+ return grub_errno; -+ } -+ grub_memcpy (file_out, bufio, sizeof (struct grub_file)); -+ grub_free (bufio); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_ssize_t -+grub_efihttp_chunk_read (grub_file_t file, char *buf, -+ grub_size_t len, grub_size_t chunk_size) -+{ -+ char *chunk = grub_malloc (chunk_size); -+ grub_size_t sum = 0; -+ -+ while (len) -+ { -+ grub_ssize_t rd; -+ grub_size_t sz = (len > chunk_size) ? chunk_size : len; -+ -+ rd = efi_net_interface (read, file, chunk, sz); -+ -+ if (rd <= 0) -+ return rd; -+ -+ if (buf) -+ { -+ grub_memcpy (buf, chunk, rd); -+ buf += rd; -+ } -+ sum += rd; -+ len -= rd; -+ } -+ -+ grub_free (chunk); -+ return sum; -+} -+ -+static grub_ssize_t -+grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)), -+ char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) -+{ -+ if (file->offset > file->device->net->offset) -+ { -+ grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240); -+ } -+ else if (file->offset < file->device->net->offset) -+ { -+ efi_net_interface (close, file); -+ efi_net_interface (open, file, file->device->net->name); -+ if (file->offset) -+ grub_efihttp_chunk_read (file, NULL, file->offset, 10240); -+ } -+ -+ return efi_net_interface (read, file, buf, len); -+} -+ -+static grub_err_t -+grub_efi_netfs_close (grub_file_t file) -+{ -+ efi_net_interface (close, file); -+ return GRUB_ERR_NONE; -+} -+ -+static grub_efi_handle_t -+grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid) -+{ -+ grub_efi_service_binding_t *service; -+ grub_efi_status_t status; -+ grub_efi_handle_t child_dev = NULL; -+ -+ service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ if (!service) -+ { -+ grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol")); -+ return NULL; -+ } -+ -+ status = efi_call_2 (service->create_child, service, &child_dev); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status); -+ return NULL; -+ } -+ -+ return child_dev; -+} -+ -+static grub_err_t -+grub_efi_net_parse_address (const char *address, -+ grub_efi_ip4_config2_manual_address_t *ip4, -+ grub_efi_ip6_config_manual_address_t *ip6, -+ int *is_ip6, -+ int *has_cidr) -+{ -+ const char *rest; -+ -+ if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest)) -+ { -+ *is_ip6 = 0; -+ if (*rest == '/') -+ { -+ grub_uint32_t subnet_mask_size; -+ -+ subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0); -+ -+ if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) -+ { -+ grub_uint32_t subnet_mask; -+ -+ subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size))); -+ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); -+ if (has_cidr) -+ *has_cidr = 1; -+ return GRUB_ERR_NONE; -+ } -+ } -+ else if (*rest == 0) -+ { -+ grub_uint32_t subnet_mask = 0xffffffffU; -+ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); -+ if (has_cidr) -+ *has_cidr = 0; -+ return GRUB_ERR_NONE; -+ } -+ } -+ else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest)) -+ { -+ *is_ip6 = 1; -+ if (*rest == '/') -+ { -+ grub_efi_uint8_t prefix_length; -+ -+ prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0); -+ if (!grub_errno && prefix_length <= 128 && *rest == 0) -+ { -+ ip6->prefix_length = prefix_length; -+ ip6->is_anycast = 0; -+ if (has_cidr) -+ *has_cidr = 1; -+ return GRUB_ERR_NONE; -+ } -+ } -+ else if (*rest == 0) -+ { -+ ip6->prefix_length = 128; -+ ip6->is_anycast = 0; -+ if (has_cidr) -+ *has_cidr = 0; -+ return GRUB_ERR_NONE; -+ } -+ } -+ -+ return grub_error (GRUB_ERR_NET_BAD_ADDRESS, -+ N_("unrecognised network address `%s'"), -+ address); -+} -+ -+static grub_efi_net_interface_t * -+match_route (const char *server) -+{ -+ grub_err_t err; -+ grub_efi_ip4_config2_manual_address_t ip4; -+ grub_efi_ip6_config_manual_address_t ip6; -+ grub_efi_net_interface_t *inf; -+ int is_ip6 = 0; -+ -+ err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); -+ -+ if (err) -+ { -+ grub_print_error (); -+ return NULL; -+ } -+ -+ if (is_ip6) -+ { -+ struct grub_efi_net_device *dev; -+ grub_efi_net_ip_address_t addr; -+ -+ grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address)); -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ if ((inf = efi_net_ip6_config->best_interface (dev, &addr))) -+ return inf; -+ } -+ else -+ { -+ struct grub_efi_net_device *dev; -+ grub_efi_net_ip_address_t addr; -+ -+ grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address)); -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ if ((inf = efi_net_ip4_config->best_interface (dev, &addr))) -+ return inf; -+ } -+ -+ return 0; -+} -+ -+static void -+grub_efi_net_add_pxebc_to_cards (void) -+{ -+ grub_efi_uintn_t num_handles; -+ grub_efi_handle_t *handles; -+ grub_efi_handle_t *handle; -+ -+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid, -+ 0, &num_handles); -+ if (!handles) -+ return; -+ -+ for (handle = handles; num_handles--; handle++) -+ { -+ grub_efi_device_path_t *dp, *ddp, *ldp; -+ grub_efi_pxe_t *pxe; -+ struct grub_efi_net_device *d; -+ int is_ip6 = 0; -+ -+ dp = grub_efi_get_device_path (*handle); -+ if (!dp) -+ continue; -+ -+ ddp = grub_efi_duplicate_device_path (dp); -+ ldp = grub_efi_find_last_device_path (ddp); -+ -+ if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE -+ && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) -+ { -+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; -+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -+ ldp->length = sizeof (*ldp); -+ } -+ else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE -+ && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) -+ { -+ is_ip6 = 1; -+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; -+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; -+ ldp->length = sizeof (*ldp); -+ } -+ -+ for (d = net_devices; d; d = d->next) -+ if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0) -+ break; -+ -+ if (!d) -+ { -+ grub_free (ddp); -+ continue; -+ } -+ -+ pxe = grub_efi_open_protocol (*handle, &pxe_io_guid, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ -+ if (!pxe) -+ { -+ grub_free (ddp); -+ continue; -+ } -+ -+ if (is_ip6) -+ { -+ d->ip6_pxe_handle = *handle; -+ d->ip6_pxe = pxe; -+ } -+ else -+ { -+ d->ip4_pxe_handle = *handle; -+ d->ip4_pxe = pxe; -+ } -+ -+ grub_free (ddp); -+ } -+ -+ grub_free (handles); -+} -+ -+static void -+set_ip_policy_to_static (void) -+{ -+ struct grub_efi_net_device *dev; -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ { -+ grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC; -+ -+ if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, -+ sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS) -+ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name); -+ -+ if (dev->ip6_config) -+ { -+ grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL; -+ -+ if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, -+ sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS) -+ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name); -+ } -+ } -+} -+ -+/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */ -+static void -+grub_efi_net_find_cards (void) -+{ -+ grub_efi_uintn_t num_handles; -+ grub_efi_handle_t *handles; -+ grub_efi_handle_t *handle; -+ int id; -+ -+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid, -+ 0, &num_handles); -+ if (!handles) -+ return; -+ -+ for (id = 0, handle = handles; num_handles--; handle++, id++) -+ { -+ grub_efi_device_path_t *dp; -+ grub_efi_ip4_config2_protocol_t *ip4_config; -+ grub_efi_ip6_config_protocol_t *ip6_config; -+ grub_efi_handle_t http_handle; -+ grub_efi_http_t *http; -+ grub_efi_handle_t dhcp4_handle; -+ grub_efi_dhcp4_protocol_t *dhcp4; -+ grub_efi_handle_t dhcp6_handle; -+ grub_efi_dhcp6_protocol_t *dhcp6; -+ -+ struct grub_efi_net_device *d; -+ -+ dp = grub_efi_get_device_path (*handle); -+ if (!dp) -+ continue; -+ -+ ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ if (!ip4_config) -+ continue; -+ -+ ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid, -+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); -+ -+ http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid); -+ grub_errno = GRUB_ERR_NONE; -+ http = (http_handle) -+ ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) -+ : NULL; -+ -+ dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid); -+ grub_errno = GRUB_ERR_NONE; -+ dhcp4 = (dhcp4_handle) -+ ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) -+ : NULL; -+ -+ -+ dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid); -+ grub_errno = GRUB_ERR_NONE; -+ dhcp6 = (dhcp6_handle) -+ ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) -+ : NULL; -+ -+ d = grub_malloc (sizeof (*d)); -+ if (!d) -+ { -+ grub_free (handles); -+ while (net_devices) -+ { -+ d = net_devices->next; -+ grub_free (net_devices); -+ net_devices = d; -+ } -+ return; -+ } -+ d->handle = *handle; -+ d->ip4_config = ip4_config; -+ d->ip6_config = ip6_config; -+ d->http_handle = http_handle; -+ d->http = http; -+ d->dhcp4_handle = dhcp4_handle; -+ d->dhcp4 = dhcp4; -+ d->dhcp6_handle = dhcp6_handle; -+ d->dhcp6 = dhcp6; -+ d->next = net_devices; -+ d->card_name = grub_xasprintf ("efinet%d", id); -+ d->net_interfaces = NULL; -+ net_devices = d; -+ } -+ -+ grub_efi_net_add_pxebc_to_cards (); -+ grub_free (handles); -+ set_ip_policy_to_static (); -+} -+ -+static void -+listroutes_ip4 (struct grub_efi_net_device *netdev) -+{ -+ char **routes; -+ -+ routes = NULL; -+ -+ if ((routes = efi_net_ip4_config->get_route_table (netdev))) -+ { -+ char **r; -+ -+ for (r = routes; *r; ++r) -+ grub_printf ("%s\n", *r); -+ } -+ -+ if (routes) -+ { -+ char **r; -+ -+ for (r = routes; *r; ++r) -+ grub_free (*r); -+ grub_free (routes); -+ } -+} -+ -+static void -+listroutes_ip6 (struct grub_efi_net_device *netdev) -+{ -+ char **routes; -+ -+ routes = NULL; -+ -+ if ((routes = efi_net_ip6_config->get_route_table (netdev))) -+ { -+ char **r; -+ -+ for (r = routes; *r; ++r) -+ grub_printf ("%s\n", *r); -+ } -+ -+ if (routes) -+ { -+ char **r; -+ -+ for (r = routes; *r; ++r) -+ grub_free (*r); -+ grub_free (routes); -+ } -+} -+ -+static grub_err_t -+grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)), -+ int argc __attribute__ ((unused)), -+ char **args __attribute__ ((unused))) -+{ -+ struct grub_efi_net_device *netdev; -+ -+ for (netdev = net_devices; netdev; netdev = netdev->next) -+ { -+ listroutes_ip4 (netdev); -+ listroutes_ip6 (netdev); -+ } -+ -+ return GRUB_ERR_NONE; -+} -+static grub_err_t -+grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)), -+ int argc __attribute__ ((unused)), -+ char **args __attribute__ ((unused))) -+{ -+ struct grub_efi_net_device *dev; -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ { -+ char *hw_addr; -+ -+ hw_addr = efi_net_ip4_config->get_hw_address (dev); -+ -+ if (hw_addr) -+ { -+ grub_printf ("%s %s\n", dev->card_name, hw_addr); -+ grub_free (hw_addr); -+ } -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)), -+ int argc __attribute__ ((unused)), -+ char **args __attribute__ ((unused))) -+{ -+ struct grub_efi_net_device *dev; -+ grub_efi_net_interface_t *inf; -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ for (inf = dev->net_interfaces; inf; inf = inf->next) -+ { -+ char *hw_addr = NULL; -+ char *addr = NULL; -+ -+ if ((hw_addr = efi_net_interface_get_hw_address (inf)) -+ && (addr = efi_net_interface_get_address (inf))) -+ grub_printf ("%s %s %s\n", inf->name, hw_addr, addr); -+ -+ if (hw_addr) -+ grub_free (hw_addr); -+ if (addr) -+ grub_free (addr); -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+/* FIXME: support MAC specifying. */ -+static grub_err_t -+grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)), -+ int argc, char **args) -+{ -+ struct grub_efi_net_device *dev; -+ grub_err_t err; -+ grub_efi_ip4_config2_manual_address_t ip4; -+ grub_efi_ip6_config_manual_address_t ip6; -+ grub_efi_net_ip_manual_address_t net_ip; -+ int is_ip6 = 0; -+ int cidr = 0; -+ -+ if (argc != 3) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); -+ -+ for (dev = net_devices; dev; dev = dev->next) -+ { -+ if (grub_strcmp (dev->card_name, args[1]) == 0) -+ break; -+ } -+ -+ if (!dev) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); -+ -+ err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr); -+ -+ if (err) -+ return err; -+ -+ net_ip.is_ip6 = is_ip6; -+ if (is_ip6) -+ grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6)); -+ else -+ grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4)); -+ -+ if (!grub_efi_net_create_interface (dev, -+ args[0], -+ &net_ip, -+ cidr)) -+ return grub_errno; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static struct grub_fs grub_efi_netfs; -+ -+static grub_net_t -+grub_net_open_real (const char *name __attribute__ ((unused))) -+{ -+ grub_size_t protnamelen; -+ const char *protname, *server; -+ grub_net_t ret; -+ -+ net_interface = NULL; -+ -+ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) -+ { -+ protname = "tftp"; -+ protnamelen = sizeof ("tftp") - 1; -+ server = name + sizeof ("pxe:") - 1; -+ } -+ else if (grub_strcmp (name, "pxe") == 0) -+ { -+ protname = "tftp"; -+ protnamelen = sizeof ("tftp") - 1; -+ server = default_server; -+ } -+ else -+ { -+ const char *comma; -+ -+ comma = grub_strchr (name, ','); -+ if (comma) -+ { -+ protnamelen = comma - name; -+ server = comma + 1; -+ protname = name; -+ } -+ else -+ { -+ protnamelen = grub_strlen (name); -+ server = default_server; -+ protname = name; -+ } -+ } -+ -+ if (!server) -+ { -+ grub_error (GRUB_ERR_NET_BAD_ADDRESS, -+ N_("no server is specified")); -+ return NULL; -+ } -+ -+ /*FIXME: Use DNS translate name to address */ -+ net_interface = match_route (server); -+ -+ /*XXX: should we check device with default gateway ? */ -+ if (!net_interface && !(net_interface = net_default_interface)) -+ { -+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), -+ name); -+ return NULL; -+ } -+ -+ if ((protnamelen == (sizeof ("https") - 1) -+ && grub_memcmp ("https", protname, protnamelen) == 0)) -+ { -+ net_interface->io = &io_http; -+ net_interface->io_type = 1; -+ } -+ else if ((protnamelen == (sizeof ("http") - 1) -+ && grub_memcmp ("http", protname, protnamelen) == 0)) -+ { -+ net_interface->io = &io_http; -+ net_interface->io_type = 0; -+ } -+ else if (protnamelen == (sizeof ("tftp") - 1) -+ && grub_memcmp ("tftp", protname, protnamelen) == 0) -+ { -+ net_interface->io = &io_pxe; -+ net_interface->io_type = 0; -+ } -+ else -+ { -+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), -+ name); -+ return NULL; -+ } -+ -+ /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */ -+ efi_net_interface (configure); -+ -+ ret = grub_zalloc (sizeof (*ret)); -+ if (!ret) -+ return NULL; -+ -+ ret->server = grub_strdup (server); -+ if (!ret->server) -+ { -+ grub_free (ret); -+ return NULL; -+ } -+ -+ ret->fs = &grub_efi_netfs; -+ return ret; -+} -+#if 0 -+static grub_command_t cmd_efi_lsaddr; -+static grub_command_t cmd_efi_lscards; -+static grub_command_t cmd_efi_lsroutes; -+static grub_command_t cmd_efi_addaddr; -+#endif -+ -+static struct grub_fs grub_efi_netfs = -+ { -+ .name = "efi netfs", -+ .fs_dir = grub_efi_netfs_dir, -+ .fs_open = grub_efi_netfs_open, -+ .fs_read = grub_efi_netfs_read, -+ .fs_close = grub_efi_netfs_close, -+ .fs_label = NULL, -+ .fs_uuid = NULL, -+ .fs_mtime = NULL, -+ }; -+ -+int -+grub_efi_net_boot_from_https (void) -+{ -+ grub_efi_loaded_image_t *image = NULL; -+ grub_efi_device_path_t *dp; -+ -+ image = grub_efi_get_loaded_image (grub_efi_image_handle); -+ if (!image) -+ return 0; -+ -+ dp = grub_efi_get_device_path (image->device_handle); -+ -+ while (1) -+ { -+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); -+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); -+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); -+ -+ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) -+ && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) -+ { -+ grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; -+ return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; -+ } -+ -+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) -+ break; -+ dp = (grub_efi_device_path_t *) ((char *) dp + len); -+ } -+ -+ return 0; -+} -+ -+int -+grub_efi_net_boot_from_opa (void) -+{ -+ grub_efi_loaded_image_t *image = NULL; -+ grub_efi_device_path_t *dp; -+ -+ image = grub_efi_get_loaded_image (grub_efi_image_handle); -+ if (!image) -+ return 0; -+ -+ dp = grub_efi_get_device_path (image->device_handle); -+ -+ while (1) -+ { -+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); -+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); -+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); -+ -+ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) -+ && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)) -+ { -+ grub_efi_mac_address_device_path_t *mac_dp = (grub_efi_mac_address_device_path_t *)dp; -+ return (mac_dp->if_type == 0xC7) ? 1 : 0; -+ } -+ -+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) -+ break; -+ dp = (grub_efi_device_path_t *) ((char *) dp + len); -+ } -+ -+ return 0; -+} -+ -+static char * -+grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), -+ const char *val __attribute__ ((unused))) -+{ -+ return NULL; -+} -+ -+grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes; -+grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards; -+grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs; -+grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr; -+ -+int -+grub_efi_net_fs_init () -+{ -+ grub_efi_net_find_cards (); -+ grub_efi_net_config = grub_efi_net_config_real; -+ grub_net_open = grub_net_open_real; -+ grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server, -+ grub_efi_net_var_set_server); -+ grub_env_export ("net_default_server"); -+ grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server, -+ grub_efi_net_var_set_server); -+ grub_env_export ("pxe_default_server"); -+ grub_register_variable_hook ("net_default_interface", 0, -+ grub_efi_net_var_set_interface); -+ grub_env_export ("net_default_interface"); -+ grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip, -+ 0); -+ grub_env_export ("net_default_ip"); -+ grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac, -+ 0); -+ grub_env_export ("net_default_mac"); -+ -+ grub_env_set ("grub_netfs_type", "efi"); -+ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); -+ grub_env_export ("grub_netfs_type"); -+ -+ return 1; -+} -+ -+void -+grub_efi_net_fs_fini (void) -+{ -+ grub_env_unset ("grub_netfs_type"); -+ grub_efi_net_unset_interface_vars (); -+ grub_register_variable_hook ("net_default_server", 0, 0); -+ grub_env_unset ("net_default_server"); -+ grub_register_variable_hook ("net_default_interface", 0, 0); -+ grub_env_unset ("net_default_interface"); -+ grub_register_variable_hook ("pxe_default_server", 0, 0); -+ grub_env_unset ("pxe_default_server"); -+ grub_register_variable_hook ("net_default_ip", 0, 0); -+ grub_env_unset ("net_default_ip"); -+ grub_register_variable_hook ("net_default_mac", 0, 0); -+ grub_env_unset ("net_default_mac"); -+ grub_efi_net_config = NULL; -+ grub_net_open = NULL; -+ grub_fs_unregister (&grub_efi_netfs); -+} -diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c -new file mode 100644 -index 0000000000..531949cba5 ---- /dev/null -+++ b/grub-core/net/efi/pxe.c -@@ -0,0 +1,424 @@ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static grub_efi_ip6_config_manual_address_t * -+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) -+{ -+ grub_efi_uintn_t sz; -+ grub_efi_status_t status; -+ grub_efi_ip6_config_manual_address_t *manual_address; -+ -+ sz = sizeof (*manual_address); -+ manual_address = grub_malloc (sz); -+ if (!manual_address) -+ return NULL; -+ -+ status = efi_call_4 (ip6_config->get_data, ip6_config, -+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, -+ &sz, manual_address); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (manual_address); -+ return NULL; -+ } -+ -+ return manual_address; -+} -+ -+static grub_efi_ip4_config2_manual_address_t * -+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) -+{ -+ grub_efi_uintn_t sz; -+ grub_efi_status_t status; -+ grub_efi_ip4_config2_manual_address_t *manual_address; -+ -+ sz = sizeof (*manual_address); -+ manual_address = grub_malloc (sz); -+ if (!manual_address) -+ return NULL; -+ -+ status = efi_call_4 (ip4_config->get_data, ip4_config, -+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, -+ &sz, manual_address); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_free (manual_address); -+ return NULL; -+ } -+ -+ return manual_address; -+} -+ -+static void -+pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6) -+{ -+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; -+ -+ grub_efi_pxe_mode_t *mode = pxe->mode; -+ -+ if (!mode->started) -+ { -+ grub_efi_status_t status; -+ status = efi_call_2 (pxe->start, pxe, prefer_ip6); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ grub_printf ("Couldn't start PXE\n"); -+ } -+ -+#if 0 -+ grub_printf ("PXE STARTED: %u\n", mode->started); -+ grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6); -+#endif -+ -+ if (mode->using_ipv6) -+ { -+ grub_efi_ip6_config_manual_address_t *manual_address; -+ manual_address = efi_ip6_config_manual_address (dev->ip6_config); -+ -+ if (manual_address && -+ grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0) -+ { -+ grub_efi_status_t status; -+ grub_efi_pxe_ip_address_t station_ip; -+ -+ grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr)); -+ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ grub_printf ("Couldn't set station ip\n"); -+ -+ grub_free (manual_address); -+ } -+ } -+ else -+ { -+ grub_efi_ip4_config2_manual_address_t *manual_address; -+ manual_address = efi_ip4_config_manual_address (dev->ip4_config); -+ -+ if (manual_address && -+ grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0) -+ { -+ grub_efi_status_t status; -+ grub_efi_pxe_ip_address_t station_ip; -+ grub_efi_pxe_ip_address_t subnet_mask; -+ -+ grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr)); -+ grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr)); -+ -+ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ grub_printf ("Couldn't set station ip\n"); -+ -+ grub_free (manual_address); -+ } -+ } -+ -+#if 0 -+ if (mode->using_ipv6) -+ { -+ grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", -+ mode->station_ip.v6.addr[0], -+ mode->station_ip.v6.addr[1], -+ mode->station_ip.v6.addr[2], -+ mode->station_ip.v6.addr[3], -+ mode->station_ip.v6.addr[4], -+ mode->station_ip.v6.addr[5], -+ mode->station_ip.v6.addr[6], -+ mode->station_ip.v6.addr[7], -+ mode->station_ip.v6.addr[8], -+ mode->station_ip.v6.addr[9], -+ mode->station_ip.v6.addr[10], -+ mode->station_ip.v6.addr[11], -+ mode->station_ip.v6.addr[12], -+ mode->station_ip.v6.addr[13], -+ mode->station_ip.v6.addr[14], -+ mode->station_ip.v6.addr[15]); -+ } -+ else -+ { -+ grub_printf ("PXE STATION IP: %d.%d.%d.%d\n", -+ mode->station_ip.v4.addr[0], -+ mode->station_ip.v4.addr[1], -+ mode->station_ip.v4.addr[2], -+ mode->station_ip.v4.addr[3]); -+ grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n", -+ mode->subnet_mask.v4.addr[0], -+ mode->subnet_mask.v4.addr[1], -+ mode->subnet_mask.v4.addr[2], -+ mode->subnet_mask.v4.addr[3]); -+ } -+#endif -+ -+ /* TODO: Set The Station IP to the IP2 Config */ -+} -+ -+static int -+parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) -+{ -+ grub_uint16_t newip[8]; -+ const char *ptr = val; -+ int word, quaddot = -1; -+ int bracketed = 0; -+ -+ if (ptr[0] == '[') { -+ bracketed = 1; -+ ptr++; -+ } -+ -+ if (ptr[0] == ':' && ptr[1] != ':') -+ return 0; -+ if (ptr[0] == ':') -+ ptr++; -+ -+ for (word = 0; word < 8; word++) -+ { -+ unsigned long t; -+ if (*ptr == ':') -+ { -+ quaddot = word; -+ word--; -+ ptr++; -+ continue; -+ } -+ t = grub_strtoul (ptr, (char **) &ptr, 16); -+ if (grub_errno) -+ { -+ grub_errno = GRUB_ERR_NONE; -+ break; -+ } -+ if (t & ~0xffff) -+ return 0; -+ newip[word] = grub_cpu_to_be16 (t); -+ if (*ptr != ':') -+ break; -+ ptr++; -+ } -+ if (quaddot == -1 && word < 7) -+ return 0; -+ if (quaddot != -1) -+ { -+ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], -+ (word - quaddot + 1) * sizeof (newip[0])); -+ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); -+ } -+ grub_memcpy (ip, newip, 16); -+ if (bracketed && *ptr == ']') { -+ ptr++; -+ } -+ if (rest) -+ *rest = ptr; -+ return 1; -+} -+ -+static grub_err_t -+pxe_open (struct grub_efi_net_device *dev, -+ int prefer_ip6, -+ grub_file_t file, -+ const char *filename, -+ int type __attribute__((unused))) -+{ -+ int i; -+ char *p; -+ grub_efi_status_t status; -+ grub_efi_pxe_ip_address_t server_ip; -+ grub_efi_uint64_t file_size = 0; -+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; -+ -+ if (pxe->mode->using_ipv6) -+ { -+ const char *rest; -+ grub_uint64_t ip6[2]; -+ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) -+ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); -+ /* TODO: ERROR Handling Here */ -+#if 0 -+ grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", -+ server_ip.v6.addr[0], -+ server_ip.v6.addr[1], -+ server_ip.v6.addr[2], -+ server_ip.v6.addr[3], -+ server_ip.v6.addr[4], -+ server_ip.v6.addr[5], -+ server_ip.v6.addr[6], -+ server_ip.v6.addr[7], -+ server_ip.v6.addr[8], -+ server_ip.v6.addr[9], -+ server_ip.v6.addr[10], -+ server_ip.v6.addr[11], -+ server_ip.v6.addr[12], -+ server_ip.v6.addr[13], -+ server_ip.v6.addr[14], -+ server_ip.v6.addr[15]); -+#endif -+ } -+ else -+ { -+ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) -+ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); -+ } -+ -+ status = efi_call_10 (pxe->mtftp, -+ pxe, -+ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, -+ NULL, -+ 0, -+ &file_size, -+ NULL, -+ &server_ip, -+ (grub_efi_char8_t *)filename, -+ NULL, -+ 0); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ return grub_error (GRUB_ERR_IO, "Couldn't get file size"); -+ -+ file->size = (grub_off_t)file_size; -+ file->not_easily_seekable = 0; -+ file->data = 0; -+ file->device->net->offset = 0; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+pxe_close (struct grub_efi_net_device *dev __attribute__((unused)), -+ int prefer_ip6 __attribute__((unused)), -+ grub_file_t file __attribute__((unused))) -+{ -+ file->offset = 0; -+ file->size = 0; -+ file->device->net->offset = 0; -+ -+ if (file->data) -+ { -+ grub_free (file->data); -+ file->data = NULL; -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_ssize_t -+pxe_read (struct grub_efi_net_device *dev, -+ int prefer_ip6, -+ grub_file_t file, -+ char *buf, -+ grub_size_t len) -+{ -+ int i; -+ char *p; -+ grub_efi_status_t status; -+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; -+ grub_efi_uint64_t bufsz = len; -+ grub_efi_pxe_ip_address_t server_ip; -+ char *buf2 = NULL; -+ -+ if (file->data) -+ { -+ /* TODO: RANGE Check for offset and file size */ -+ grub_memcpy (buf, (char*)file->data + file->device->net->offset, len); -+ file->device->net->offset += len; -+ return len; -+ } -+ -+ if (file->device->net->offset) -+ { -+ grub_error (GRUB_ERR_BUG, "No Offet Read Possible"); -+ grub_print_error (); -+ return 0; -+ } -+ -+ if (pxe->mode->using_ipv6) -+ { -+ const char *rest; -+ grub_uint64_t ip6[2]; -+ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) -+ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); -+ /* TODO: ERROR Handling Here */ -+ } -+ else -+ { -+ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) -+ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); -+ } -+ -+ status = efi_call_10 (pxe->mtftp, -+ pxe, -+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, -+ buf, -+ 0, -+ &bufsz, -+ NULL, -+ &server_ip, -+ (grub_efi_char8_t *)file->device->net->name, -+ NULL, -+ 0); -+ -+ if (bufsz != file->size) -+ { -+ grub_error (GRUB_ERR_BUG, "Short read should not happen here"); -+ grub_print_error (); -+ return 0; -+ } -+ -+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) -+ { -+ -+ buf2 = grub_malloc (bufsz); -+ -+ if (!buf2) -+ { -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY"); -+ grub_print_error (); -+ return 0; -+ } -+ -+ status = efi_call_10 (pxe->mtftp, -+ pxe, -+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, -+ buf2, -+ 0, -+ &bufsz, -+ NULL, -+ &server_ip, -+ (grub_efi_char8_t *)file->device->net->name, -+ NULL, -+ 0); -+ } -+ -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ if (buf2) -+ grub_free (buf2); -+ -+ grub_error (GRUB_ERR_IO, "Failed to Read File"); -+ grub_print_error (); -+ return 0; -+ } -+ -+ if (buf2) -+ grub_memcpy (buf, buf2, len); -+ -+ file->device->net->offset = len; -+ -+ if (buf2) -+ file->data = buf2; -+ -+ return len; -+} -+ -+struct grub_efi_net_io io_pxe = -+ { -+ .configure = pxe_configure, -+ .open = pxe_open, -+ .read = pxe_read, -+ .close = pxe_close -+ }; -+ -diff --git a/grub-core/net/net.c b/grub-core/net/net.c -index 0ce5e675ed..55aed92722 100644 ---- a/grub-core/net/net.c -+++ b/grub-core/net/net.c -@@ -32,6 +32,9 @@ - #include - #include - #include -+#ifdef GRUB_MACHINE_EFI -+#include -+#endif - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -2033,8 +2036,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; - static grub_command_t cmd_lsroutes, cmd_lscards; - static grub_command_t cmd_lsaddr, cmd_slaac; - -+#ifdef GRUB_MACHINE_EFI -+ -+static enum { -+ INIT_MODE_NONE, -+ INIT_MODE_GRUB, -+ INIT_MODE_EFI -+} init_mode; -+ -+static grub_command_t cmd_bootp, cmd_bootp6; -+ -+#endif -+ - GRUB_MOD_INIT(net) - { -+#ifdef GRUB_MACHINE_EFI -+ if (grub_net_open) -+ return; -+ -+ if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ()) -+ && grub_efi_net_fs_init ()) -+ { -+ cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes, -+ "", N_("list network routes")); -+ cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards, -+ "", N_("list network cards")); -+ cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs, -+ "", N_("list network addresses")); -+ cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr, -+ /* TRANSLATORS: HWADDRESS stands for -+ "hardware address". */ -+ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), -+ N_("Add a network address.")); -+ cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp, -+ N_("[CARD]"), -+ N_("perform a bootp autoconfiguration")); -+ cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6, -+ N_("[CARD]"), -+ N_("perform a bootp autoconfiguration")); -+ init_mode = INIT_MODE_EFI; -+ return; -+ } -+#endif -+ - grub_register_variable_hook ("net_default_server", defserver_get_env, - defserver_set_env); - grub_env_export ("net_default_server"); -@@ -2082,10 +2126,37 @@ GRUB_MOD_INIT(net) - grub_net_restore_hw, - GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); - grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; -+ -+#ifdef GRUB_MACHINE_EFI -+ grub_env_set ("grub_netfs_type", "grub"); -+ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); -+ grub_env_export ("grub_netfs_type"); -+ init_mode = INIT_MODE_GRUB; -+#endif -+ - } - - GRUB_MOD_FINI(net) - { -+ -+#ifdef GRUB_MACHINE_EFI -+ if (init_mode == INIT_MODE_NONE) -+ return; -+ -+ if (init_mode == INIT_MODE_EFI) -+ { -+ grub_unregister_command (cmd_lsroutes); -+ grub_unregister_command (cmd_lscards); -+ grub_unregister_command (cmd_lsaddr); -+ grub_unregister_command (cmd_addaddr); -+ grub_unregister_command (cmd_bootp); -+ grub_unregister_command (cmd_bootp6); -+ grub_efi_net_fs_fini (); -+ init_mode = INIT_MODE_NONE; -+ return; -+ } -+#endif -+ - grub_register_variable_hook ("net_default_server", 0, 0); - grub_register_variable_hook ("pxe_default_server", 0, 0); - -@@ -2104,4 +2175,7 @@ GRUB_MOD_FINI(net) - grub_net_fini_hw (0); - grub_loader_unregister_preboot_hook (fini_hnd); - grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; -+#ifdef GRUB_MACHINE_EFI -+ init_mode = INIT_MODE_NONE; -+#endif - } -diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c -index a2461cda1c..77958dd9dd 100644 ---- a/util/grub-mknetdir.c -+++ b/util/grub-mknetdir.c -@@ -32,13 +32,15 @@ - - static char *rootdir = NULL, *subdir = NULL; - static char *debug_image = NULL; -+static char efi_netfs = 0; - - enum - { - OPTION_NET_DIRECTORY = 0x301, - OPTION_SUBDIR, - OPTION_DEBUG, -- OPTION_DEBUG_IMAGE -+ OPTION_DEBUG_IMAGE, -+ OPTION_DEBUG_EFI_NETFS - }; - - static struct argp_option options[] = { -@@ -49,6 +51,7 @@ static struct argp_option options[] = { - 0, N_("relative subdirectory on network server"), 2}, - {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, - {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, -+ {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2}, - {0, 0, 0, 0, 0, 0} - }; - -@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state) - free (subdir); - subdir = xstrdup (arg); - return 0; -+ case OPTION_DEBUG_EFI_NETFS: -+ efi_netfs = 1; -+ return 0; - /* This is an undocumented feature... */ - case OPTION_DEBUG: - verbosity++; -@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state) - } - } - -- - struct argp argp = { - options, argp_parser, NULL, - "\v"N_("Prepares GRUB network boot images at net_directory/subdir " -@@ -92,7 +97,7 @@ struct argp argp = { - - static char *base; - --static const struct -+static struct - { - const char *mkimage_target; - const char *netmodule; -@@ -156,6 +161,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform) - grub_install_push_module (targets[platform].netmodule); - - output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext); -+ - grub_install_make_image_wrap (input_dir, prefix, output, - 0, load_cfg, - targets[platform].mkimage_target, 0); -@@ -195,7 +201,16 @@ main (int argc, char *argv[]) - - grub_install_mkdir_p (base); - -- grub_install_push_module ("tftp"); -+ if (!efi_netfs) -+ { -+ grub_install_push_module ("tftp"); -+ grub_install_push_module ("http"); -+ } -+ else -+ { -+ targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs"; -+ targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs"; -+ } - - if (!grub_install_source_directory) - { -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index 0b490195ad..f431f49973 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -622,6 +622,23 @@ typedef union - - typedef grub_efi_uint64_t grub_efi_physical_address_t; - typedef grub_efi_uint64_t grub_efi_virtual_address_t; -+typedef struct { -+ grub_uint8_t addr[4]; -+} grub_efi_pxe_ipv4_address_t; -+ -+typedef struct { -+ grub_uint8_t addr[16]; -+} grub_efi_pxe_ipv6_address_t; -+ -+typedef struct { -+ grub_uint8_t addr[32]; -+} grub_efi_pxe_mac_address_t; -+ -+typedef union { -+ grub_uint32_t addr[4]; -+ grub_efi_pxe_ipv4_address_t v4; -+ grub_efi_pxe_ipv6_address_t v6; -+} grub_efi_pxe_ip_address_t; - - struct grub_efi_guid - { -@@ -889,6 +906,8 @@ struct grub_efi_ipv6_device_path - grub_efi_uint16_t remote_port; - grub_efi_uint16_t protocol; - grub_efi_uint8_t static_ip_address; -+ grub_efi_uint8_t prefix_length; -+ grub_efi_ipv6_address_t gateway_ip_address; - } GRUB_PACKED; - typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; - -@@ -938,6 +957,15 @@ struct grub_efi_uri_device_path - } GRUB_PACKED; - typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; - -+#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE 31 -+struct grub_efi_dns_device_path -+{ -+ grub_efi_device_path_t header; -+ grub_efi_uint8_t is_ipv6; -+ grub_efi_pxe_ip_address_t dns_server_ip[0]; -+} GRUB_PACKED; -+typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t; -+ - #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 - - /* Media Device Path. */ -@@ -1020,6 +1048,23 @@ struct grub_efi_bios_device_path - } GRUB_PACKED; - typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; - -+/* Service Binding definitions */ -+struct grub_efi_service_binding; -+ -+typedef grub_efi_status_t -+(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this, -+ grub_efi_handle_t *child_handle); -+ -+typedef grub_efi_status_t -+(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this, -+ grub_efi_handle_t *child_handle); -+ -+typedef struct grub_efi_service_binding -+{ -+ grub_efi_service_binding_create_child create_child; -+ grub_efi_service_binding_destroy_child destroy_child; -+} grub_efi_service_binding_t; -+ - struct grub_efi_open_protocol_information_entry - { - grub_efi_handle_t agent_handle; -@@ -1569,23 +1614,27 @@ typedef struct grub_efi_pxe_tftp_error - grub_efi_char8_t error_string[127]; - } grub_efi_pxe_tftp_error_t; - --typedef struct { -- grub_uint8_t addr[4]; --} grub_efi_pxe_ipv4_address_t; -+typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t; - --typedef struct { -- grub_uint8_t addr[16]; --} grub_efi_pxe_ipv6_address_t; -+typedef enum { -+ GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST, -+ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, -+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, -+ GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, -+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, -+ GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, -+ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE, -+ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, -+ GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST -+} grub_efi_pxe_base_code_tftp_opcode_t; - - typedef struct { -- grub_uint8_t addr[32]; --} grub_efi_pxe_mac_address_t; -- --typedef union { -- grub_uint32_t addr[4]; -- grub_efi_pxe_ipv4_address_t v4; -- grub_efi_pxe_ipv6_address_t v6; --} grub_efi_pxe_ip_address_t; -+ grub_efi_ip_address_t mcast_ip; -+ grub_efi_pxe_base_code_udp_port_t c_port; -+ grub_efi_pxe_base_code_udp_port_t s_port; -+ grub_efi_uint16_t listen_timeout; -+ grub_efi_uint16_t transmit_timeout; -+} grub_efi_pxe_base_code_mtftp_info_t; - - #define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 - typedef struct grub_efi_pxe_ip_filter -@@ -1652,17 +1701,31 @@ typedef struct grub_efi_pxe_mode - typedef struct grub_efi_pxe - { - grub_uint64_t rev; -- void (*start) (void); -+ grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6); - void (*stop) (void); -- void (*dhcp) (void); -+ grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this, -+ grub_efi_boolean_t sort_offers); - void (*discover) (void); -- void (*mftp) (void); -+ grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this, -+ grub_efi_pxe_base_code_tftp_opcode_t operation, -+ void *buffer_ptr, -+ grub_efi_boolean_t overwrite, -+ grub_efi_uint64_t *buffer_size, -+ grub_efi_uintn_t *block_size, -+ grub_efi_pxe_ip_address_t *server_ip, -+ //grub_efi_ip_address_t *server_ip, -+ grub_efi_char8_t *filename, -+ grub_efi_pxe_base_code_mtftp_info_t *info, -+ grub_efi_boolean_t dont_use_buffer); - void (*udpwrite) (void); - void (*udpread) (void); - void (*setipfilter) (void); - void (*arp) (void); - void (*setparams) (void); -- void (*setstationip) (void); -+ grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this, -+ grub_efi_pxe_ip_address_t *new_station_ip, -+ grub_efi_pxe_ip_address_t *new_subnet_mask); -+ //void (*setstationip) (void); - void (*setpackets) (void); - struct grub_efi_pxe_mode *mode; - } grub_efi_pxe_t; -@@ -1924,6 +1987,44 @@ struct grub_efi_ip4_config2_protocol - }; - typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; - -+struct grub_efi_ip4_route_table { -+ grub_efi_ipv4_address_t subnet_address; -+ grub_efi_ipv4_address_t subnet_mask; -+ grub_efi_ipv4_address_t gateway_address; -+}; -+ -+typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t; -+ -+#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 -+ -+struct grub_efi_ip4_config2_interface_info { -+ grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; -+ grub_efi_uint8_t if_type; -+ grub_efi_uint32_t hw_address_size; -+ grub_efi_mac_address_t hw_address; -+ grub_efi_ipv4_address_t station_address; -+ grub_efi_ipv4_address_t subnet_mask; -+ grub_efi_uint32_t route_table_size; -+ grub_efi_ip4_route_table_t *route_table; -+}; -+ -+typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t; -+ -+enum grub_efi_ip4_config2_policy { -+ GRUB_EFI_IP4_CONFIG2_POLICY_STATIC, -+ GRUB_EFI_IP4_CONFIG2_POLICY_DHCP, -+ GRUB_EFI_IP4_CONFIG2_POLICY_MAX -+}; -+ -+typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t; -+ -+struct grub_efi_ip4_config2_manual_address { -+ grub_efi_ipv4_address_t address; -+ grub_efi_ipv4_address_t subnet_mask; -+}; -+ -+typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t; -+ - enum grub_efi_ip6_config_data_type { - GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, - GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, -@@ -1958,6 +2059,49 @@ struct grub_efi_ip6_config_protocol - }; - typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; - -+enum grub_efi_ip6_config_policy { -+ GRUB_EFI_IP6_CONFIG_POLICY_MANUAL, -+ GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC -+}; -+typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t; -+ -+struct grub_efi_ip6_address_info { -+ grub_efi_ipv6_address_t address; -+ grub_efi_uint8_t prefix_length; -+}; -+typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t; -+ -+struct grub_efi_ip6_route_table { -+ grub_efi_pxe_ipv6_address_t gateway; -+ grub_efi_pxe_ipv6_address_t destination; -+ grub_efi_uint8_t prefix_length; -+}; -+typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t; -+ -+struct grub_efi_ip6_config_interface_info { -+ grub_efi_char16_t name[32]; -+ grub_efi_uint8_t if_type; -+ grub_efi_uint32_t hw_address_size; -+ grub_efi_mac_address_t hw_address; -+ grub_efi_uint32_t address_info_count; -+ grub_efi_ip6_address_info_t *address_info; -+ grub_efi_uint32_t route_count; -+ grub_efi_ip6_route_table_t *route_table; -+}; -+typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t; -+ -+struct grub_efi_ip6_config_dup_addr_detect_transmits { -+ grub_efi_uint32_t dup_addr_detect_transmits; -+}; -+typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t; -+ -+struct grub_efi_ip6_config_manual_address { -+ grub_efi_ipv6_address_t address; -+ grub_efi_boolean_t is_anycast; -+ grub_efi_uint8_t prefix_length; -+}; -+typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; -+ - #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ - || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ - || defined(__riscv) -diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h -new file mode 100644 -index 0000000000..fdb88eb810 ---- /dev/null -+++ b/include/grub/efi/dhcp.h -@@ -0,0 +1,343 @@ -+#ifndef GRUB_EFI_DHCP_HEADER -+#define GRUB_EFI_DHCP_HEADER 1 -+ -+#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ -+ { 0x9d9a39d8, 0xbd42, 0x4a73, \ -+ { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \ -+ } -+ -+#define GRUB_EFI_DHCP4_PROTOCOL_GUID \ -+ { 0x8a219718, 0x4ef5, 0x4761, \ -+ { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \ -+ } -+ -+#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ -+ { 0x9fb9a8a1, 0x2f4a, 0x43a6, \ -+ { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \ -+ } -+ -+#define GRUB_EFI_DHCP6_PROTOCOL_GUID \ -+ { 0x87c8bad7, 0x595, 0x4053, \ -+ { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \ -+ } -+ -+typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t; -+ -+enum grub_efi_dhcp4_state { -+ GRUB_EFI_DHCP4_STOPPED, -+ GRUB_EFI_DHCP4_INIT, -+ GRUB_EFI_DHCP4_SELECTING, -+ GRUB_EFI_DHCP4_REQUESTING, -+ GRUB_EFI_DHCP4_BOUND, -+ GRUB_EFI_DHCP4_RENEWING, -+ GRUB_EFI_DHCP4_REBINDING, -+ GRUB_EFI_DHCP4_INIT_REBOOT, -+ GRUB_EFI_DHCP4_REBOOTING -+}; -+ -+typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t; -+ -+struct grub_efi_dhcp4_header { -+ grub_efi_uint8_t op_code; -+ grub_efi_uint8_t hw_type; -+ grub_efi_uint8_t hw_addr_len; -+ grub_efi_uint8_t hops; -+ grub_efi_uint32_t xid; -+ grub_efi_uint16_t seconds; -+ grub_efi_uint16_t reserved; -+ grub_efi_ipv4_address_t client_addr; -+ grub_efi_ipv4_address_t your_addr; -+ grub_efi_ipv4_address_t server_addr; -+ grub_efi_ipv4_address_t gateway_addr; -+ grub_efi_uint8_t client_hw_addr[16]; -+ grub_efi_char8_t server_name[64]; -+ grub_efi_char8_t boot_file_name[128]; -+} GRUB_PACKED; -+ -+typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t; -+ -+struct grub_efi_dhcp4_packet { -+ grub_efi_uint32_t size; -+ grub_efi_uint32_t length; -+ struct { -+ grub_efi_dhcp4_header_t header; -+ grub_efi_uint32_t magik; -+ grub_efi_uint8_t option[1]; -+ } dhcp4; -+} GRUB_PACKED; -+ -+typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t; -+ -+struct grub_efi_dhcp4_listen_point { -+ grub_efi_ipv4_address_t listen_address; -+ grub_efi_ipv4_address_t subnet_mask; -+ grub_efi_uint16_t listen_port; -+}; -+ -+typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t; -+ -+struct grub_efi_dhcp4_transmit_receive_token { -+ grub_efi_status_t status; -+ grub_efi_event_t completion_event; -+ grub_efi_ipv4_address_t remote_address; -+ grub_efi_uint16_t remote_port; -+ grub_efi_ipv4_address_t gateway_address; -+ grub_efi_uint32_t listen_point_count; -+ grub_efi_dhcp4_listen_point_t *listen_points; -+ grub_efi_uint32_t timeout_value; -+ grub_efi_dhcp4_packet_t *packet; -+ grub_efi_uint32_t response_count; -+ grub_efi_dhcp4_packet_t *response_list; -+}; -+ -+typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t; -+ -+enum grub_efi_dhcp4_event { -+ GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01, -+ GRUB_EFI_DHCP4_RCVD_OFFER, -+ GRUB_EFI_DHCP4_SELECT_OFFER, -+ GRUB_EFI_DHCP4_SEND_REQUEST, -+ GRUB_EFI_DHCP4_RCVD_ACK, -+ GRUB_EFI_DHCP4_RCVD_NAK, -+ GRUB_EFI_DHCP4_SEND_DECLINE, -+ GRUB_EFI_DHCP4_BOUND_COMPLETED, -+ GRUB_EFI_DHCP4_ENTER_RENEWING, -+ GRUB_EFI_DHCP4_ENTER_REBINDING, -+ GRUB_EFI_DHCP4_ADDRESS_LOST, -+ GRUB_EFI_DHCP4_FAIL -+}; -+ -+typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t; -+ -+struct grub_efi_dhcp4_packet_option { -+ grub_efi_uint8_t op_code; -+ grub_efi_uint8_t length; -+ grub_efi_uint8_t data[1]; -+} GRUB_PACKED; -+ -+typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t; -+ -+struct grub_efi_dhcp4_config_data { -+ grub_efi_uint32_t discover_try_count; -+ grub_efi_uint32_t *discover_timeout; -+ grub_efi_uint32_t request_try_count; -+ grub_efi_uint32_t *request_timeout; -+ grub_efi_ipv4_address_t client_address; -+ grub_efi_status_t (*dhcp4_callback) ( -+ grub_efi_dhcp4_protocol_t *this, -+ void *context, -+ grub_efi_dhcp4_state_t current_state, -+ grub_efi_dhcp4_event_t dhcp4_event, -+ grub_efi_dhcp4_packet_t *packet, -+ grub_efi_dhcp4_packet_t **new_packet -+ ); -+ void *callback_context; -+ grub_efi_uint32_t option_count; -+ grub_efi_dhcp4_packet_option_t **option_list; -+}; -+ -+typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t; -+ -+struct grub_efi_dhcp4_mode_data { -+ grub_efi_dhcp4_state_t state; -+ grub_efi_dhcp4_config_data_t config_data; -+ grub_efi_ipv4_address_t client_address; -+ grub_efi_mac_address_t client_mac_address; -+ grub_efi_ipv4_address_t server_address; -+ grub_efi_ipv4_address_t router_address; -+ grub_efi_ipv4_address_t subnet_mask; -+ grub_efi_uint32_t lease_time; -+ grub_efi_dhcp4_packet_t *reply_packet; -+}; -+ -+typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t; -+ -+struct grub_efi_dhcp4_protocol { -+ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this, -+ grub_efi_dhcp4_mode_data_t *dhcp4_mode_data); -+ grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this, -+ grub_efi_dhcp4_config_data_t *dhcp4_cfg_data); -+ grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this, -+ grub_efi_event_t completion_event); -+ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this, -+ grub_efi_boolean_t rebind_request, -+ grub_efi_event_t completion_event); -+ grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this); -+ grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this); -+ grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this, -+ grub_efi_dhcp4_packet_t *seed_packet, -+ grub_efi_uint32_t delete_count, -+ grub_efi_uint8_t *delete_list, -+ grub_efi_uint32_t append_count, -+ grub_efi_dhcp4_packet_option_t *append_list[], -+ grub_efi_dhcp4_packet_t **new_packet); -+ grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this, -+ grub_efi_dhcp4_transmit_receive_token_t *token); -+ grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this, -+ grub_efi_dhcp4_packet_t *packet, -+ grub_efi_uint32_t *option_count, -+ grub_efi_dhcp4_packet_option_t *packet_option_list[]); -+}; -+ -+typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t; -+ -+struct grub_efi_dhcp6_retransmission { -+ grub_efi_uint32_t irt; -+ grub_efi_uint32_t mrc; -+ grub_efi_uint32_t mrt; -+ grub_efi_uint32_t mrd; -+}; -+ -+typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t; -+ -+enum grub_efi_dhcp6_event { -+ GRUB_EFI_DHCP6_SEND_SOLICIT, -+ GRUB_EFI_DHCP6_RCVD_ADVERTISE, -+ GRUB_EFI_DHCP6_SELECT_ADVERTISE, -+ GRUB_EFI_DHCP6_SEND_REQUEST, -+ GRUB_EFI_DHCP6_RCVD_REPLY, -+ GRUB_EFI_DHCP6_RCVD_RECONFIGURE, -+ GRUB_EFI_DHCP6_SEND_DECLINE, -+ GRUB_EFI_DHCP6_SEND_CONFIRM, -+ GRUB_EFI_DHCP6_SEND_RELEASE, -+ GRUB_EFI_DHCP6_SEND_RENEW, -+ GRUB_EFI_DHCP6_SEND_REBIND -+}; -+ -+typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t; -+ -+struct grub_efi_dhcp6_packet_option { -+ grub_efi_uint16_t op_code; -+ grub_efi_uint16_t op_len; -+ grub_efi_uint8_t data[1]; -+} GRUB_PACKED; -+ -+typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t; -+ -+struct grub_efi_dhcp6_header { -+ grub_efi_uint32_t transaction_id:24; -+ grub_efi_uint32_t message_type:8; -+} GRUB_PACKED; -+ -+typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t; -+ -+struct grub_efi_dhcp6_packet { -+ grub_efi_uint32_t size; -+ grub_efi_uint32_t length; -+ struct { -+ grub_efi_dhcp6_header_t header; -+ grub_efi_uint8_t option[1]; -+ } dhcp6; -+} GRUB_PACKED; -+ -+typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t; -+ -+struct grub_efi_dhcp6_ia_address { -+ grub_efi_ipv6_address_t ip_address; -+ grub_efi_uint32_t preferred_lifetime; -+ grub_efi_uint32_t valid_lifetime; -+}; -+ -+typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t; -+ -+enum grub_efi_dhcp6_state { -+ GRUB_EFI_DHCP6_INIT, -+ GRUB_EFI_DHCP6_SELECTING, -+ GRUB_EFI_DHCP6_REQUESTING, -+ GRUB_EFI_DHCP6_DECLINING, -+ GRUB_EFI_DHCP6_CONFIRMING, -+ GRUB_EFI_DHCP6_RELEASING, -+ GRUB_EFI_DHCP6_BOUND, -+ GRUB_EFI_DHCP6_RENEWING, -+ GRUB_EFI_DHCP6_REBINDING -+}; -+ -+typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t; -+ -+#define GRUB_EFI_DHCP6_IA_TYPE_NA 3 -+#define GRUB_EFI_DHCP6_IA_TYPE_TA 4 -+ -+struct grub_efi_dhcp6_ia_descriptor { -+ grub_efi_uint16_t type; -+ grub_efi_uint32_t ia_id; -+}; -+ -+typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t; -+ -+struct grub_efi_dhcp6_ia { -+ grub_efi_dhcp6_ia_descriptor_t descriptor; -+ grub_efi_dhcp6_state_t state; -+ grub_efi_dhcp6_packet_t *reply_packet; -+ grub_efi_uint32_t ia_address_count; -+ grub_efi_dhcp6_ia_address_t ia_address[1]; -+}; -+ -+typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t; -+ -+struct grub_efi_dhcp6_duid { -+ grub_efi_uint16_t length; -+ grub_efi_uint8_t duid[1]; -+}; -+ -+typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t; -+ -+struct grub_efi_dhcp6_mode_data { -+ grub_efi_dhcp6_duid_t *client_id; -+ grub_efi_dhcp6_ia_t *ia; -+}; -+ -+typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t; -+ -+struct grub_efi_dhcp6_config_data { -+ grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this, -+ void *context, -+ grub_efi_dhcp6_state_t current_state, -+ grub_efi_dhcp6_event_t dhcp6_event, -+ grub_efi_dhcp6_packet_t *packet, -+ grub_efi_dhcp6_packet_t **new_packet); -+ void *callback_context; -+ grub_efi_uint32_t option_count; -+ grub_efi_dhcp6_packet_option_t **option_list; -+ grub_efi_dhcp6_ia_descriptor_t ia_descriptor; -+ grub_efi_event_t ia_info_event; -+ grub_efi_boolean_t reconfigure_accept; -+ grub_efi_boolean_t rapid_commit; -+ grub_efi_dhcp6_retransmission_t *solicit_retransmission; -+}; -+ -+typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t; -+ -+struct grub_efi_dhcp6_protocol { -+ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this, -+ grub_efi_dhcp6_mode_data_t *dhcp6_mode_data, -+ grub_efi_dhcp6_config_data_t *dhcp6_config_data); -+ grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this, -+ grub_efi_dhcp6_config_data_t *dhcp6_cfg_data); -+ grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this); -+ grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this, -+ grub_efi_boolean_t send_client_id, -+ grub_efi_dhcp6_packet_option_t *option_request, -+ grub_efi_uint32_t option_count, -+ grub_efi_dhcp6_packet_option_t *option_list[], -+ grub_efi_dhcp6_retransmission_t *retransmission, -+ grub_efi_event_t timeout_event, -+ grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this, -+ void *context, -+ grub_efi_dhcp6_packet_t *packet), -+ void *callback_context); -+ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this, -+ grub_efi_boolean_t rebind_request); -+ grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this, -+ grub_efi_uint32_t address_count, -+ grub_efi_ipv6_address_t *addresses); -+ grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this, -+ grub_efi_uint32_t address_count, -+ grub_efi_ipv6_address_t *addresses); -+ grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this); -+ grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this, -+ grub_efi_dhcp6_packet_t *packet, -+ grub_efi_uint32_t *option_count, -+ grub_efi_dhcp6_packet_option_t *packet_option_list[]); -+}; -+ -+#endif /* ! GRUB_EFI_DHCP_HEADER */ -diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h -new file mode 100644 -index 0000000000..c5e9a89f50 ---- /dev/null -+++ b/include/grub/efi/http.h -@@ -0,0 +1,215 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_EFI_HTTP_HEADER -+#define GRUB_EFI_HTTP_HEADER 1 -+ -+#include -+#include -+#include -+ -+#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ -+ { 0xbdc8e6af, 0xd9bc, 0x4379, \ -+ { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ -+ } -+ -+#define GRUB_EFI_HTTP_PROTOCOL_GUID \ -+ { 0x7A59B29B, 0x910B, 0x4171, \ -+ { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \ -+ } -+ -+#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s -+#define EFIHTTP_RX_BUF_LEN 10240 -+ -+//****************************************** -+// Protocol Interface Structure -+//****************************************** -+struct grub_efi_http; -+ -+//****************************************** -+// EFI_HTTP_VERSION -+//****************************************** -+typedef enum { -+ GRUB_EFI_HTTPVERSION10, -+ GRUB_EFI_HTTPVERSION11, -+ GRUB_EFI_HTTPVERSIONUNSUPPORTED -+} grub_efi_http_version_t; -+ -+//****************************************** -+// EFI_HTTPv4_ACCESS_POINT -+//****************************************** -+typedef struct { -+ grub_efi_boolean_t use_default_address; -+ grub_efi_ipv4_address_t local_address; -+ grub_efi_ipv4_address_t local_subnet; -+ grub_efi_uint16_t local_port; -+} grub_efi_httpv4_access_point_t; -+ -+//****************************************** -+// EFI_HTTPv6_ACCESS_POINT -+//****************************************** -+typedef struct { -+ grub_efi_ipv6_address_t local_address; -+ grub_efi_uint16_t local_port; -+} grub_efi_httpv6_access_point_t; -+ -+//****************************************** -+// EFI_HTTP_CONFIG_DATA -+//****************************************** -+typedef struct { -+ grub_efi_http_version_t http_version; -+ grub_efi_uint32_t timeout_millisec; -+ grub_efi_boolean_t local_address_is_ipv6; -+ union { -+ grub_efi_httpv4_access_point_t *ipv4_node; -+ grub_efi_httpv6_access_point_t *ipv6_node; -+ } access_point; -+} grub_efi_http_config_data_t; -+ -+//****************************************** -+// EFI_HTTP_METHOD -+//****************************************** -+typedef enum { -+ GRUB_EFI_HTTPMETHODGET, -+ GRUB_EFI_HTTPMETHODPOST, -+ GRUB_EFI_HTTPMETHODPATCH, -+ GRUB_EFI_HTTPMETHODOPTIONS, -+ GRUB_EFI_HTTPMETHODCONNECT, -+ GRUB_EFI_HTTPMETHODHEAD, -+ GRUB_EFI_HTTPMETHODPUT, -+ GRUB_EFI_HTTPMETHODDELETE, -+ GRUB_EFI_HTTPMETHODTRACE, -+} grub_efi_http_method_t; -+ -+//****************************************** -+// EFI_HTTP_REQUEST_DATA -+//****************************************** -+typedef struct { -+ grub_efi_http_method_t method; -+ grub_efi_char16_t *url; -+} grub_efi_http_request_data_t; -+ -+typedef enum { -+ GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, -+ GRUB_EFI_HTTP_STATUS_100_CONTINUE, -+ GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS, -+ GRUB_EFI_HTTP_STATUS_200_OK, -+ GRUB_EFI_HTTP_STATUS_201_CREATED, -+ GRUB_EFI_HTTP_STATUS_202_ACCEPTED, -+ GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, -+ GRUB_EFI_HTTP_STATUS_204_NO_CONTENT, -+ GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT, -+ GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT, -+ GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES, -+ GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY, -+ GRUB_EFI_HTTP_STATUS_302_FOUND, -+ GRUB_EFI_HTTP_STATUS_303_SEE_OTHER, -+ GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED, -+ GRUB_EFI_HTTP_STATUS_305_USE_PROXY, -+ GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT, -+ GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST, -+ GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED, -+ GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED, -+ GRUB_EFI_HTTP_STATUS_403_FORBIDDEN, -+ GRUB_EFI_HTTP_STATUS_404_NOT_FOUND, -+ GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED, -+ GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE, -+ GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, -+ GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT, -+ GRUB_EFI_HTTP_STATUS_409_CONFLICT, -+ GRUB_EFI_HTTP_STATUS_410_GONE, -+ GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED, -+ GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED, -+ GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, -+ GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, -+ GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, -+ GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, -+ GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED, -+ GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR, -+ GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED, -+ GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY, -+ GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE, -+ GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT, -+ GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED -+} grub_efi_http_status_code_t; -+ -+//****************************************** -+// EFI_HTTP_RESPONSE_DATA -+//****************************************** -+typedef struct { -+ grub_efi_http_status_code_t status_code; -+} grub_efi_http_response_data_t; -+ -+//****************************************** -+// EFI_HTTP_HEADER -+//****************************************** -+typedef struct { -+ grub_efi_char8_t *field_name; -+ grub_efi_char8_t *field_value; -+} grub_efi_http_header_t; -+ -+//****************************************** -+// EFI_HTTP_MESSAGE -+//****************************************** -+typedef struct { -+ union { -+ grub_efi_http_request_data_t *request; -+ grub_efi_http_response_data_t *response; -+ } data; -+ grub_efi_uint32_t header_count; -+ grub_efi_http_header_t *headers; -+ grub_efi_uint32_t body_length; -+ void *body; -+} grub_efi_http_message_t; -+ -+//****************************************** -+// EFI_HTTP_TOKEN -+//****************************************** -+typedef struct { -+ grub_efi_event_t event; -+ grub_efi_status_t status; -+ grub_efi_http_message_t *message; -+} grub_efi_http_token_t; -+ -+struct grub_efi_http { -+ grub_efi_status_t -+ (*get_mode_data) (struct grub_efi_http *this, -+ grub_efi_http_config_data_t *http_config_data); -+ -+ grub_efi_status_t -+ (*configure) (struct grub_efi_http *this, -+ grub_efi_http_config_data_t *http_config_data); -+ -+ grub_efi_status_t -+ (*request) (struct grub_efi_http *this, -+ grub_efi_http_token_t *token); -+ -+ grub_efi_status_t -+ (*cancel) (struct grub_efi_http *this, -+ grub_efi_http_token_t *token); -+ -+ grub_efi_status_t -+ (*response) (struct grub_efi_http *this, -+ grub_efi_http_token_t *token); -+ -+ grub_efi_status_t -+ (*poll) (struct grub_efi_http *this); -+}; -+typedef struct grub_efi_http grub_efi_http_t; -+ -+#endif /* !GRUB_EFI_HTTP_HEADER */ -diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h -new file mode 100644 -index 0000000000..de90d223e8 ---- /dev/null -+++ b/include/grub/net/efi.h -@@ -0,0 +1,144 @@ -+#ifndef GRUB_NET_EFI_HEADER -+#define GRUB_NET_EFI_HEADER 1 -+ -+#include -+#include -+#include -+#include -+ -+typedef struct grub_efi_net_interface grub_efi_net_interface_t; -+typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t; -+typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t; -+typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t; -+ -+struct grub_efi_net_interface -+{ -+ char *name; -+ int prefer_ip6; -+ struct grub_efi_net_device *dev; -+ struct grub_efi_net_io *io; -+ grub_efi_net_ip_config_t *ip_config; -+ int io_type; -+ struct grub_efi_net_interface *next; -+}; -+ -+#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev) -+#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev) -+#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev) -+#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet) -+#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr) -+#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr) -+ -+struct grub_efi_net_ip_config -+{ -+ char * (*get_hw_address) (struct grub_efi_net_device *dev); -+ char * (*get_address) (struct grub_efi_net_device *dev); -+ char ** (*get_route_table) (struct grub_efi_net_device *dev); -+ grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); -+ int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet); -+ int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); -+ int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns); -+}; -+ -+union grub_efi_net_ip_address -+{ -+ grub_efi_ipv4_address_t ip4; -+ grub_efi_ipv6_address_t ip6; -+}; -+ -+struct grub_efi_net_ip_manual_address -+{ -+ int is_ip6; -+ union -+ { -+ grub_efi_ip4_config2_manual_address_t ip4; -+ grub_efi_ip6_config_manual_address_t ip6; -+ }; -+}; -+ -+struct grub_efi_net_device -+{ -+ grub_efi_handle_t handle; -+ grub_efi_ip4_config2_protocol_t *ip4_config; -+ grub_efi_ip6_config_protocol_t *ip6_config; -+ grub_efi_handle_t http_handle; -+ grub_efi_http_t *http; -+ grub_efi_handle_t ip4_pxe_handle; -+ grub_efi_pxe_t *ip4_pxe; -+ grub_efi_handle_t ip6_pxe_handle; -+ grub_efi_pxe_t *ip6_pxe; -+ grub_efi_handle_t dhcp4_handle; -+ grub_efi_dhcp4_protocol_t *dhcp4; -+ grub_efi_handle_t dhcp6_handle; -+ grub_efi_dhcp6_protocol_t *dhcp6; -+ char *card_name; -+ grub_efi_net_interface_t *net_interfaces; -+ struct grub_efi_net_device *next; -+}; -+ -+struct grub_efi_net_io -+{ -+ void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6); -+ grub_err_t (*open) (struct grub_efi_net_device *dev, -+ int prefer_ip6, -+ grub_file_t file, -+ const char *filename, -+ int type); -+ grub_ssize_t (*read) (struct grub_efi_net_device *dev, -+ int prefer_ip6, -+ grub_file_t file, -+ char *buf, -+ grub_size_t len); -+ grub_err_t (*close) (struct grub_efi_net_device *dev, -+ int prefer_ip6, -+ grub_file_t file); -+}; -+ -+extern struct grub_efi_net_device *net_devices; -+ -+extern struct grub_efi_net_io io_http; -+extern struct grub_efi_net_io io_pxe; -+ -+extern grub_efi_net_ip_config_t *efi_net_ip4_config; -+extern grub_efi_net_ip_config_t *efi_net_ip6_config; -+ -+char * -+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address); -+ -+char * -+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address); -+ -+char * -+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address); -+ -+int -+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest); -+ -+int -+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest); -+ -+char * -+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev); -+ -+char * -+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev); -+ -+grub_efi_net_interface_t * -+grub_efi_net_create_interface (struct grub_efi_net_device *dev, -+ const char *interface_name, -+ grub_efi_net_ip_manual_address_t *net_ip, -+ int has_subnet); -+ -+int grub_efi_net_fs_init (void); -+void grub_efi_net_fs_fini (void); -+int grub_efi_net_boot_from_https (void); -+int grub_efi_net_boot_from_opa (void); -+ -+extern grub_command_func_t grub_efi_net_list_routes; -+extern grub_command_func_t grub_efi_net_list_cards; -+extern grub_command_func_t grub_efi_net_list_addrs; -+extern grub_command_func_t grub_efi_net_add_addr; -+extern grub_command_func_t grub_efi_net_bootp; -+extern grub_command_func_t grub_efi_net_bootp6; -+ -+#endif /* ! GRUB_NET_EFI_HEADER */ diff --git a/0081-AUDIT-0-http-boot-tracker-bug.patch b/0081-AUDIT-0-http-boot-tracker-bug.patch deleted file mode 100644 index b487271..0000000 --- a/0081-AUDIT-0-http-boot-tracker-bug.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sebastian Krahmer -Date: Tue, 28 Nov 2017 17:24:38 +0800 -Subject: [PATCH] AUDIT-0: http boot tracker bug - -Fixing a memory leak in case of error, and a integer overflow, leading to a -heap overflow due to overly large chunk sizes. - -We need to check against some maximum value, otherwise values like 0xffffffff -will eventually lead in the allocation functions to small sized buffers, since -the len is rounded up to the next reasonable alignment. The following memcpy -will then smash the heap, leading to RCE. - -This is no big issue for pure http boot, since its going to execute an -untrusted kernel anyway, but it will break trusted boot scenarios, where only -signed code is allowed to be executed. - -Signed-off-by: Michael Chang ---- - grub-core/net/efi/net.c | 4 +++- - grub-core/net/http.c | 5 ++++- - 2 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c -index 86bce6535d..4bb308026c 100644 ---- a/grub-core/net/efi/net.c -+++ b/grub-core/net/efi/net.c -@@ -645,8 +645,10 @@ grub_efihttp_chunk_read (grub_file_t file, char *buf, - - rd = efi_net_interface (read, file, chunk, sz); - -- if (rd <= 0) -+ if (rd <= 0) { -+ grub_free (chunk); - return rd; -+ } - - if (buf) - { -diff --git a/grub-core/net/http.c b/grub-core/net/http.c -index 12a2632ea5..b52b558d63 100644 ---- a/grub-core/net/http.c -+++ b/grub-core/net/http.c -@@ -31,7 +31,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); - - enum - { -- HTTP_PORT = 80 -+ HTTP_PORT = 80, -+ HTTP_MAX_CHUNK_SIZE = 0x80000000 - }; - - -@@ -78,6 +79,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) - if (data->in_chunk_len == 2) - { - data->chunk_rem = grub_strtoul (ptr, 0, 16); -+ if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE) -+ return GRUB_ERR_NET_PACKET_TOO_BIG; - grub_errno = GRUB_ERR_NONE; - if (data->chunk_rem == 0) - { diff --git a/0081-grub-editenv-Add-incr-command-to-increment-integer-v.patch b/0081-grub-editenv-Add-incr-command-to-increment-integer-v.patch new file mode 100644 index 0000000..6e2e4e2 --- /dev/null +++ b/0081-grub-editenv-Add-incr-command-to-increment-integer-v.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 4 Jun 2018 19:49:47 +0200 +Subject: [PATCH] grub-editenv: Add "incr" command to increment integer value + env. variables + +To be able to automatically detect if the last boot was successful, +We want to keep count of succesful / failed boots in some integer +environment variable. + +This commit adds a grub-editenvt "incr" command to increment such +integer value env. variables by 1 for use from various boot scripts. + +Signed-off-by: Hans de Goede +--- + util/grub-editenv.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/util/grub-editenv.c b/util/grub-editenv.c +index db6f187cc6..948eec8a11 100644 +--- a/util/grub-editenv.c ++++ b/util/grub-editenv.c +@@ -53,6 +53,9 @@ static struct argp_option options[] = { + /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */ + {N_("unset [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("Delete variables."), 0}, ++ /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand. */ ++ {N_("incr [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, ++ N_("Increase value of integer variables."), 0}, + + {0, 0, 0, OPTION_DOC, N_("Options:"), -1}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, +@@ -253,6 +256,51 @@ unset_variables (const char *name, int argc, char *argv[]) + grub_envblk_close (envblk); + } + ++struct get_int_value_params { ++ char *varname; ++ int value; ++}; ++ ++static int ++get_int_value (const char *varname, const char *value, void *hook_data) ++{ ++ struct get_int_value_params *params = hook_data; ++ ++ if (strcmp (varname, params->varname) == 0) { ++ params->value = strtol (value, NULL, 10); ++ return 1; ++ } ++ return 0; ++} ++ ++static void ++incr_variables (const char *name, int argc, char *argv[]) ++{ ++ grub_envblk_t envblk; ++ char buf[16]; ++ ++ envblk = open_envblk_file (name); ++ while (argc) ++ { ++ struct get_int_value_params params = { ++ .varname = argv[0], ++ .value = 0, /* Consider unset variables 0 */ ++ }; ++ ++ grub_envblk_iterate (envblk, ¶ms, get_int_value); ++ snprintf(buf, sizeof(buf), "%d", params.value + 1); ++ ++ if (! grub_envblk_set (envblk, argv[0], buf)) ++ grub_util_error ("%s", _("environment block too small")); ++ ++ argc--; ++ argv++; ++ } ++ ++ write_envblk (name, envblk); ++ grub_envblk_close (envblk); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -292,6 +340,8 @@ main (int argc, char *argv[]) + set_variables (filename, argc - curindex, argv + curindex); + else if (strcmp (command, "unset") == 0) + unset_variables (filename, argc - curindex, argv + curindex); ++ else if (strcmp (command, "incr") == 0) ++ incr_variables (filename, argc - curindex, argv + curindex); + else + { + char *program = xstrdup(program_name); diff --git a/0082-Add-auto-hide-menu-support.patch b/0082-Add-auto-hide-menu-support.patch new file mode 100644 index 0000000..a4fbe4a --- /dev/null +++ b/0082-Add-auto-hide-menu-support.patch @@ -0,0 +1,183 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 6 Jun 2018 08:44:11 +0200 +Subject: [PATCH] Add auto-hide menu support + +On single-os systems we do not want to show the menu, unless something +went wrong with the previous boot, in which case the user may need the +menu to debug/fix the problem. + +This commit adds a new grub.d/00_menu_auto_hide file which emits a +config snippet implementing this. I've chosen to do this in a separate +grub.d file because chances of this going upstream are small and this way +it will be easier to rebase. + +Since auto-hiding the menu requires detecting the previous boot was ok, +we get fastboot support (where we don't check for a key at all) for free +so this commit also adds support for this. + +The new config-file code uses the following variables: + +menu_auto_hide Set this to "1" to activate the new auto-hide feature + Set this to "2" to auto-hide the menu even when multiple + operating systems are installed. Note the menu will still + auto show after booting an other os as that won't set + boot_success. +menu_show_once Set this to "1" to force showing the menu once. +boot_success The OS sets this to "1" to indicate a successful boot. +boot_indeterminate The OS increments this integer when rebooting after e.g. + installing updates or a selinux relabel. +fastboot If set to "1" and the conditions for auto-hiding the menu + are met, the menu is not shown and all checks for keypresses + are skipped, booting the default immediately. + +30_os-prober.in changes somewhat inspired by: +https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/quick_boot.patch + +Signed-off-by: Hans de Goede +--- + Makefile.util.def | 6 +++++ + util/grub.d/01_menu_auto_hide.in | 48 ++++++++++++++++++++++++++++++++++++++++ + util/grub.d/30_os-prober.in | 18 +++++++++++++++ + 3 files changed, 72 insertions(+) + create mode 100644 util/grub.d/01_menu_auto_hide.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index bda9fd1211..cb8e3c3270 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -458,6 +458,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '01_menu_auto_hide'; ++ common = util/grub.d/01_menu_auto_hide.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '01_users'; + common = util/grub.d/01_users.in; +diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/01_menu_auto_hide.in +new file mode 100644 +index 0000000000..ad175870a5 +--- /dev/null ++++ b/util/grub.d/01_menu_auto_hide.in +@@ -0,0 +1,48 @@ ++#! /bin/sh ++ ++# Disable / skip generating menu-auto-hide config parts on serial terminals ++for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do ++ case "$x" in ++ serial*) ++ exit 0 ++ ;; ++ esac ++done ++ ++cat << EOF ++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then ++ set last_boot_ok=1 ++else ++ set last_boot_ok=0 ++fi ++ ++# Reset boot_indeterminate after a successful boot ++if [ "\${boot_success}" = "1" ] ; then ++ set boot_indeterminate=0 ++# Avoid boot_indeterminate causing the menu to be hidden more then once ++elif [ "\${boot_indeterminate}" = "1" ]; then ++ set boot_indeterminate=2 ++fi ++set boot_success=0 ++save_env boot_success boot_indeterminate ++ ++if [ x\$feature_timeout_style = xy ] ; then ++ if [ "\${menu_show_once}" ]; then ++ unset menu_show_once ++ save_env menu_show_once ++ set timeout_style=menu ++ set timeout=60 ++ elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then ++ set orig_timeout_style=\${timeout_style} ++ set orig_timeout=\${timeout} ++ if [ "\${fastboot}" = "1" ]; then ++ # timeout_style=menu + timeout=0 avoids the countdown code keypress check ++ set timeout_style=menu ++ set timeout=0 ++ else ++ set timeout_style=hidden ++ set timeout=1 ++ fi ++ fi ++fi ++EOF +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 4b27bd2015..3c9431cfcf 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -42,6 +42,7 @@ if [ -z "${OSPROBED}" ] ; then + fi + + osx_entry() { ++ found_other_os=1 + # TRANSLATORS: it refers on the OS residing on device %s + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + hints="" +@@ -102,6 +103,7 @@ for OS in ${OSPROBED} ; do + + case ${BOOT} in + chain) ++ found_other_os=1 + + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF +@@ -132,6 +134,7 @@ EOF + EOF + ;; + efi) ++ found_other_os=1 + + EFIPATH=${DEVICE#*@} + DEVICE=${DEVICE%@*} +@@ -176,6 +179,7 @@ EOF + LINITRD="${LINITRD#/boot}" + fi + ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + recovery_params="$(echo "${LPARAMS}" | grep single)" || true + counter=1 +@@ -257,6 +261,7 @@ EOF + done + ;; + hurd) ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF + menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' { +@@ -283,6 +288,7 @@ EOF + EOF + ;; + minix) ++ found_other_os=1 + cat << EOF + menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" { + EOF +@@ -299,3 +305,15 @@ EOF + ;; + esac + done ++ ++# We override the results of the menu_auto_hide code here, this is a bit ugly, ++# but grub-mkconfig writes out the file linearly, so this is the only way ++if [ "${found_other_os}" = "1" ]; then ++ cat << EOF ++# Other OS found, undo autohiding of menu unless menu_auto_hide=2 ++if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then ++ set timeout_style=\${orig_timeout_style} ++ set timeout=\${orig_timeout} ++fi ++EOF ++fi diff --git a/0082-grub-editenv-Add-incr-command-to-increment-integer-v.patch b/0082-grub-editenv-Add-incr-command-to-increment-integer-v.patch deleted file mode 100644 index 6e2e4e2..0000000 --- a/0082-grub-editenv-Add-incr-command-to-increment-integer-v.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 4 Jun 2018 19:49:47 +0200 -Subject: [PATCH] grub-editenv: Add "incr" command to increment integer value - env. variables - -To be able to automatically detect if the last boot was successful, -We want to keep count of succesful / failed boots in some integer -environment variable. - -This commit adds a grub-editenvt "incr" command to increment such -integer value env. variables by 1 for use from various boot scripts. - -Signed-off-by: Hans de Goede ---- - util/grub-editenv.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 50 insertions(+) - -diff --git a/util/grub-editenv.c b/util/grub-editenv.c -index db6f187cc6..948eec8a11 100644 ---- a/util/grub-editenv.c -+++ b/util/grub-editenv.c -@@ -53,6 +53,9 @@ static struct argp_option options[] = { - /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */ - {N_("unset [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, - N_("Delete variables."), 0}, -+ /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand. */ -+ {N_("incr [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, -+ N_("Increase value of integer variables."), 0}, - - {0, 0, 0, OPTION_DOC, N_("Options:"), -1}, - {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, -@@ -253,6 +256,51 @@ unset_variables (const char *name, int argc, char *argv[]) - grub_envblk_close (envblk); - } - -+struct get_int_value_params { -+ char *varname; -+ int value; -+}; -+ -+static int -+get_int_value (const char *varname, const char *value, void *hook_data) -+{ -+ struct get_int_value_params *params = hook_data; -+ -+ if (strcmp (varname, params->varname) == 0) { -+ params->value = strtol (value, NULL, 10); -+ return 1; -+ } -+ return 0; -+} -+ -+static void -+incr_variables (const char *name, int argc, char *argv[]) -+{ -+ grub_envblk_t envblk; -+ char buf[16]; -+ -+ envblk = open_envblk_file (name); -+ while (argc) -+ { -+ struct get_int_value_params params = { -+ .varname = argv[0], -+ .value = 0, /* Consider unset variables 0 */ -+ }; -+ -+ grub_envblk_iterate (envblk, ¶ms, get_int_value); -+ snprintf(buf, sizeof(buf), "%d", params.value + 1); -+ -+ if (! grub_envblk_set (envblk, argv[0], buf)) -+ grub_util_error ("%s", _("environment block too small")); -+ -+ argc--; -+ argv++; -+ } -+ -+ write_envblk (name, envblk); -+ grub_envblk_close (envblk); -+} -+ - int - main (int argc, char *argv[]) - { -@@ -292,6 +340,8 @@ main (int argc, char *argv[]) - set_variables (filename, argc - curindex, argv + curindex); - else if (strcmp (command, "unset") == 0) - unset_variables (filename, argc - curindex, argv + curindex); -+ else if (strcmp (command, "incr") == 0) -+ incr_variables (filename, argc - curindex, argv + curindex); - else - { - char *program = xstrdup(program_name); diff --git a/0083-Add-auto-hide-menu-support.patch b/0083-Add-auto-hide-menu-support.patch deleted file mode 100644 index f5aed0e..0000000 --- a/0083-Add-auto-hide-menu-support.patch +++ /dev/null @@ -1,183 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 6 Jun 2018 08:44:11 +0200 -Subject: [PATCH] Add auto-hide menu support - -On single-os systems we do not want to show the menu, unless something -went wrong with the previous boot, in which case the user may need the -menu to debug/fix the problem. - -This commit adds a new grub.d/00_menu_auto_hide file which emits a -config snippet implementing this. I've chosen to do this in a separate -grub.d file because chances of this going upstream are small and this way -it will be easier to rebase. - -Since auto-hiding the menu requires detecting the previous boot was ok, -we get fastboot support (where we don't check for a key at all) for free -so this commit also adds support for this. - -The new config-file code uses the following variables: - -menu_auto_hide Set this to "1" to activate the new auto-hide feature - Set this to "2" to auto-hide the menu even when multiple - operating systems are installed. Note the menu will still - auto show after booting an other os as that won't set - boot_success. -menu_show_once Set this to "1" to force showing the menu once. -boot_success The OS sets this to "1" to indicate a successful boot. -boot_indeterminate The OS increments this integer when rebooting after e.g. - installing updates or a selinux relabel. -fastboot If set to "1" and the conditions for auto-hiding the menu - are met, the menu is not shown and all checks for keypresses - are skipped, booting the default immediately. - -30_os-prober.in changes somewhat inspired by: -https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/quick_boot.patch - -Signed-off-by: Hans de Goede ---- - Makefile.util.def | 6 +++++ - util/grub.d/01_menu_auto_hide.in | 48 ++++++++++++++++++++++++++++++++++++++++ - util/grub.d/30_os-prober.in | 18 +++++++++++++++ - 3 files changed, 72 insertions(+) - create mode 100644 util/grub.d/01_menu_auto_hide.in - -diff --git a/Makefile.util.def b/Makefile.util.def -index 48512bc631..314e6f2acf 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -458,6 +458,12 @@ script = { - installdir = grubconf; - }; - -+script = { -+ name = '01_menu_auto_hide'; -+ common = util/grub.d/01_menu_auto_hide.in; -+ installdir = grubconf; -+}; -+ - script = { - name = '01_users'; - common = util/grub.d/01_users.in; -diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/01_menu_auto_hide.in -new file mode 100644 -index 0000000000..ad175870a5 ---- /dev/null -+++ b/util/grub.d/01_menu_auto_hide.in -@@ -0,0 +1,48 @@ -+#! /bin/sh -+ -+# Disable / skip generating menu-auto-hide config parts on serial terminals -+for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do -+ case "$x" in -+ serial*) -+ exit 0 -+ ;; -+ esac -+done -+ -+cat << EOF -+if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then -+ set last_boot_ok=1 -+else -+ set last_boot_ok=0 -+fi -+ -+# Reset boot_indeterminate after a successful boot -+if [ "\${boot_success}" = "1" ] ; then -+ set boot_indeterminate=0 -+# Avoid boot_indeterminate causing the menu to be hidden more then once -+elif [ "\${boot_indeterminate}" = "1" ]; then -+ set boot_indeterminate=2 -+fi -+set boot_success=0 -+save_env boot_success boot_indeterminate -+ -+if [ x\$feature_timeout_style = xy ] ; then -+ if [ "\${menu_show_once}" ]; then -+ unset menu_show_once -+ save_env menu_show_once -+ set timeout_style=menu -+ set timeout=60 -+ elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then -+ set orig_timeout_style=\${timeout_style} -+ set orig_timeout=\${timeout} -+ if [ "\${fastboot}" = "1" ]; then -+ # timeout_style=menu + timeout=0 avoids the countdown code keypress check -+ set timeout_style=menu -+ set timeout=0 -+ else -+ set timeout_style=hidden -+ set timeout=1 -+ fi -+ fi -+fi -+EOF -diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in -index 4b27bd2015..3c9431cfcf 100644 ---- a/util/grub.d/30_os-prober.in -+++ b/util/grub.d/30_os-prober.in -@@ -42,6 +42,7 @@ if [ -z "${OSPROBED}" ] ; then - fi - - osx_entry() { -+ found_other_os=1 - # TRANSLATORS: it refers on the OS residing on device %s - onstr="$(gettext_printf "(on %s)" "${DEVICE}")" - hints="" -@@ -102,6 +103,7 @@ for OS in ${OSPROBED} ; do - - case ${BOOT} in - chain) -+ found_other_os=1 - - onstr="$(gettext_printf "(on %s)" "${DEVICE}")" - cat << EOF -@@ -132,6 +134,7 @@ EOF - EOF - ;; - efi) -+ found_other_os=1 - - EFIPATH=${DEVICE#*@} - DEVICE=${DEVICE%@*} -@@ -176,6 +179,7 @@ EOF - LINITRD="${LINITRD#/boot}" - fi - -+ found_other_os=1 - onstr="$(gettext_printf "(on %s)" "${DEVICE}")" - recovery_params="$(echo "${LPARAMS}" | grep single)" || true - counter=1 -@@ -257,6 +261,7 @@ EOF - done - ;; - hurd) -+ found_other_os=1 - onstr="$(gettext_printf "(on %s)" "${DEVICE}")" - cat << EOF - menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' { -@@ -283,6 +288,7 @@ EOF - EOF - ;; - minix) -+ found_other_os=1 - cat << EOF - menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" { - EOF -@@ -299,3 +305,15 @@ EOF - ;; - esac - done -+ -+# We override the results of the menu_auto_hide code here, this is a bit ugly, -+# but grub-mkconfig writes out the file linearly, so this is the only way -+if [ "${found_other_os}" = "1" ]; then -+ cat << EOF -+# Other OS found, undo autohiding of menu unless menu_auto_hide=2 -+if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then -+ set timeout_style=\${orig_timeout_style} -+ set timeout=\${orig_timeout} -+fi -+EOF -+fi diff --git a/0083-Add-grub-set-bootflag-utility.patch b/0083-Add-grub-set-bootflag-utility.patch new file mode 100644 index 0000000..495bb13 --- /dev/null +++ b/0083-Add-grub-set-bootflag-utility.patch @@ -0,0 +1,290 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 12 Jun 2018 13:25:16 +0200 +Subject: [PATCH] Add grub-set-bootflag utility + +This commit adds a new grub-set-bootflag utility, which can be used +to set known bootflags in the grubenv: boot_success or menu_show_once. + +grub-set-bootflag is different from grub-editenv in 2 ways: + +1) It is intended to be executed by regular users so must be installed +as suid root. As such it is written to not use any existing grubenv +related code for easy auditing. + +It can't be executed through pkexec because we want to call it under gdm +and pkexec does not work under gdm due the gdm user having /sbin/nologin +as shell. + +2) Since it can be executed by regular users it only allows setting +(assigning a value of 1 to) bootflags which it knows about. Currently +those are just boot_success and menu_show_once. + +This commit also adds a couple of example systemd and files which show +how this can be used to set boot_success from a user-session: + +docs/grub-boot-success.service +docs/grub-boot-success.timer + +The 2 grub-boot-success.systemd files should be placed in /lib/systemd/user +and a symlink to grub-boot-success.timer should be added to +/lib/systemd/user/timers.target.wants. + +Signed-off-by: Hans de Goede +[makhomed: grub-boot-success.timer: Only run if not in a container] +Signed-off-by: Gena Makhomed +[rharwood: migrate to h2m] +Signed-off-by: Robbie Harwood +--- + Makefile.util.def | 7 ++ + util/grub-set-bootflag.c | 172 +++++++++++++++++++++++++++++++++++++++++ + conf/Makefile.extra-dist | 3 + + docs/grub-boot-success.service | 6 ++ + docs/grub-boot-success.timer | 7 ++ + docs/man/grub-set-bootflag.h2m | 2 + + 6 files changed, 197 insertions(+) + create mode 100644 util/grub-set-bootflag.c + create mode 100644 docs/grub-boot-success.service + create mode 100644 docs/grub-boot-success.timer + create mode 100644 docs/man/grub-set-bootflag.h2m + +diff --git a/Makefile.util.def b/Makefile.util.def +index cb8e3c3270..d066652e9b 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1429,3 +1429,10 @@ program = { + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; ++ ++program = { ++ name = grub-set-bootflag; ++ installdir = sbin; ++ mansection = 1; ++ common = util/grub-set-bootflag.c; ++}; +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +new file mode 100644 +index 0000000000..d506f7e75b +--- /dev/null ++++ b/util/grub-set-bootflag.c +@@ -0,0 +1,172 @@ ++/* grub-set-bootflag.c - tool to set boot-flags in the grubenv. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2018 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 . ++ */ ++ ++/* ++ * NOTE this gets run by users as root (through pkexec), so this does not ++ * use any grub library / util functions to allow for easy auditing. ++ * The grub headers are only included to get certain defines. ++ */ ++ ++#include /* For *_DIR_NAME defines */ ++#include ++#include /* For GRUB_ENVBLK_DEFCFG define */ ++#include ++#include ++#include ++#include ++ ++#include "progname.h" ++ ++#define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG ++#define GRUBENV_SIZE 1024 ++ ++const char *bootflags[] = { ++ "boot_success", ++ "menu_show_once", ++ NULL ++}; ++ ++static void usage(FILE *out) ++{ ++ int i; ++ ++ fprintf (out, "Usage: 'grub-set-bootflag ', where is one of:\n"); ++ for (i = 0; bootflags[i]; i++) ++ fprintf (out, " %s\n", bootflags[i]); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ /* NOTE buf must be at least the longest bootflag length + 4 bytes */ ++ char env[GRUBENV_SIZE + 1], buf[64], *s; ++ const char *bootflag; ++ int i, len, ret; ++ FILE *f; ++ ++ if (argc != 2) ++ { ++ usage (stderr); ++ return 1; ++ } ++ else if (!strcmp (argv[1], "--help")) ++ { ++ usage (stdout); ++ return 0; ++ } ++ else if (!strcmp (argv[1], "--version")) ++ { ++ printf ("grub-set-bootflag (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); ++ return 0; ++ } ++ ++ for (i = 0; bootflags[i]; i++) ++ if (!strcmp (argv[1], bootflags[i])) ++ break; ++ if (!bootflags[i]) ++ { ++ fprintf (stderr, "Invalid bootflag: '%s'\n", argv[1]); ++ usage (stderr); ++ return 1; ++ } ++ ++ bootflag = bootflags[i]; ++ len = strlen (bootflag); ++ ++ f = fopen (GRUBENV, "r"); ++ if (!f) ++ { ++ perror ("Error opening " GRUBENV " for reading"); ++ return 1; ++ } ++ ++ ret = fread (env, 1, GRUBENV_SIZE, f); ++ fclose (f); ++ if (ret != GRUBENV_SIZE) ++ { ++ errno = EINVAL; ++ perror ("Error reading from " GRUBENV); ++ return 1; ++ } ++ ++ /* 0 terminate env */ ++ env[GRUBENV_SIZE] = 0; ++ ++ if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE))) ++ { ++ fprintf (stderr, "Error invalid environment block\n"); ++ return 1; ++ } ++ ++ /* Find a pre-existing definition of the bootflag */ ++ s = strstr (env, bootflag); ++ while (s && s[len] != '=') ++ s = strstr (s + len, bootflag); ++ ++ if (s && ((s[len + 1] != '0' && s[len + 1] != '1') || s[len + 2] != '\n')) ++ { ++ fprintf (stderr, "Pre-existing bootflag '%s' has unexpected value\n", bootflag); ++ return 1; ++ } ++ ++ /* No pre-existing bootflag? -> find free space */ ++ if (!s) ++ { ++ for (i = 0; i < (len + 3); i++) ++ buf[i] = '#'; ++ buf[i] = 0; ++ s = strstr (env, buf); ++ } ++ ++ if (!s) ++ { ++ fprintf (stderr, "No space in grubenv to store bootflag '%s'\n", bootflag); ++ return 1; ++ } ++ ++ /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */ ++ snprintf(buf, sizeof(buf), "%s=1\n", bootflag); ++ memcpy(s, buf, len + 3); ++ ++ /* "r+", don't truncate so that the diskspace stays reserved */ ++ f = fopen (GRUBENV, "r+"); ++ if (!f) ++ { ++ perror ("Error opening " GRUBENV " for writing"); ++ return 1; ++ } ++ ++ ret = fwrite (env, 1, GRUBENV_SIZE, f); ++ if (ret != GRUBENV_SIZE) ++ { ++ perror ("Error writing to " GRUBENV); ++ return 1; ++ } ++ ++ ret = fflush (f); ++ if (ret) ++ { ++ perror ("Error flushing " GRUBENV); ++ return 1; ++ } ++ ++ fsync (fileno (f)); ++ fclose (f); ++ ++ return 0; ++} +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 8f1485d52a..ad235de7fc 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -15,6 +15,9 @@ EXTRA_DIST += docs/man + EXTRA_DIST += docs/autoiso.cfg + EXTRA_DIST += docs/grub.cfg + EXTRA_DIST += docs/osdetect.cfg ++EXTRA_DIST += docs/org.gnu.grub.policy ++EXTRA_DIST += docs/grub-boot-success.service ++EXTRA_DIST += docs/grub-boot-success.timer + + EXTRA_DIST += conf/i386-cygwin-img-ld.sc + +diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service +new file mode 100644 +index 0000000000..80e79584c9 +--- /dev/null ++++ b/docs/grub-boot-success.service +@@ -0,0 +1,6 @@ ++[Unit] ++Description=Mark boot as successful ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/sbin/grub2-set-bootflag boot_success +diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer +new file mode 100644 +index 0000000000..406f172005 +--- /dev/null ++++ b/docs/grub-boot-success.timer +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Mark boot as successful after the user session has run 2 minutes ++ConditionUser=!@system ++ConditionVirtualization=!container ++ ++[Timer] ++OnActiveSec=2min +diff --git a/docs/man/grub-set-bootflag.h2m b/docs/man/grub-set-bootflag.h2m +new file mode 100644 +index 0000000000..94ec0b92ed +--- /dev/null ++++ b/docs/man/grub-set-bootflag.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-set-bootflag \- set a bootflag in the GRUB environment block diff --git a/0084-Add-grub-set-bootflag-utility.patch b/0084-Add-grub-set-bootflag-utility.patch deleted file mode 100644 index 4ee43cf..0000000 --- a/0084-Add-grub-set-bootflag-utility.patch +++ /dev/null @@ -1,290 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 12 Jun 2018 13:25:16 +0200 -Subject: [PATCH] Add grub-set-bootflag utility - -This commit adds a new grub-set-bootflag utility, which can be used -to set known bootflags in the grubenv: boot_success or menu_show_once. - -grub-set-bootflag is different from grub-editenv in 2 ways: - -1) It is intended to be executed by regular users so must be installed -as suid root. As such it is written to not use any existing grubenv -related code for easy auditing. - -It can't be executed through pkexec because we want to call it under gdm -and pkexec does not work under gdm due the gdm user having /sbin/nologin -as shell. - -2) Since it can be executed by regular users it only allows setting -(assigning a value of 1 to) bootflags which it knows about. Currently -those are just boot_success and menu_show_once. - -This commit also adds a couple of example systemd and files which show -how this can be used to set boot_success from a user-session: - -docs/grub-boot-success.service -docs/grub-boot-success.timer - -The 2 grub-boot-success.systemd files should be placed in /lib/systemd/user -and a symlink to grub-boot-success.timer should be added to -/lib/systemd/user/timers.target.wants. - -Signed-off-by: Hans de Goede -[makhomed: grub-boot-success.timer: Only run if not in a container] -Signed-off-by: Gena Makhomed -[rharwood: migrate to h2m] -Signed-off-by: Robbie Harwood ---- - Makefile.util.def | 7 ++ - util/grub-set-bootflag.c | 172 +++++++++++++++++++++++++++++++++++++++++ - conf/Makefile.extra-dist | 3 + - docs/grub-boot-success.service | 6 ++ - docs/grub-boot-success.timer | 7 ++ - docs/man/grub-set-bootflag.h2m | 2 + - 6 files changed, 197 insertions(+) - create mode 100644 util/grub-set-bootflag.c - create mode 100644 docs/grub-boot-success.service - create mode 100644 docs/grub-boot-success.timer - create mode 100644 docs/man/grub-set-bootflag.h2m - -diff --git a/Makefile.util.def b/Makefile.util.def -index 314e6f2acf..0b85a7fce4 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -1446,3 +1446,10 @@ program = { - ldadd = grub-core/lib/gnulib/libgnu.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; - }; -+ -+program = { -+ name = grub-set-bootflag; -+ installdir = sbin; -+ mansection = 1; -+ common = util/grub-set-bootflag.c; -+}; -diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c -new file mode 100644 -index 0000000000..d506f7e75b ---- /dev/null -+++ b/util/grub-set-bootflag.c -@@ -0,0 +1,172 @@ -+/* grub-set-bootflag.c - tool to set boot-flags in the grubenv. */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2018 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 . -+ */ -+ -+/* -+ * NOTE this gets run by users as root (through pkexec), so this does not -+ * use any grub library / util functions to allow for easy auditing. -+ * The grub headers are only included to get certain defines. -+ */ -+ -+#include /* For *_DIR_NAME defines */ -+#include -+#include /* For GRUB_ENVBLK_DEFCFG define */ -+#include -+#include -+#include -+#include -+ -+#include "progname.h" -+ -+#define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG -+#define GRUBENV_SIZE 1024 -+ -+const char *bootflags[] = { -+ "boot_success", -+ "menu_show_once", -+ NULL -+}; -+ -+static void usage(FILE *out) -+{ -+ int i; -+ -+ fprintf (out, "Usage: 'grub-set-bootflag ', where is one of:\n"); -+ for (i = 0; bootflags[i]; i++) -+ fprintf (out, " %s\n", bootflags[i]); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ /* NOTE buf must be at least the longest bootflag length + 4 bytes */ -+ char env[GRUBENV_SIZE + 1], buf[64], *s; -+ const char *bootflag; -+ int i, len, ret; -+ FILE *f; -+ -+ if (argc != 2) -+ { -+ usage (stderr); -+ return 1; -+ } -+ else if (!strcmp (argv[1], "--help")) -+ { -+ usage (stdout); -+ return 0; -+ } -+ else if (!strcmp (argv[1], "--version")) -+ { -+ printf ("grub-set-bootflag (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); -+ return 0; -+ } -+ -+ for (i = 0; bootflags[i]; i++) -+ if (!strcmp (argv[1], bootflags[i])) -+ break; -+ if (!bootflags[i]) -+ { -+ fprintf (stderr, "Invalid bootflag: '%s'\n", argv[1]); -+ usage (stderr); -+ return 1; -+ } -+ -+ bootflag = bootflags[i]; -+ len = strlen (bootflag); -+ -+ f = fopen (GRUBENV, "r"); -+ if (!f) -+ { -+ perror ("Error opening " GRUBENV " for reading"); -+ return 1; -+ } -+ -+ ret = fread (env, 1, GRUBENV_SIZE, f); -+ fclose (f); -+ if (ret != GRUBENV_SIZE) -+ { -+ errno = EINVAL; -+ perror ("Error reading from " GRUBENV); -+ return 1; -+ } -+ -+ /* 0 terminate env */ -+ env[GRUBENV_SIZE] = 0; -+ -+ if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE))) -+ { -+ fprintf (stderr, "Error invalid environment block\n"); -+ return 1; -+ } -+ -+ /* Find a pre-existing definition of the bootflag */ -+ s = strstr (env, bootflag); -+ while (s && s[len] != '=') -+ s = strstr (s + len, bootflag); -+ -+ if (s && ((s[len + 1] != '0' && s[len + 1] != '1') || s[len + 2] != '\n')) -+ { -+ fprintf (stderr, "Pre-existing bootflag '%s' has unexpected value\n", bootflag); -+ return 1; -+ } -+ -+ /* No pre-existing bootflag? -> find free space */ -+ if (!s) -+ { -+ for (i = 0; i < (len + 3); i++) -+ buf[i] = '#'; -+ buf[i] = 0; -+ s = strstr (env, buf); -+ } -+ -+ if (!s) -+ { -+ fprintf (stderr, "No space in grubenv to store bootflag '%s'\n", bootflag); -+ return 1; -+ } -+ -+ /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */ -+ snprintf(buf, sizeof(buf), "%s=1\n", bootflag); -+ memcpy(s, buf, len + 3); -+ -+ /* "r+", don't truncate so that the diskspace stays reserved */ -+ f = fopen (GRUBENV, "r+"); -+ if (!f) -+ { -+ perror ("Error opening " GRUBENV " for writing"); -+ return 1; -+ } -+ -+ ret = fwrite (env, 1, GRUBENV_SIZE, f); -+ if (ret != GRUBENV_SIZE) -+ { -+ perror ("Error writing to " GRUBENV); -+ return 1; -+ } -+ -+ ret = fflush (f); -+ if (ret) -+ { -+ perror ("Error flushing " GRUBENV); -+ return 1; -+ } -+ -+ fsync (fileno (f)); -+ fclose (f); -+ -+ return 0; -+} -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index 8f1485d52a..ad235de7fc 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -15,6 +15,9 @@ EXTRA_DIST += docs/man - EXTRA_DIST += docs/autoiso.cfg - EXTRA_DIST += docs/grub.cfg - EXTRA_DIST += docs/osdetect.cfg -+EXTRA_DIST += docs/org.gnu.grub.policy -+EXTRA_DIST += docs/grub-boot-success.service -+EXTRA_DIST += docs/grub-boot-success.timer - - EXTRA_DIST += conf/i386-cygwin-img-ld.sc - -diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service -new file mode 100644 -index 0000000000..80e79584c9 ---- /dev/null -+++ b/docs/grub-boot-success.service -@@ -0,0 +1,6 @@ -+[Unit] -+Description=Mark boot as successful -+ -+[Service] -+Type=oneshot -+ExecStart=/usr/sbin/grub2-set-bootflag boot_success -diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer -new file mode 100644 -index 0000000000..406f172005 ---- /dev/null -+++ b/docs/grub-boot-success.timer -@@ -0,0 +1,7 @@ -+[Unit] -+Description=Mark boot as successful after the user session has run 2 minutes -+ConditionUser=!@system -+ConditionVirtualization=!container -+ -+[Timer] -+OnActiveSec=2min -diff --git a/docs/man/grub-set-bootflag.h2m b/docs/man/grub-set-bootflag.h2m -new file mode 100644 -index 0000000000..94ec0b92ed ---- /dev/null -+++ b/docs/man/grub-set-bootflag.h2m -@@ -0,0 +1,2 @@ -+[NAME] -+grub-set-bootflag \- set a bootflag in the GRUB environment block diff --git a/0084-docs-Add-grub-boot-indeterminate.service-example.patch b/0084-docs-Add-grub-boot-indeterminate.service-example.patch new file mode 100644 index 0000000..96eff36 --- /dev/null +++ b/0084-docs-Add-grub-boot-indeterminate.service-example.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 19 Jun 2018 15:20:54 +0200 +Subject: [PATCH] docs: Add grub-boot-indeterminate.service example + +This is an example service file, for use from +/lib/systemd/system/system-update.target.wants +to increment the boot_indeterminate variable when +doing offline updates. + +Signed-off-by: Hans de Goede +--- + docs/grub-boot-indeterminate.service | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 docs/grub-boot-indeterminate.service + +diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service +new file mode 100644 +index 0000000000..6c8dcb186b +--- /dev/null ++++ b/docs/grub-boot-indeterminate.service +@@ -0,0 +1,11 @@ ++[Unit] ++Description=Mark boot as indeterminate ++DefaultDependencies=false ++Requires=sysinit.target ++After=sysinit.target ++Wants=system-update-pre.target ++Before=system-update-pre.target ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate diff --git a/0085-docs-Add-grub-boot-indeterminate.service-example.patch b/0085-docs-Add-grub-boot-indeterminate.service-example.patch deleted file mode 100644 index 96eff36..0000000 --- a/0085-docs-Add-grub-boot-indeterminate.service-example.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 19 Jun 2018 15:20:54 +0200 -Subject: [PATCH] docs: Add grub-boot-indeterminate.service example - -This is an example service file, for use from -/lib/systemd/system/system-update.target.wants -to increment the boot_indeterminate variable when -doing offline updates. - -Signed-off-by: Hans de Goede ---- - docs/grub-boot-indeterminate.service | 11 +++++++++++ - 1 file changed, 11 insertions(+) - create mode 100644 docs/grub-boot-indeterminate.service - -diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service -new file mode 100644 -index 0000000000..6c8dcb186b ---- /dev/null -+++ b/docs/grub-boot-indeterminate.service -@@ -0,0 +1,11 @@ -+[Unit] -+Description=Mark boot as indeterminate -+DefaultDependencies=false -+Requires=sysinit.target -+After=sysinit.target -+Wants=system-update-pre.target -+Before=system-update-pre.target -+ -+[Service] -+Type=oneshot -+ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate diff --git a/0085-gentpl-add-disable-support.patch b/0085-gentpl-add-disable-support.patch new file mode 100644 index 0000000..3b305e6 --- /dev/null +++ b/0085-gentpl-add-disable-support.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 11 Jul 2018 13:43:15 -0400 +Subject: [PATCH] gentpl: add 'disable = ' support + +Signed-off-by: Peter Jones +--- + gentpl.py | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/gentpl.py b/gentpl.py +index c86550d4f9..f3c5f84f85 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -592,11 +592,21 @@ def platform_conditional(platform, closure): + # }; + # + def foreach_enabled_platform(defn, closure): ++ enabled = False ++ disabled = False + if 'enable' in defn: ++ enabled = True + for platform in GRUB_PLATFORMS: + if platform_tagged(defn, platform, "enable"): + platform_conditional(platform, closure) +- else: ++ ++ if 'disable' in defn: ++ disabled = True ++ for platform in GRUB_PLATFORMS: ++ if not platform_tagged(defn, platform, "disable"): ++ platform_conditional(platform, closure) ++ ++ if not enabled and not disabled: + for platform in GRUB_PLATFORMS: + platform_conditional(platform, closure) + +@@ -655,6 +665,8 @@ def first_time(defn, snippet): + def is_platform_independent(defn): + if 'enable' in defn: + return False ++ if 'disable' in defn: ++ return False + for suffix in [ "", "_nodist" ]: + template = platform_values(defn, GRUB_PLATFORMS[0], suffix) + for platform in GRUB_PLATFORMS[1:]: diff --git a/0086-gentpl-add-disable-support.patch b/0086-gentpl-add-disable-support.patch deleted file mode 100644 index 3b305e6..0000000 --- a/0086-gentpl-add-disable-support.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 11 Jul 2018 13:43:15 -0400 -Subject: [PATCH] gentpl: add 'disable = ' support - -Signed-off-by: Peter Jones ---- - gentpl.py | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/gentpl.py b/gentpl.py -index c86550d4f9..f3c5f84f85 100644 ---- a/gentpl.py -+++ b/gentpl.py -@@ -592,11 +592,21 @@ def platform_conditional(platform, closure): - # }; - # - def foreach_enabled_platform(defn, closure): -+ enabled = False -+ disabled = False - if 'enable' in defn: -+ enabled = True - for platform in GRUB_PLATFORMS: - if platform_tagged(defn, platform, "enable"): - platform_conditional(platform, closure) -- else: -+ -+ if 'disable' in defn: -+ disabled = True -+ for platform in GRUB_PLATFORMS: -+ if not platform_tagged(defn, platform, "disable"): -+ platform_conditional(platform, closure) -+ -+ if not enabled and not disabled: - for platform in GRUB_PLATFORMS: - platform_conditional(platform, closure) - -@@ -655,6 +665,8 @@ def first_time(defn, snippet): - def is_platform_independent(defn): - if 'enable' in defn: - return False -+ if 'disable' in defn: -+ return False - for suffix in [ "", "_nodist" ]: - template = platform_values(defn, GRUB_PLATFORMS[0], suffix) - for platform in GRUB_PLATFORMS[1:]: diff --git a/0086-gentpl-add-pc-firmware-type.patch b/0086-gentpl-add-pc-firmware-type.patch new file mode 100644 index 0000000..0bfd2ea --- /dev/null +++ b/0086-gentpl-add-pc-firmware-type.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 11:04:24 +0200 +Subject: [PATCH] gentpl: add 'pc' firmware type + +Signed-off-by: Peter Jones +--- + gentpl.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gentpl.py b/gentpl.py +index f3c5f84f85..f09b336869 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -51,6 +51,7 @@ GROUPS["riscv32"] = [ "riscv32_efi" ] + GROUPS["riscv64"] = [ "riscv64_efi" ] + + # Groups based on firmware ++GROUPS["pc"] = [ "i386_pc" ] + GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", + "riscv32_efi", "riscv64_efi" ] + GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] diff --git a/0087-efinet-also-use-the-firmware-acceleration-for-http.patch b/0087-efinet-also-use-the-firmware-acceleration-for-http.patch new file mode 100644 index 0000000..a3a9400 --- /dev/null +++ b/0087-efinet-also-use-the-firmware-acceleration-for-http.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 30 Jul 2018 14:06:42 -0400 +Subject: [PATCH] efinet: also use the firmware acceleration for http + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/net.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 4bb308026c..6603cd83ed 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -1324,7 +1324,9 @@ grub_efi_net_boot_from_https (void) + && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + { + grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; +- return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; ++ grub_dprintf ("efinet", "url:%s\n", (const char *)uri_dp->uri); ++ return (grub_strncmp ((const char *)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0 || ++ grub_strncmp ((const char *)uri_dp->uri, "http://", sizeof ("http://") - 1) == 0); + } + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) diff --git a/0087-gentpl-add-pc-firmware-type.patch b/0087-gentpl-add-pc-firmware-type.patch deleted file mode 100644 index 0bfd2ea..0000000 --- a/0087-gentpl-add-pc-firmware-type.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 11 Jul 2019 11:04:24 +0200 -Subject: [PATCH] gentpl: add 'pc' firmware type - -Signed-off-by: Peter Jones ---- - gentpl.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/gentpl.py b/gentpl.py -index f3c5f84f85..f09b336869 100644 ---- a/gentpl.py -+++ b/gentpl.py -@@ -51,6 +51,7 @@ GROUPS["riscv32"] = [ "riscv32_efi" ] - GROUPS["riscv64"] = [ "riscv64_efi" ] - - # Groups based on firmware -+GROUPS["pc"] = [ "i386_pc" ] - GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", - "riscv32_efi", "riscv64_efi" ] - GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] diff --git a/0088-efi-http-Make-root_url-reflect-the-protocol-hostname.patch b/0088-efi-http-Make-root_url-reflect-the-protocol-hostname.patch new file mode 100644 index 0000000..90d9777 --- /dev/null +++ b/0088-efi-http-Make-root_url-reflect-the-protocol-hostname.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 30 Jul 2018 16:39:57 -0400 +Subject: [PATCH] efi/http: Make root_url reflect the protocol+hostname of our + boot url. + +This lets you write config files that don't know urls. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/http.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index 3f61fd2fa5..243acbaa35 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + static void + http_configure (struct grub_efi_net_device *dev, int prefer_ip6) +@@ -351,6 +352,24 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + grub_err_t err; + grub_off_t size; + char *buf; ++ char *root_url; ++ grub_efi_ipv6_address_t address; ++ const char *rest; ++ ++ if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0) ++ root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server); ++ else ++ root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server); ++ if (root_url) ++ { ++ grub_env_unset ("root_url"); ++ grub_env_set ("root_url", root_url); ++ grub_free (root_url); ++ } ++ else ++ { ++ return grub_errno; ++ } + + err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); + if (err != GRUB_ERR_NONE) diff --git a/0088-efinet-also-use-the-firmware-acceleration-for-http.patch b/0088-efinet-also-use-the-firmware-acceleration-for-http.patch deleted file mode 100644 index a3a9400..0000000 --- a/0088-efinet-also-use-the-firmware-acceleration-for-http.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 30 Jul 2018 14:06:42 -0400 -Subject: [PATCH] efinet: also use the firmware acceleration for http - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/net.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c -index 4bb308026c..6603cd83ed 100644 ---- a/grub-core/net/efi/net.c -+++ b/grub-core/net/efi/net.c -@@ -1324,7 +1324,9 @@ grub_efi_net_boot_from_https (void) - && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) - { - grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; -- return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; -+ grub_dprintf ("efinet", "url:%s\n", (const char *)uri_dp->uri); -+ return (grub_strncmp ((const char *)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0 || -+ grub_strncmp ((const char *)uri_dp->uri, "http://", sizeof ("http://") - 1) == 0); - } - - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) diff --git a/0089-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch b/0089-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch new file mode 100644 index 0000000..6d2974f --- /dev/null +++ b/0089-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch @@ -0,0 +1,149 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 26 Jun 2018 17:16:06 -0400 +Subject: [PATCH] Make it so we can tell configure which cflags utils are built + with + +This lets us have kernel.img be built with TARGET_CFLAGS but grub-mkimage and +friends built with HOST_CFLAGS. That in turn lets us build with an ARM compiler +that only has hard-float ABI versions of crt*.o and libgcc*, but still use soft +float for grub.efi. + +Signed-off-by: Peter Jones +--- + configure.ac | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- + conf/Makefile.common | 23 ++++++++++++----------- + gentpl.py | 8 ++++---- + 3 files changed, 64 insertions(+), 16 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 302300711f..008f6c273b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -849,11 +849,23 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p + TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow" + fi + ++# Should grub utils get the host CFLAGS, or the target CFLAGS? ++AC_ARG_WITH([utils], ++ AS_HELP_STRING([--with-utils=host|target|build], ++ [choose which flags to build utilities with. (default=target)]), ++ [have_with_utils=y], ++ [have_with_utils=n]) ++if test x"$have_with_utils" = xy ; then ++ with_utils="$withval" ++else ++ with_utils=target ++fi ++ + # GRUB doesn't use float or doubles at all. Yet some toolchains may decide + # that floats are a good fit to run instead of what's written in the code. + # Given that floating point unit is disabled (if present to begin with) + # when GRUB is running which may result in various hard crashes. +-if test x"$platform" != xemu ; then ++if test x"$platform" != xemu -a x"$with_utils" == xtarget ; then + AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [ + grub_cv_target_cc_soft_float=no + if test "x$target_cpu" = xarm64; then +@@ -1954,6 +1966,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include" + ++case "$with_utils" in ++ host) ++ UTILS_CFLAGS=$HOST_CFLAGS ++ UTILS_CPPFLAGS=$HOST_CPPFLAGS ++ UTILS_CCASFLAGS=$HOST_CCASFLAGS ++ UTILS_LDFLAGS=$HOST_LDFLAGS ++ ;; ++ target) ++ UTILS_CFLAGS=$TARGET_CFLAGS ++ UTILS_CPPFLAGS=$TARGET_CPPFLAGS ++ UTILS_CCASFLAGS=$TARGET_CCASFLAGS ++ UTILS_LDFLAGS=$TARGET_LDFLAGS ++ ;; ++ build) ++ UTILS_CFLAGS=$BUILD_CFLAGS ++ UTILS_CPPFLAGS=$BUILD_CPPFLAGS ++ UTILS_CCASFLAGS=$BUILD_CCASFLAGS ++ UTILS_LDFLAGS=$BUILD_LDFLAGS ++ ;; ++ *) ++ AC_MSG_ERROR([--with-utils must be either host, target, or build]) ++ ;; ++esac ++AC_MSG_NOTICE([Using $with_utils flags for utilities.]) ++ ++unset CFLAGS ++unset CPPFLAGS ++unset CCASFLAGS ++unset LDFLAGS ++ ++AC_SUBST(UTILS_CFLAGS) ++AC_SUBST(UTILS_CPPFLAGS) ++AC_SUBST(UTILS_CCASFLAGS) ++AC_SUBST(UTILS_LDFLAGS) ++ + GRUB_TARGET_CPU="${target_cpu}" + GRUB_PLATFORM="${platform}" + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 5f0ef96985..2ff9b39357 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -40,24 +40,25 @@ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 + CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes + +-CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding +-LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d +-CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) +-CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) ++CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding ++LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d ++CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) ++CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + + CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin + LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S + CPPFLAGS_IMAGE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) + CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + +-CFLAGS_PROGRAM = +-LDFLAGS_PROGRAM = +-CPPFLAGS_PROGRAM = +-CCASFLAGS_PROGRAM = ++CFLAGS_PROGRAM = $(UTILS_CFLAGS) ++LDFLAGS_PROGRAM = $(UTILS_LDFLAGS) ++CPPFLAGS_PROGRAM = $(UTILS_CPPFLAGS) ++CCASFLAGS_PROGRAM = $(UTILS_CCASFLAGS) + +-CFLAGS_LIBRARY = +-CPPFLAGS_LIBRARY = +-CCASFLAGS_LIBRARY = ++CFLAGS_LIBRARY = $(UTILS_CFLAGS) ++LDFLAGS_LIBRARY = $(UTILS_LDFLAGS) ++CPPFLAGS_LIBRARY = $(UTILS_CPPFLAGS) ++CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS) + + # Other variables + +diff --git a/gentpl.py b/gentpl.py +index f09b336869..0e62e14666 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -697,10 +697,10 @@ def module(defn, platform): + var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources") + var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources") + var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) +- var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform)) +- var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) +- var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) +- var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) ++ var_set(cname(defn) + "_CFLAGS", "$(CFLAGS_MODULE) " + platform_cflags(defn, platform)) ++ var_set(cname(defn) + "_LDFLAGS", "$(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) ++ var_set(cname(defn) + "_CPPFLAGS", "$(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) ++ var_set(cname(defn) + "_CCASFLAGS", "$(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) + var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform)) + + gvar_add("dist_noinst_DATA", extra_dist(defn)) diff --git a/0089-efi-http-Make-root_url-reflect-the-protocol-hostname.patch b/0089-efi-http-Make-root_url-reflect-the-protocol-hostname.patch deleted file mode 100644 index 90d9777..0000000 --- a/0089-efi-http-Make-root_url-reflect-the-protocol-hostname.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 30 Jul 2018 16:39:57 -0400 -Subject: [PATCH] efi/http: Make root_url reflect the protocol+hostname of our - boot url. - -This lets you write config files that don't know urls. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/http.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c -index 3f61fd2fa5..243acbaa35 100644 ---- a/grub-core/net/efi/http.c -+++ b/grub-core/net/efi/http.c -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - static void - http_configure (struct grub_efi_net_device *dev, int prefer_ip6) -@@ -351,6 +352,24 @@ grub_efihttp_open (struct grub_efi_net_device *dev, - grub_err_t err; - grub_off_t size; - char *buf; -+ char *root_url; -+ grub_efi_ipv6_address_t address; -+ const char *rest; -+ -+ if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0) -+ root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server); -+ else -+ root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server); -+ if (root_url) -+ { -+ grub_env_unset ("root_url"); -+ grub_env_set ("root_url", root_url); -+ grub_free (root_url); -+ } -+ else -+ { -+ return grub_errno; -+ } - - err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); - if (err != GRUB_ERR_NONE) diff --git a/0090-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch b/0090-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch deleted file mode 100644 index a2c7136..0000000 --- a/0090-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 26 Jun 2018 17:16:06 -0400 -Subject: [PATCH] Make it so we can tell configure which cflags utils are built - with - -This lets us have kernel.img be built with TARGET_CFLAGS but grub-mkimage and -friends built with HOST_CFLAGS. That in turn lets us build with an ARM compiler -that only has hard-float ABI versions of crt*.o and libgcc*, but still use soft -float for grub.efi. - -Signed-off-by: Peter Jones ---- - configure.ac | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- - conf/Makefile.common | 23 ++++++++++++----------- - gentpl.py | 8 ++++---- - 3 files changed, 64 insertions(+), 16 deletions(-) - -diff --git a/configure.ac b/configure.ac -index b809c00784..b1ca894791 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -850,11 +850,23 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p - TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow" - fi - -+# Should grub utils get the host CFLAGS, or the target CFLAGS? -+AC_ARG_WITH([utils], -+ AS_HELP_STRING([--with-utils=host|target|build], -+ [choose which flags to build utilities with. (default=target)]), -+ [have_with_utils=y], -+ [have_with_utils=n]) -+if test x"$have_with_utils" = xy ; then -+ with_utils="$withval" -+else -+ with_utils=target -+fi -+ - # GRUB doesn't use float or doubles at all. Yet some toolchains may decide - # that floats are a good fit to run instead of what's written in the code. - # Given that floating point unit is disabled (if present to begin with) - # when GRUB is running which may result in various hard crashes. --if test x"$platform" != xemu ; then -+if test x"$platform" != xemu -a x"$with_utils" == xtarget ; then - AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [ - grub_cv_target_cc_soft_float=no - if test "x$target_cpu" = xarm64; then -@@ -1984,6 +1996,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include" - TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include" - TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include" - -+case "$with_utils" in -+ host) -+ UTILS_CFLAGS=$HOST_CFLAGS -+ UTILS_CPPFLAGS=$HOST_CPPFLAGS -+ UTILS_CCASFLAGS=$HOST_CCASFLAGS -+ UTILS_LDFLAGS=$HOST_LDFLAGS -+ ;; -+ target) -+ UTILS_CFLAGS=$TARGET_CFLAGS -+ UTILS_CPPFLAGS=$TARGET_CPPFLAGS -+ UTILS_CCASFLAGS=$TARGET_CCASFLAGS -+ UTILS_LDFLAGS=$TARGET_LDFLAGS -+ ;; -+ build) -+ UTILS_CFLAGS=$BUILD_CFLAGS -+ UTILS_CPPFLAGS=$BUILD_CPPFLAGS -+ UTILS_CCASFLAGS=$BUILD_CCASFLAGS -+ UTILS_LDFLAGS=$BUILD_LDFLAGS -+ ;; -+ *) -+ AC_MSG_ERROR([--with-utils must be either host, target, or build]) -+ ;; -+esac -+AC_MSG_NOTICE([Using $with_utils flags for utilities.]) -+ -+unset CFLAGS -+unset CPPFLAGS -+unset CCASFLAGS -+unset LDFLAGS -+ -+AC_SUBST(UTILS_CFLAGS) -+AC_SUBST(UTILS_CPPFLAGS) -+AC_SUBST(UTILS_CCASFLAGS) -+AC_SUBST(UTILS_LDFLAGS) -+ - GRUB_TARGET_CPU="${target_cpu}" - GRUB_PLATFORM="${platform}" - -diff --git a/conf/Makefile.common b/conf/Makefile.common -index 5f0ef96985..2ff9b39357 100644 ---- a/conf/Makefile.common -+++ b/conf/Makefile.common -@@ -40,24 +40,25 @@ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 - CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) - STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes - --CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding --LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d --CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) --CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) -+CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding -+LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d -+CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -+CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) - - CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin - LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S - CPPFLAGS_IMAGE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) - CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) - --CFLAGS_PROGRAM = --LDFLAGS_PROGRAM = --CPPFLAGS_PROGRAM = --CCASFLAGS_PROGRAM = -+CFLAGS_PROGRAM = $(UTILS_CFLAGS) -+LDFLAGS_PROGRAM = $(UTILS_LDFLAGS) -+CPPFLAGS_PROGRAM = $(UTILS_CPPFLAGS) -+CCASFLAGS_PROGRAM = $(UTILS_CCASFLAGS) - --CFLAGS_LIBRARY = --CPPFLAGS_LIBRARY = --CCASFLAGS_LIBRARY = -+CFLAGS_LIBRARY = $(UTILS_CFLAGS) -+LDFLAGS_LIBRARY = $(UTILS_LDFLAGS) -+CPPFLAGS_LIBRARY = $(UTILS_CPPFLAGS) -+CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS) - - # Other variables - -diff --git a/gentpl.py b/gentpl.py -index f09b336869..0e62e14666 100644 ---- a/gentpl.py -+++ b/gentpl.py -@@ -697,10 +697,10 @@ def module(defn, platform): - var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources") - var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources") - var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) -- var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform)) -- var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) -- var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) -- var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) -+ var_set(cname(defn) + "_CFLAGS", "$(CFLAGS_MODULE) " + platform_cflags(defn, platform)) -+ var_set(cname(defn) + "_LDFLAGS", "$(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) -+ var_set(cname(defn) + "_CPPFLAGS", "$(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) -+ var_set(cname(defn) + "_CCASFLAGS", "$(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) - var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform)) - - gvar_add("dist_noinst_DATA", extra_dist(defn)) diff --git a/0090-module-verifier-make-it-possible-to-run-checkers-on-.patch b/0090-module-verifier-make-it-possible-to-run-checkers-on-.patch new file mode 100644 index 0000000..78c15d6 --- /dev/null +++ b/0090-module-verifier-make-it-possible-to-run-checkers-on-.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 1 Aug 2018 10:24:52 -0400 +Subject: [PATCH] module-verifier: make it possible to run checkers on + grub-module-verifierxx.c + +This makes it so you can treat grub-module-verifierxx.c as a file you can +build directly, so syntax checkers like vim's "syntastic" plugin, which uses +"gcc -x c -fsyntax-only" to build it, will work. + +One still has to do whatever setup is required to make it pick the right +include dirs, which -W options we use, etc., but this makes it so you can do +the checking on the file you're editing, rather than on a different file. + +v2: fix the typo in the #else clause in util/grub-module-verifierXX.c + +Signed-off-by: Peter Jones +--- + util/grub-module-verifier32.c | 2 ++ + util/grub-module-verifier64.c | 2 ++ + util/grub-module-verifierXX.c | 9 +++++++++ + 3 files changed, 13 insertions(+) + +diff --git a/util/grub-module-verifier32.c b/util/grub-module-verifier32.c +index 257229f8f0..ba7d41aafe 100644 +--- a/util/grub-module-verifier32.c ++++ b/util/grub-module-verifier32.c +@@ -1,2 +1,4 @@ + #define MODULEVERIFIER_ELF32 1 ++#ifndef GRUB_MODULE_VERIFIERXX + #include "grub-module-verifierXX.c" ++#endif +diff --git a/util/grub-module-verifier64.c b/util/grub-module-verifier64.c +index 4db6b4bedd..fc23ef800b 100644 +--- a/util/grub-module-verifier64.c ++++ b/util/grub-module-verifier64.c +@@ -1,2 +1,4 @@ + #define MODULEVERIFIER_ELF64 1 ++#ifndef GRUB_MODULE_VERIFIERXX + #include "grub-module-verifierXX.c" ++#endif +diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c +index ceb24309ae..a98e2f9b1a 100644 +--- a/util/grub-module-verifierXX.c ++++ b/util/grub-module-verifierXX.c +@@ -1,3 +1,12 @@ ++#define GRUB_MODULE_VERIFIERXX ++#if !defined(MODULEVERIFIER_ELF32) && !defined(MODULEVERIFIER_ELF64) ++#if __SIZEOF_POINTER__ == 8 ++#include "grub-module-verifier64.c" ++#else ++#include "grub-module-verifier32.c" ++#endif ++#endif ++ + #include + + #include diff --git a/0091-Rework-how-the-fdt-command-builds.patch b/0091-Rework-how-the-fdt-command-builds.patch new file mode 100644 index 0000000..a374f90 --- /dev/null +++ b/0091-Rework-how-the-fdt-command-builds.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 13:01:41 +0200 +Subject: [PATCH] Rework how the fdt command builds. + +Trying to avoid all variants of: +cat syminfo.lst | sort | gawk -f ../../grub-core/genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1) +grub_fdt_install in linux is not defined +grub_fdt_load in linux is not defined +grub_fdt_unload in linux is not defined +grub_fdt_install in xen_boot is not defined +grub_fdt_load in xen_boot is not defined +grub_fdt_unload in xen_boot is not defined + +Signed-off-by: Peter Jones +[javierm: Fix build with platform emu, aarch64, and risc-v] +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 5 ++--- + grub-core/lib/fdt.c | 2 -- + grub-core/loader/efi/fdt.c | 2 ++ + include/grub/fdt.h | 6 ++++++ + grub-core/Makefile.am | 1 + + 5 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index c40170f2dd..84a3d89de9 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -177,7 +177,6 @@ kernel = { + arm_coreboot = kern/arm/coreboot/init.c; + arm_coreboot = kern/arm/coreboot/timer.c; + arm_coreboot = kern/arm/coreboot/coreboot.S; +- arm_coreboot = lib/fdt.c; + arm_coreboot = bus/fdt.c; + arm_coreboot = term/ps2.c; + arm_coreboot = term/arm/pl050.c; +@@ -351,6 +350,8 @@ kernel = { + riscv64 = kern/riscv/cache_flush.S; + riscv64 = kern/riscv/dl.c; + ++ fdt = lib/fdt.c; ++ + emu = disk/host.c; + emu = kern/emu/cache_s.S; + emu = kern/emu/hostdisk.c; +@@ -1825,7 +1826,6 @@ module = { + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; +- fdt = lib/fdt.c; + + common = loader/linux.c; + common = lib/cmdline.c; +@@ -1836,7 +1836,6 @@ module = { + module = { + name = fdt; + efi = loader/efi/fdt.c; +- common = lib/fdt.c; + enable = fdt; + }; + +diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c +index 0d371c5633..37e04bd69e 100644 +--- a/grub-core/lib/fdt.c ++++ b/grub-core/lib/fdt.c +@@ -21,8 +21,6 @@ + #include + #include + +-GRUB_MOD_LICENSE ("GPLv3+"); +- + #define FDT_SUPPORTED_VERSION 17 + + #define FDT_BEGIN_NODE 0x00000001 +diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c +index c86f283d75..c572415d38 100644 +--- a/grub-core/loader/efi/fdt.c ++++ b/grub-core/loader/efi/fdt.c +@@ -27,6 +27,8 @@ + #include + #include + ++GRUB_MOD_LICENSE ("GPLv3+"); ++ + static void *loaded_fdt; + static void *fdt; + +diff --git a/include/grub/fdt.h b/include/grub/fdt.h +index e609c7e411..3514aa4a5b 100644 +--- a/include/grub/fdt.h ++++ b/include/grub/fdt.h +@@ -19,6 +19,9 @@ + #ifndef GRUB_FDT_HEADER + #define GRUB_FDT_HEADER 1 + ++#if !defined(GRUB_MACHINE_EMU) && \ ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) ++ + #include + #include + +@@ -144,4 +147,7 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch + grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16); \ + }) + ++#endif /* !defined(GRUB_MACHINE_EMU) && \ ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */ ++ + #endif /* ! GRUB_FDT_HEADER */ +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index f512573c0d..dd49939aaa 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -76,6 +76,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h diff --git a/0091-module-verifier-make-it-possible-to-run-checkers-on-.patch b/0091-module-verifier-make-it-possible-to-run-checkers-on-.patch deleted file mode 100644 index 78c15d6..0000000 --- a/0091-module-verifier-make-it-possible-to-run-checkers-on-.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 1 Aug 2018 10:24:52 -0400 -Subject: [PATCH] module-verifier: make it possible to run checkers on - grub-module-verifierxx.c - -This makes it so you can treat grub-module-verifierxx.c as a file you can -build directly, so syntax checkers like vim's "syntastic" plugin, which uses -"gcc -x c -fsyntax-only" to build it, will work. - -One still has to do whatever setup is required to make it pick the right -include dirs, which -W options we use, etc., but this makes it so you can do -the checking on the file you're editing, rather than on a different file. - -v2: fix the typo in the #else clause in util/grub-module-verifierXX.c - -Signed-off-by: Peter Jones ---- - util/grub-module-verifier32.c | 2 ++ - util/grub-module-verifier64.c | 2 ++ - util/grub-module-verifierXX.c | 9 +++++++++ - 3 files changed, 13 insertions(+) - -diff --git a/util/grub-module-verifier32.c b/util/grub-module-verifier32.c -index 257229f8f0..ba7d41aafe 100644 ---- a/util/grub-module-verifier32.c -+++ b/util/grub-module-verifier32.c -@@ -1,2 +1,4 @@ - #define MODULEVERIFIER_ELF32 1 -+#ifndef GRUB_MODULE_VERIFIERXX - #include "grub-module-verifierXX.c" -+#endif -diff --git a/util/grub-module-verifier64.c b/util/grub-module-verifier64.c -index 4db6b4bedd..fc23ef800b 100644 ---- a/util/grub-module-verifier64.c -+++ b/util/grub-module-verifier64.c -@@ -1,2 +1,4 @@ - #define MODULEVERIFIER_ELF64 1 -+#ifndef GRUB_MODULE_VERIFIERXX - #include "grub-module-verifierXX.c" -+#endif -diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c -index ceb24309ae..a98e2f9b1a 100644 ---- a/util/grub-module-verifierXX.c -+++ b/util/grub-module-verifierXX.c -@@ -1,3 +1,12 @@ -+#define GRUB_MODULE_VERIFIERXX -+#if !defined(MODULEVERIFIER_ELF32) && !defined(MODULEVERIFIER_ELF64) -+#if __SIZEOF_POINTER__ == 8 -+#include "grub-module-verifier64.c" -+#else -+#include "grub-module-verifier32.c" -+#endif -+#endif -+ - #include - - #include diff --git a/0092-Disable-non-wordsize-allocations-on-arm.patch b/0092-Disable-non-wordsize-allocations-on-arm.patch new file mode 100644 index 0000000..ea09b65 --- /dev/null +++ b/0092-Disable-non-wordsize-allocations-on-arm.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 2 Aug 2018 10:56:38 -0400 +Subject: [PATCH] Disable non-wordsize allocations on arm + +Signed-off-by: Peter Jones +--- + configure.ac | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 008f6c273b..54462e0892 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1260,6 +1260,26 @@ if test "x$target_cpu" = xarm; then + done + ]) + ++ AC_CACHE_CHECK([for options to disable movt and movw relocations], ++ grub_cv_target_cc_mword_relocations, ++ [grub_cv_target_cc_mword_relocations=no ++ for cand in "-mword-relocations" ; do ++ if test x"$grub_cv_target_cc_mword_relocations" != xno ; then ++ break ++ fi ++ CFLAGS="$TARGET_CFLAGS $cand -Werror" ++ CPPFLAGS="$TARGET_CPPFLAGS" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_target_cc_mword_relocations="$cand"], ++ []) ++ done ++ ]) ++ if test x"$grub_cv_target_cc_mword_relocations" = xno ; then ++ AC_MSG_ERROR(["your compiler doesn't support disabling movw/movt relocations"]) ++ else ++ TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mword_relocations" ++ fi ++ + if test x"$grub_cv_target_cc_mno_movt" != xno ; then + # A trick so that clang doesn't see it on link stage + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt" diff --git a/0092-Rework-how-the-fdt-command-builds.patch b/0092-Rework-how-the-fdt-command-builds.patch deleted file mode 100644 index a374f90..0000000 --- a/0092-Rework-how-the-fdt-command-builds.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 11 Jul 2019 13:01:41 +0200 -Subject: [PATCH] Rework how the fdt command builds. - -Trying to avoid all variants of: -cat syminfo.lst | sort | gawk -f ../../grub-core/genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1) -grub_fdt_install in linux is not defined -grub_fdt_load in linux is not defined -grub_fdt_unload in linux is not defined -grub_fdt_install in xen_boot is not defined -grub_fdt_load in xen_boot is not defined -grub_fdt_unload in xen_boot is not defined - -Signed-off-by: Peter Jones -[javierm: Fix build with platform emu, aarch64, and risc-v] -Signed-off-by: Javier Martinez Canillas -Signed-off-by: Robbie Harwood ---- - grub-core/Makefile.core.def | 5 ++--- - grub-core/lib/fdt.c | 2 -- - grub-core/loader/efi/fdt.c | 2 ++ - include/grub/fdt.h | 6 ++++++ - grub-core/Makefile.am | 1 + - 5 files changed, 11 insertions(+), 5 deletions(-) - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index c40170f2dd..84a3d89de9 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -177,7 +177,6 @@ kernel = { - arm_coreboot = kern/arm/coreboot/init.c; - arm_coreboot = kern/arm/coreboot/timer.c; - arm_coreboot = kern/arm/coreboot/coreboot.S; -- arm_coreboot = lib/fdt.c; - arm_coreboot = bus/fdt.c; - arm_coreboot = term/ps2.c; - arm_coreboot = term/arm/pl050.c; -@@ -351,6 +350,8 @@ kernel = { - riscv64 = kern/riscv/cache_flush.S; - riscv64 = kern/riscv/dl.c; - -+ fdt = lib/fdt.c; -+ - emu = disk/host.c; - emu = kern/emu/cache_s.S; - emu = kern/emu/hostdisk.c; -@@ -1825,7 +1826,6 @@ module = { - riscv32 = loader/riscv/linux.c; - riscv64 = loader/riscv/linux.c; - emu = loader/emu/linux.c; -- fdt = lib/fdt.c; - - common = loader/linux.c; - common = lib/cmdline.c; -@@ -1836,7 +1836,6 @@ module = { - module = { - name = fdt; - efi = loader/efi/fdt.c; -- common = lib/fdt.c; - enable = fdt; - }; - -diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c -index 0d371c5633..37e04bd69e 100644 ---- a/grub-core/lib/fdt.c -+++ b/grub-core/lib/fdt.c -@@ -21,8 +21,6 @@ - #include - #include - --GRUB_MOD_LICENSE ("GPLv3+"); -- - #define FDT_SUPPORTED_VERSION 17 - - #define FDT_BEGIN_NODE 0x00000001 -diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c -index c86f283d75..c572415d38 100644 ---- a/grub-core/loader/efi/fdt.c -+++ b/grub-core/loader/efi/fdt.c -@@ -27,6 +27,8 @@ - #include - #include - -+GRUB_MOD_LICENSE ("GPLv3+"); -+ - static void *loaded_fdt; - static void *fdt; - -diff --git a/include/grub/fdt.h b/include/grub/fdt.h -index e609c7e411..3514aa4a5b 100644 ---- a/include/grub/fdt.h -+++ b/include/grub/fdt.h -@@ -19,6 +19,9 @@ - #ifndef GRUB_FDT_HEADER - #define GRUB_FDT_HEADER 1 - -+#if !defined(GRUB_MACHINE_EMU) && \ -+ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) -+ - #include - #include - -@@ -144,4 +147,7 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch - grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16); \ - }) - -+#endif /* !defined(GRUB_MACHINE_EMU) && \ -+ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */ -+ - #endif /* ! GRUB_FDT_HEADER */ -diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am -index f512573c0d..dd49939aaa 100644 ---- a/grub-core/Makefile.am -+++ b/grub-core/Makefile.am -@@ -76,6 +76,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h -+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h diff --git a/0093-Disable-non-wordsize-allocations-on-arm.patch b/0093-Disable-non-wordsize-allocations-on-arm.patch deleted file mode 100644 index 7105c7c..0000000 --- a/0093-Disable-non-wordsize-allocations-on-arm.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 2 Aug 2018 10:56:38 -0400 -Subject: [PATCH] Disable non-wordsize allocations on arm - -Signed-off-by: Peter Jones ---- - configure.ac | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/configure.ac b/configure.ac -index b1ca894791..f42be65332 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1261,6 +1261,26 @@ if test "x$target_cpu" = xarm; then - done - ]) - -+ AC_CACHE_CHECK([for options to disable movt and movw relocations], -+ grub_cv_target_cc_mword_relocations, -+ [grub_cv_target_cc_mword_relocations=no -+ for cand in "-mword-relocations" ; do -+ if test x"$grub_cv_target_cc_mword_relocations" != xno ; then -+ break -+ fi -+ CFLAGS="$TARGET_CFLAGS $cand -Werror" -+ CPPFLAGS="$TARGET_CPPFLAGS" -+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], -+ [grub_cv_target_cc_mword_relocations="$cand"], -+ []) -+ done -+ ]) -+ if test x"$grub_cv_target_cc_mword_relocations" = xno ; then -+ AC_MSG_ERROR(["your compiler doesn't support disabling movw/movt relocations"]) -+ else -+ TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mword_relocations" -+ fi -+ - if test x"$grub_cv_target_cc_mno_movt" != xno ; then - # A trick so that clang doesn't see it on link stage - TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt" diff --git a/0093-Prepend-prefix-when-HTTP-path-is-relative.patch b/0093-Prepend-prefix-when-HTTP-path-is-relative.patch new file mode 100644 index 0000000..30d8075 --- /dev/null +++ b/0093-Prepend-prefix-when-HTTP-path-is-relative.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stephen Benjamin +Date: Thu, 16 Aug 2018 16:58:51 -0400 +Subject: [PATCH] Prepend prefix when HTTP path is relative + +This sets a couple of variables. With the url http://www.example.com/foo/bar : +http_path: /foo/bar +http_url: http://www.example.com/foo/bar + +Signed-off-by: Peter Jones +Signed-off-by: Stephen Benjamin +Signed-off-by: Robbie Harwood +--- + grub-core/kern/main.c | 10 +++++- + grub-core/net/efi/http.c | 82 ++++++++++++++++++++++++++++++++++++------------ + 2 files changed, 71 insertions(+), 21 deletions(-) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index d1de9fa687..1c540fc8c2 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -131,11 +131,19 @@ grub_set_prefix_and_root (void) + if (fwdevice && fwpath) + { + char *fw_path; ++ char separator[3] = ")"; + +- fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath); ++ grub_dprintf ("fw_path", "\n"); ++ grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath); ++ ++ if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/') ++ grub_strcpy(separator, ")/"); ++ ++ fw_path = grub_xasprintf ("(%s%s%s", fwdevice, separator, fwpath); + if (fw_path) + { + grub_env_set ("fw_path", fw_path); ++ grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path); + grub_free (fw_path); + } + } +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index 243acbaa35..de351b2cd0 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -9,10 +9,52 @@ + static void + http_configure (struct grub_efi_net_device *dev, int prefer_ip6) + { ++ grub_efi_ipv6_address_t address; + grub_efi_http_config_data_t http_config; + grub_efi_httpv4_access_point_t httpv4_node; + grub_efi_httpv6_access_point_t httpv6_node; + grub_efi_status_t status; ++ int https; ++ char *http_url; ++ const char *rest, *http_server, *http_path = NULL; ++ ++ http_server = grub_env_get ("root"); ++ https = (grub_strncmp (http_server, "https", 5) == 0) ? 1 : 0; ++ ++ /* extract http server + port */ ++ if (http_server) ++ { ++ http_server = grub_strchr (http_server, ','); ++ if (http_server) ++ http_server++; ++ } ++ ++ /* fw_path is like (http,192.168.1.1:8000)/httpboot, extract path part */ ++ http_path = grub_env_get ("fw_path"); ++ if (http_path) ++ { ++ http_path = grub_strchr (http_path, ')'); ++ if (http_path) ++ { ++ http_path++; ++ grub_env_unset ("http_path"); ++ grub_env_set ("http_path", http_path); ++ } ++ } ++ ++ if (http_server && http_path) ++ { ++ if (grub_efi_string_to_ip6_address (http_server, &address, &rest) && *rest == 0) ++ http_url = grub_xasprintf ("%s://[%s]%s", https ? "https" : "http", http_server, http_path); ++ else ++ http_url = grub_xasprintf ("%s://%s%s", https ? "https" : "http", http_server, http_path); ++ if (http_url) ++ { ++ grub_env_unset ("http_url"); ++ grub_env_set ("http_url", http_url); ++ grub_free (http_url); ++ } ++ } + + grub_efi_http_t *http = dev->http; + +@@ -352,32 +394,32 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + grub_err_t err; + grub_off_t size; + char *buf; +- char *root_url; +- grub_efi_ipv6_address_t address; +- const char *rest; ++ char *file_name = NULL; ++ const char *http_path; + +- if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0) +- root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server); +- else +- root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server); +- if (root_url) +- { +- grub_env_unset ("root_url"); +- grub_env_set ("root_url", root_url); +- grub_free (root_url); +- } +- else +- { ++ /* If path is relative, prepend http_path */ ++ http_path = grub_env_get ("http_path"); ++ if (http_path && file->device->net->name[0] != '/') { ++ file_name = grub_xasprintf ("%s/%s", http_path, file->device->net->name); ++ if (!file_name) + return grub_errno; +- } ++ } + +- err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); ++ err = efihttp_request (dev->http, file->device->net->server, ++ file_name ? file_name : file->device->net->name, type, 1, 0); + if (err != GRUB_ERR_NONE) +- return err; ++ { ++ grub_free (file_name); ++ return err; ++ } + +- err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); ++ err = efihttp_request (dev->http, file->device->net->server, ++ file_name ? file_name : file->device->net->name, type, 0, &size); ++ grub_free (file_name); + if (err != GRUB_ERR_NONE) +- return err; ++ { ++ return err; ++ } + + buf = grub_malloc (size); + efihttp_read (dev, buf, size); diff --git a/0094-Make-grub_error-more-verbose.patch b/0094-Make-grub_error-more-verbose.patch new file mode 100644 index 0000000..306a3d3 --- /dev/null +++ b/0094-Make-grub_error-more-verbose.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 27 Aug 2018 13:14:06 -0400 +Subject: [PATCH] Make grub_error() more verbose + +Signed-off-by: Peter Jones +--- + grub-core/kern/err.c | 13 +++++++++++-- + include/grub/err.h | 8 ++++++-- + 2 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c +index 53c734de70..aebfe0cf83 100644 +--- a/grub-core/kern/err.c ++++ b/grub-core/kern/err.c +@@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE]; + static int grub_error_stack_pos; + static int grub_error_stack_assert; + ++#ifdef grub_error ++#undef grub_error ++#endif ++ + grub_err_t +-grub_error (grub_err_t n, const char *fmt, ...) ++grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...) + { + va_list ap; ++ int m; + + grub_errno = n; + ++ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line); ++ if (m < 0) ++ m = 0; ++ + va_start (ap, fmt); +- grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); ++ grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap); + va_end (ap); + + return n; +diff --git a/include/grub/err.h b/include/grub/err.h +index b08d5d0de4..c0f90ef07c 100644 +--- a/include/grub/err.h ++++ b/include/grub/err.h +@@ -85,8 +85,12 @@ struct grub_error_saved + extern grub_err_t EXPORT_VAR(grub_errno); + extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG]; + +-grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...) +- __attribute__ ((format (GNU_PRINTF, 2, 3))); ++grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...) ++ __attribute__ ((format (GNU_PRINTF, 4, 5))); ++ ++#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__) ++ ++ + void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn)); + void EXPORT_FUNC(grub_error_push) (void); + int EXPORT_FUNC(grub_error_pop) (void); diff --git a/0094-Prepend-prefix-when-HTTP-path-is-relative.patch b/0094-Prepend-prefix-when-HTTP-path-is-relative.patch deleted file mode 100644 index 30d8075..0000000 --- a/0094-Prepend-prefix-when-HTTP-path-is-relative.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Stephen Benjamin -Date: Thu, 16 Aug 2018 16:58:51 -0400 -Subject: [PATCH] Prepend prefix when HTTP path is relative - -This sets a couple of variables. With the url http://www.example.com/foo/bar : -http_path: /foo/bar -http_url: http://www.example.com/foo/bar - -Signed-off-by: Peter Jones -Signed-off-by: Stephen Benjamin -Signed-off-by: Robbie Harwood ---- - grub-core/kern/main.c | 10 +++++- - grub-core/net/efi/http.c | 82 ++++++++++++++++++++++++++++++++++++------------ - 2 files changed, 71 insertions(+), 21 deletions(-) - -diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c -index d1de9fa687..1c540fc8c2 100644 ---- a/grub-core/kern/main.c -+++ b/grub-core/kern/main.c -@@ -131,11 +131,19 @@ grub_set_prefix_and_root (void) - if (fwdevice && fwpath) - { - char *fw_path; -+ char separator[3] = ")"; - -- fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath); -+ grub_dprintf ("fw_path", "\n"); -+ grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath); -+ -+ if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/') -+ grub_strcpy(separator, ")/"); -+ -+ fw_path = grub_xasprintf ("(%s%s%s", fwdevice, separator, fwpath); - if (fw_path) - { - grub_env_set ("fw_path", fw_path); -+ grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path); - grub_free (fw_path); - } - } -diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c -index 243acbaa35..de351b2cd0 100644 ---- a/grub-core/net/efi/http.c -+++ b/grub-core/net/efi/http.c -@@ -9,10 +9,52 @@ - static void - http_configure (struct grub_efi_net_device *dev, int prefer_ip6) - { -+ grub_efi_ipv6_address_t address; - grub_efi_http_config_data_t http_config; - grub_efi_httpv4_access_point_t httpv4_node; - grub_efi_httpv6_access_point_t httpv6_node; - grub_efi_status_t status; -+ int https; -+ char *http_url; -+ const char *rest, *http_server, *http_path = NULL; -+ -+ http_server = grub_env_get ("root"); -+ https = (grub_strncmp (http_server, "https", 5) == 0) ? 1 : 0; -+ -+ /* extract http server + port */ -+ if (http_server) -+ { -+ http_server = grub_strchr (http_server, ','); -+ if (http_server) -+ http_server++; -+ } -+ -+ /* fw_path is like (http,192.168.1.1:8000)/httpboot, extract path part */ -+ http_path = grub_env_get ("fw_path"); -+ if (http_path) -+ { -+ http_path = grub_strchr (http_path, ')'); -+ if (http_path) -+ { -+ http_path++; -+ grub_env_unset ("http_path"); -+ grub_env_set ("http_path", http_path); -+ } -+ } -+ -+ if (http_server && http_path) -+ { -+ if (grub_efi_string_to_ip6_address (http_server, &address, &rest) && *rest == 0) -+ http_url = grub_xasprintf ("%s://[%s]%s", https ? "https" : "http", http_server, http_path); -+ else -+ http_url = grub_xasprintf ("%s://%s%s", https ? "https" : "http", http_server, http_path); -+ if (http_url) -+ { -+ grub_env_unset ("http_url"); -+ grub_env_set ("http_url", http_url); -+ grub_free (http_url); -+ } -+ } - - grub_efi_http_t *http = dev->http; - -@@ -352,32 +394,32 @@ grub_efihttp_open (struct grub_efi_net_device *dev, - grub_err_t err; - grub_off_t size; - char *buf; -- char *root_url; -- grub_efi_ipv6_address_t address; -- const char *rest; -+ char *file_name = NULL; -+ const char *http_path; - -- if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0) -- root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server); -- else -- root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server); -- if (root_url) -- { -- grub_env_unset ("root_url"); -- grub_env_set ("root_url", root_url); -- grub_free (root_url); -- } -- else -- { -+ /* If path is relative, prepend http_path */ -+ http_path = grub_env_get ("http_path"); -+ if (http_path && file->device->net->name[0] != '/') { -+ file_name = grub_xasprintf ("%s/%s", http_path, file->device->net->name); -+ if (!file_name) - return grub_errno; -- } -+ } - -- err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); -+ err = efihttp_request (dev->http, file->device->net->server, -+ file_name ? file_name : file->device->net->name, type, 1, 0); - if (err != GRUB_ERR_NONE) -- return err; -+ { -+ grub_free (file_name); -+ return err; -+ } - -- err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); -+ err = efihttp_request (dev->http, file->device->net->server, -+ file_name ? file_name : file->device->net->name, type, 0, &size); -+ grub_free (file_name); - if (err != GRUB_ERR_NONE) -- return err; -+ { -+ return err; -+ } - - buf = grub_malloc (size); - efihttp_read (dev, buf, size); diff --git a/0095-Make-grub_error-more-verbose.patch b/0095-Make-grub_error-more-verbose.patch deleted file mode 100644 index 306a3d3..0000000 --- a/0095-Make-grub_error-more-verbose.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 27 Aug 2018 13:14:06 -0400 -Subject: [PATCH] Make grub_error() more verbose - -Signed-off-by: Peter Jones ---- - grub-core/kern/err.c | 13 +++++++++++-- - include/grub/err.h | 8 ++++++-- - 2 files changed, 17 insertions(+), 4 deletions(-) - -diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c -index 53c734de70..aebfe0cf83 100644 ---- a/grub-core/kern/err.c -+++ b/grub-core/kern/err.c -@@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE]; - static int grub_error_stack_pos; - static int grub_error_stack_assert; - -+#ifdef grub_error -+#undef grub_error -+#endif -+ - grub_err_t --grub_error (grub_err_t n, const char *fmt, ...) -+grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...) - { - va_list ap; -+ int m; - - grub_errno = n; - -+ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line); -+ if (m < 0) -+ m = 0; -+ - va_start (ap, fmt); -- grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); -+ grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap); - va_end (ap); - - return n; -diff --git a/include/grub/err.h b/include/grub/err.h -index b08d5d0de4..c0f90ef07c 100644 ---- a/include/grub/err.h -+++ b/include/grub/err.h -@@ -85,8 +85,12 @@ struct grub_error_saved - extern grub_err_t EXPORT_VAR(grub_errno); - extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG]; - --grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...) -- __attribute__ ((format (GNU_PRINTF, 2, 3))); -+grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...) -+ __attribute__ ((format (GNU_PRINTF, 4, 5))); -+ -+#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -+ -+ - void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn)); - void EXPORT_FUNC(grub_error_push) (void); - int EXPORT_FUNC(grub_error_pop) (void); diff --git a/0095-Make-reset-an-alias-for-the-reboot-command.patch b/0095-Make-reset-an-alias-for-the-reboot-command.patch new file mode 100644 index 0000000..22475d6 --- /dev/null +++ b/0095-Make-reset-an-alias-for-the-reboot-command.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 31 Aug 2018 16:42:03 -0400 +Subject: [PATCH] Make "reset" an alias for the "reboot" command. + +I'm really tired of half the tools I get to use having one and the other half +having the other. + +Signed-off-by: Peter Jones +--- + grub-core/commands/reboot.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c +index 46d364c99a..f5cc228363 100644 +--- a/grub-core/commands/reboot.c ++++ b/grub-core/commands/reboot.c +@@ -32,15 +32,18 @@ grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)), + grub_reboot (); + } + +-static grub_command_t cmd; ++static grub_command_t reboot_cmd, reset_cmd; + + GRUB_MOD_INIT(reboot) + { +- cmd = grub_register_command ("reboot", grub_cmd_reboot, +- 0, N_("Reboot the computer.")); ++ reboot_cmd = grub_register_command ("reboot", grub_cmd_reboot, ++ 0, N_("Reboot the computer.")); ++ reset_cmd = grub_register_command ("reset", grub_cmd_reboot, ++ 0, N_("Reboot the computer.")); + } + + GRUB_MOD_FINI(reboot) + { +- grub_unregister_command (cmd); ++ grub_unregister_command (reboot_cmd); ++ grub_unregister_command (reset_cmd); + } diff --git a/0096-Add-a-version-command.patch b/0096-Add-a-version-command.patch new file mode 100644 index 0000000..10d40b3 --- /dev/null +++ b/0096-Add-a-version-command.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 11 Sep 2018 14:20:37 -0400 +Subject: [PATCH] Add a "version" command + +This adds a command that shows you info about grub's version, the grub +target platform, the compiler version, and if you built with +--with-rpm-version=, the rpm package version. + +Signed-off-by: Peter Jones +[rharwood: don't say GNU, commit message cleanup] +Signed-off-by: Robbie Harwood +--- + configure.ac | 13 ++++++++++ + grub-core/Makefile.core.def | 5 ++++ + grub-core/commands/version.c | 56 ++++++++++++++++++++++++++++++++++++++++++++ + config.h.in | 1 + + 4 files changed, 75 insertions(+) + create mode 100644 grub-core/commands/version.c + +diff --git a/configure.ac b/configure.ac +index 54462e0892..7b4e1854d3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -284,6 +284,19 @@ AC_SUBST(target_cpu) + AC_SUBST(platform) + + # Define default variables ++have_with_rpm_version=n ++AC_ARG_WITH([rpm_version], ++ AS_HELP_STRING([--with-rpm-version=VERSION], ++ [set the rpm package version [[guessed]]]), ++ [have_with_rpm_version=y], ++ [have_with_rpm_version=n]) ++if test x$have_with_rpm_version = xy; then ++ rpm_version="$with_rpm_version" ++else ++ rpm_version="" ++fi ++GRUB_RPM_VERSION="$rpm_version" ++AC_SUBST(GRUB_RPM_VERSION) + + have_with_bootdir=n + AC_ARG_WITH([bootdir], +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 84a3d89de9..498ca11762 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -579,6 +579,11 @@ image = { + enable = mips_loongson; + }; + ++module = { ++ name = version; ++ common = commands/version.c; ++}; ++ + module = { + name = disk; + common = lib/disk.c; +diff --git a/grub-core/commands/version.c b/grub-core/commands/version.c +new file mode 100644 +index 0000000000..de0acb07ba +--- /dev/null ++++ b/grub-core/commands/version.c +@@ -0,0 +1,56 @@ ++/* version.c - Command to print the grub version and build info. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_err_t ++grub_cmd_version (grub_command_t cmd UNUSED, int argc, char **args UNUSED) ++{ ++ if (argc != 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no arguments expected")); ++ ++ grub_printf (_("GRUB version %s\n"), PACKAGE_VERSION); ++ grub_printf (_("Platform %s-%s\n"), GRUB_TARGET_CPU, GRUB_PLATFORM); ++ if (grub_strlen(GRUB_RPM_VERSION) != 0) ++ grub_printf (_("RPM package version %s\n"), GRUB_RPM_VERSION); ++ grub_printf (_("Compiler version %s\n"), __VERSION__); ++ ++ return 0; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(version) ++{ ++ cmd = grub_register_command ("version", grub_cmd_version, NULL, ++ N_("Print version and build information.")); ++} ++ ++GRUB_MOD_FINI(version) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/config.h.in b/config.h.in +index 9e8f9911b1..c7e316f0f1 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -59,6 +59,7 @@ + + #define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" + #define GRUB_PLATFORM "@GRUB_PLATFORM@" ++#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" + + #define RE_ENABLE_I18N 1 + diff --git a/0096-Make-reset-an-alias-for-the-reboot-command.patch b/0096-Make-reset-an-alias-for-the-reboot-command.patch deleted file mode 100644 index 22475d6..0000000 --- a/0096-Make-reset-an-alias-for-the-reboot-command.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 31 Aug 2018 16:42:03 -0400 -Subject: [PATCH] Make "reset" an alias for the "reboot" command. - -I'm really tired of half the tools I get to use having one and the other half -having the other. - -Signed-off-by: Peter Jones ---- - grub-core/commands/reboot.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c -index 46d364c99a..f5cc228363 100644 ---- a/grub-core/commands/reboot.c -+++ b/grub-core/commands/reboot.c -@@ -32,15 +32,18 @@ grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)), - grub_reboot (); - } - --static grub_command_t cmd; -+static grub_command_t reboot_cmd, reset_cmd; - - GRUB_MOD_INIT(reboot) - { -- cmd = grub_register_command ("reboot", grub_cmd_reboot, -- 0, N_("Reboot the computer.")); -+ reboot_cmd = grub_register_command ("reboot", grub_cmd_reboot, -+ 0, N_("Reboot the computer.")); -+ reset_cmd = grub_register_command ("reset", grub_cmd_reboot, -+ 0, N_("Reboot the computer.")); - } - - GRUB_MOD_FINI(reboot) - { -- grub_unregister_command (cmd); -+ grub_unregister_command (reboot_cmd); -+ grub_unregister_command (reset_cmd); - } diff --git a/0097-Add-a-version-command.patch b/0097-Add-a-version-command.patch deleted file mode 100644 index 8daad53..0000000 --- a/0097-Add-a-version-command.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 11 Sep 2018 14:20:37 -0400 -Subject: [PATCH] Add a "version" command - -This adds a command that shows you info about grub's version, the grub -target platform, the compiler version, and if you built with ---with-rpm-version=, the rpm package version. - -Signed-off-by: Peter Jones -[rharwood: don't say GNU, commit message cleanup] -Signed-off-by: Robbie Harwood ---- - configure.ac | 13 ++++++++++ - grub-core/Makefile.core.def | 5 ++++ - grub-core/commands/version.c | 56 ++++++++++++++++++++++++++++++++++++++++++++ - config.h.in | 1 + - 4 files changed, 75 insertions(+) - create mode 100644 grub-core/commands/version.c - -diff --git a/configure.ac b/configure.ac -index f42be65332..2af5f23adf 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -285,6 +285,19 @@ AC_SUBST(target_cpu) - AC_SUBST(platform) - - # Define default variables -+have_with_rpm_version=n -+AC_ARG_WITH([rpm_version], -+ AS_HELP_STRING([--with-rpm-version=VERSION], -+ [set the rpm package version [[guessed]]]), -+ [have_with_rpm_version=y], -+ [have_with_rpm_version=n]) -+if test x$have_with_rpm_version = xy; then -+ rpm_version="$with_rpm_version" -+else -+ rpm_version="" -+fi -+GRUB_RPM_VERSION="$rpm_version" -+AC_SUBST(GRUB_RPM_VERSION) - - have_with_bootdir=n - AC_ARG_WITH([bootdir], -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 84a3d89de9..498ca11762 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -579,6 +579,11 @@ image = { - enable = mips_loongson; - }; - -+module = { -+ name = version; -+ common = commands/version.c; -+}; -+ - module = { - name = disk; - common = lib/disk.c; -diff --git a/grub-core/commands/version.c b/grub-core/commands/version.c -new file mode 100644 -index 0000000000..de0acb07ba ---- /dev/null -+++ b/grub-core/commands/version.c -@@ -0,0 +1,56 @@ -+/* version.c - Command to print the grub version and build info. */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static grub_err_t -+grub_cmd_version (grub_command_t cmd UNUSED, int argc, char **args UNUSED) -+{ -+ if (argc != 0) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no arguments expected")); -+ -+ grub_printf (_("GRUB version %s\n"), PACKAGE_VERSION); -+ grub_printf (_("Platform %s-%s\n"), GRUB_TARGET_CPU, GRUB_PLATFORM); -+ if (grub_strlen(GRUB_RPM_VERSION) != 0) -+ grub_printf (_("RPM package version %s\n"), GRUB_RPM_VERSION); -+ grub_printf (_("Compiler version %s\n"), __VERSION__); -+ -+ return 0; -+} -+ -+static grub_command_t cmd; -+ -+GRUB_MOD_INIT(version) -+{ -+ cmd = grub_register_command ("version", grub_cmd_version, NULL, -+ N_("Print version and build information.")); -+} -+ -+GRUB_MOD_FINI(version) -+{ -+ grub_unregister_command (cmd); -+} -diff --git a/config.h.in b/config.h.in -index 9e8f9911b1..c7e316f0f1 100644 ---- a/config.h.in -+++ b/config.h.in -@@ -59,6 +59,7 @@ - - #define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" - #define GRUB_PLATFORM "@GRUB_PLATFORM@" -+#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" - - #define RE_ENABLE_I18N 1 - diff --git a/0097-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch b/0097-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch new file mode 100644 index 0000000..72c8d30 --- /dev/null +++ b/0097-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 11 Sep 2018 15:58:29 -0400 +Subject: [PATCH] Add more dprintf, and nerf dprintf in script.c + +Signed-off-by: Peter Jones +--- + grub-core/disk/diskfilter.c | 3 +++ + grub-core/disk/efi/efidisk.c | 1 + + grub-core/kern/device.c | 1 + + grub-core/script/script.c | 5 +++++ + 4 files changed, 10 insertions(+) + +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index 0320115662..7cdffe3ebd 100644 +--- a/grub-core/disk/diskfilter.c ++++ b/grub-core/disk/diskfilter.c +@@ -188,6 +188,8 @@ scan_disk (const char *name, int accept_diskfilter) + grub_disk_t disk; + static int scan_depth = 0; + ++ grub_dprintf ("diskfilter", "scanning %s\n", name); ++ + if (!accept_diskfilter && is_valid_diskfilter_name (name)) + return 0; + +@@ -1212,6 +1214,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, + the same. */ + if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size) + return GRUB_ERR_NONE; ++ grub_dprintf ("diskfilter", "checking %s\n", disk->name); + pv->disk = grub_disk_open (disk->name); + if (!pv->disk) + return grub_errno; +diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c +index f077b5f553..fe8ba6e6c9 100644 +--- a/grub-core/disk/efi/efidisk.c ++++ b/grub-core/disk/efi/efidisk.c +@@ -855,6 +855,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) + return 0; + } + ++ grub_dprintf ("efidisk", "getting disk for %s\n", device_name); + parent = grub_disk_open (device_name); + grub_free (dup_dp); + +diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c +index 73b8ecc0c0..f58b58c89d 100644 +--- a/grub-core/kern/device.c ++++ b/grub-core/kern/device.c +@@ -34,6 +34,7 @@ grub_device_open (const char *name) + { + grub_device_t dev = 0; + ++ grub_dprintf ("device", "opening device %s\n", name); + if (! name) + { + name = grub_env_get ("root"); +diff --git a/grub-core/script/script.c b/grub-core/script/script.c +index ec4d4337c6..844e8343ca 100644 +--- a/grub-core/script/script.c ++++ b/grub-core/script/script.c +@@ -22,6 +22,11 @@ + #include + #include + ++#ifdef grub_dprintf ++#undef grub_dprintf ++#endif ++#define grub_dprintf(no, fmt, ...) ++ + /* It is not possible to deallocate the memory when a syntax error was + found. Because of that it is required to keep track of all memory + allocations. The memory is freed in case of an error, or assigned diff --git a/0098-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch b/0098-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch deleted file mode 100644 index 72c8d30..0000000 --- a/0098-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 11 Sep 2018 15:58:29 -0400 -Subject: [PATCH] Add more dprintf, and nerf dprintf in script.c - -Signed-off-by: Peter Jones ---- - grub-core/disk/diskfilter.c | 3 +++ - grub-core/disk/efi/efidisk.c | 1 + - grub-core/kern/device.c | 1 + - grub-core/script/script.c | 5 +++++ - 4 files changed, 10 insertions(+) - -diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c -index 0320115662..7cdffe3ebd 100644 ---- a/grub-core/disk/diskfilter.c -+++ b/grub-core/disk/diskfilter.c -@@ -188,6 +188,8 @@ scan_disk (const char *name, int accept_diskfilter) - grub_disk_t disk; - static int scan_depth = 0; - -+ grub_dprintf ("diskfilter", "scanning %s\n", name); -+ - if (!accept_diskfilter && is_valid_diskfilter_name (name)) - return 0; - -@@ -1212,6 +1214,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, - the same. */ - if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size) - return GRUB_ERR_NONE; -+ grub_dprintf ("diskfilter", "checking %s\n", disk->name); - pv->disk = grub_disk_open (disk->name); - if (!pv->disk) - return grub_errno; -diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c -index f077b5f553..fe8ba6e6c9 100644 ---- a/grub-core/disk/efi/efidisk.c -+++ b/grub-core/disk/efi/efidisk.c -@@ -855,6 +855,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) - return 0; - } - -+ grub_dprintf ("efidisk", "getting disk for %s\n", device_name); - parent = grub_disk_open (device_name); - grub_free (dup_dp); - -diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c -index 73b8ecc0c0..f58b58c89d 100644 ---- a/grub-core/kern/device.c -+++ b/grub-core/kern/device.c -@@ -34,6 +34,7 @@ grub_device_open (const char *name) - { - grub_device_t dev = 0; - -+ grub_dprintf ("device", "opening device %s\n", name); - if (! name) - { - name = grub_env_get ("root"); -diff --git a/grub-core/script/script.c b/grub-core/script/script.c -index ec4d4337c6..844e8343ca 100644 ---- a/grub-core/script/script.c -+++ b/grub-core/script/script.c -@@ -22,6 +22,11 @@ - #include - #include - -+#ifdef grub_dprintf -+#undef grub_dprintf -+#endif -+#define grub_dprintf(no, fmt, ...) -+ - /* It is not possible to deallocate the memory when a syntax error was - found. Because of that it is required to keep track of all memory - allocations. The memory is freed in case of an error, or assigned diff --git a/0098-arm-arm64-loader-Better-memory-allocation-and-error-.patch b/0098-arm-arm64-loader-Better-memory-allocation-and-error-.patch new file mode 100644 index 0000000..57d937c --- /dev/null +++ b/0098-arm-arm64-loader-Better-memory-allocation-and-error-.patch @@ -0,0 +1,279 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 14:38:57 +0200 +Subject: [PATCH] arm/arm64 loader: Better memory allocation and error + messages. + +On mustang, our memory map looks like: + +Type Physical start - end #Pages Size Attributes +reserved 0000004000000000-00000040001fffff 00000200 2MiB UC WC WT WB +conv-mem 0000004000200000-0000004393ffffff 00393e00 14654MiB UC WC WT WB +ldr-code 0000004394000000-00000043f7ffffff 00064000 1600MiB UC WC WT WB +BS-data 00000043f8000000-00000043f801ffff 00000020 128KiB UC WC WT WB +conv-mem 00000043f8020000-00000043fa15bfff 0000213c 34032KiB UC WC WT WB +ldr-code 00000043fa15c000-00000043fa2a1fff 00000146 1304KiB UC WC WT WB +ldr-data 00000043fa2a2000-00000043fa3e8fff 00000147 1308KiB UC WC WT WB +conv-mem 00000043fa3e9000-00000043fa3e9fff 00000001 4KiB UC WC WT WB +ldr-data 00000043fa3ea000-00000043fa3eafff 00000001 4KiB UC WC WT WB +ldr-code 00000043fa3eb000-00000043fa4affff 000000c5 788KiB UC WC WT WB +BS-code 00000043fa4b0000-00000043fa59ffff 000000f0 960KiB UC WC WT WB +RT-code 00000043fa5a0000-00000043fa5affff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa5b0000-00000043fa5bffff 00000010 64KiB RT UC WC WT WB +RT-code 00000043fa5c0000-00000043fa5cffff 00000010 64KiB RT UC WC WT WB +ldr-data 00000043fa5d0000-00000043fa5d0fff 00000001 4KiB UC WC WT WB +BS-code 00000043fa5d1000-00000043fa5ddfff 0000000d 52KiB UC WC WT WB +reserved 00000043fa5de000-00000043fa60ffff 00000032 200KiB UC WC WT WB +ACPI-rec 00000043fa610000-00000043fa6affff 000000a0 640KiB UC WC WT WB +ACPI-nvs 00000043fa6b0000-00000043fa6bffff 00000010 64KiB UC WC WT WB +ACPI-rec 00000043fa6c0000-00000043fa70ffff 00000050 320KiB UC WC WT WB +RT-code 00000043fa710000-00000043fa72ffff 00000020 128KiB RT UC WC WT WB +RT-data 00000043fa730000-00000043fa78ffff 00000060 384KiB RT UC WC WT WB +RT-code 00000043fa790000-00000043fa79ffff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa7a0000-00000043fa99ffff 00000200 2MiB RT UC WC WT WB +RT-code 00000043fa9a0000-00000043fa9affff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa9b0000-00000043fa9cffff 00000020 128KiB RT UC WC WT WB +BS-code 00000043fa9d0000-00000043fa9d9fff 0000000a 40KiB UC WC WT WB +reserved 00000043fa9da000-00000043fa9dbfff 00000002 8KiB UC WC WT WB +conv-mem 00000043fa9dc000-00000043fc29dfff 000018c2 25352KiB UC WC WT WB +BS-data 00000043fc29e000-00000043fc78afff 000004ed 5044KiB UC WC WT WB +conv-mem 00000043fc78b000-00000043fca01fff 00000277 2524KiB UC WC WT WB +BS-data 00000043fca02000-00000043fcea3fff 000004a2 4744KiB UC WC WT WB +conv-mem 00000043fcea4000-00000043fcea4fff 00000001 4KiB UC WC WT WB +BS-data 00000043fcea5000-00000043fd192fff 000002ee 3000KiB UC WC WT WB +conv-mem 00000043fd193000-00000043fd2b0fff 0000011e 1144KiB UC WC WT WB +BS-data 00000043fd2b1000-00000043ff80ffff 0000255f 38268KiB UC WC WT WB +BS-code 00000043ff810000-00000043ff99ffff 00000190 1600KiB UC WC WT WB +RT-code 00000043ff9a0000-00000043ff9affff 00000010 64KiB RT UC WC WT WB +conv-mem 00000043ff9b0000-00000043ff9bffff 00000010 64KiB UC WC WT WB +RT-data 00000043ff9c0000-00000043ff9effff 00000030 192KiB RT UC WC WT WB +conv-mem 00000043ff9f0000-00000043ffa05fff 00000016 88KiB UC WC WT WB +BS-data 00000043ffa06000-00000043ffffffff 000005fa 6120KiB UC WC WT WB +MMIO 0000000010510000-0000000010510fff 00000001 4KiB RT +MMIO 0000000010548000-0000000010549fff 00000002 8KiB RT +MMIO 0000000017000000-0000000017001fff 00000002 8KiB RT +MMIO 000000001c025000-000000001c025fff 00000001 4KiB RT + +This patch adds a requirement when we're trying to find the base of ram, that +the memory we choose is actually /allocatable/ conventional memory, not merely +write-combining. On this machine that means we wind up with an allocation +around 0x4392XXXXXX, which is a reasonable address. + +This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it +tries to allocate again starting with the same max address it did the first +time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any +per-platform constraints on its given address are maintained. + +Signed-off-by: Peter Jones +--- + grub-core/kern/efi/mm.c | 33 +++++++++++++++----- + grub-core/loader/arm64/linux.c | 68 +++++++++++++++++++++++++++++++----------- + 2 files changed, 76 insertions(+), 25 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index f6aef0ef64..85ad4b4494 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + { + grub_efi_status_t status; + grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t ret = address; + + /* Limit the memory access to less than 4GB for 32-bit platforms. */ + if (address > GRUB_EFI_MAX_USABLE_ADDRESS) +@@ -170,19 +171,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + + b = grub_efi_system_table->boot_services; +- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); ++ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + if (status != GRUB_EFI_SUCCESS) + { ++ grub_dprintf ("efi", ++ "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n", ++ alloctype, memtype, pages, address, status); + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + return NULL; + } + +- if (address == 0) ++ if (ret == 0) + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ +- address = GRUB_EFI_MAX_USABLE_ADDRESS; +- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); ++ ret = address; ++ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) + { +@@ -191,9 +195,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + } + +- grub_efi_store_alloc (address, pages); ++ grub_efi_store_alloc (ret, pages); + +- return (void *) ((grub_addr_t) address); ++ return (void *) ((grub_addr_t) ret); + } + + void * +@@ -713,8 +717,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) + for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS; + (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) +- if (desc->attribute & GRUB_EFI_MEMORY_WB) +- *base_addr = grub_min (*base_addr, desc->physical_start); ++ { ++ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY && ++ (desc->attribute & GRUB_EFI_MEMORY_WB)) ++ { ++ *base_addr = grub_min (*base_addr, desc->physical_start); ++ grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr); ++ } ++ else ++ { ++ grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start); ++ } ++ } ++ ++ if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS) ++ grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr); + + grub_free(memory_map); + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 04994d5c67..70a0075ec5 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -71,20 +71,25 @@ finalize_params_linux (void) + { + grub_efi_loaded_image_t *loaded_image = NULL; + int node, retval, len; +- ++ grub_err_t err = GRUB_ERR_NONE; + void *fdt; + + fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); +- + if (!fdt) +- goto failure; ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT"); ++ goto failure; ++ } + + node = grub_fdt_find_subnode (fdt, 0, "chosen"); + if (node < 0) + node = grub_fdt_add_subnode (fdt, 0, "chosen"); + + if (node < 1) +- goto failure; ++ { ++ err = grub_error(grub_errno, "failed to load chosen fdt node."); ++ goto failure; ++ } + + /* Set initrd info */ + if (initrd_start && initrd_end > initrd_start) +@@ -95,15 +100,26 @@ finalize_params_linux (void) + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", + initrd_start); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-start property"); ++ goto failure; ++ } ++ + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", + initrd_end); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-end property"); ++ goto failure; ++ } + } + +- if (grub_fdt_install() != GRUB_ERR_NONE) +- goto failure; ++ retval = grub_fdt_install(); ++ if (retval != GRUB_ERR_NONE) ++ { ++ err = grub_error(retval, "Failed to install fdt"); ++ goto failure; ++ } + + grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", + fdt); +@@ -111,14 +127,20 @@ finalize_params_linux (void) + /* Convert command line to UCS-2 */ + loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (!loaded_image) +- goto failure; ++ { ++ err = grub_error(grub_errno, "Failed to install fdt"); ++ goto failure; ++ } + + loaded_image->load_options_size = len = + (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); + loaded_image->load_options = + grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); + if (!loaded_image->load_options) +- return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ goto failure; ++ } + + loaded_image->load_options_size = + 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, +@@ -128,7 +150,7 @@ finalize_params_linux (void) + + failure: + grub_fdt_unload(); +- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++ return err; + } + + static void +@@ -212,16 +234,28 @@ grub_linux_unload (void) + static void * + allocate_initrd_mem (int initrd_pages) + { +- grub_addr_t max_addr; ++ grub_addr_t max_addr = 0; ++ grub_err_t err; ++ void *ret; + +- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) +- return NULL; ++ err = grub_efi_get_ram_base (&max_addr); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_error (err, "grub_efi_get_ram_base() failed"); ++ return NULL; ++ } ++ ++ grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n", ++ max_addr, INITRD_MAX_ADDRESS_OFFSET); + + max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; ++ grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages); + +- return grub_efi_allocate_pages_real (max_addr, initrd_pages, +- GRUB_EFI_ALLOCATE_MAX_ADDRESS, +- GRUB_EFI_LOADER_DATA); ++ ret = grub_efi_allocate_pages_real (max_addr, initrd_pages, ++ GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_DATA); ++ grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret); ++ return ret; + } + + static grub_err_t diff --git a/0099-Try-to-pick-better-locations-for-kernel-and-initrd.patch b/0099-Try-to-pick-better-locations-for-kernel-and-initrd.patch new file mode 100644 index 0000000..4f42ea5 --- /dev/null +++ b/0099-Try-to-pick-better-locations-for-kernel-and-initrd.patch @@ -0,0 +1,211 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 17:17:02 +0200 +Subject: [PATCH] Try to pick better locations for kernel and initrd + +- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if + we're using the "large" code model ; use __UINTPTR_MAX__. +- Get the comparison right to check the address we've allocated. +- Fix the allocation for the command line as well. + +*But*, when we did this some systems started failing badly; coudln't +parse partition tables, etc. What's going on here is the disk controller +is silently failing DMAs to addresses above 4GB, so we're trying to parse +uninitialized (or HW zeroed) ram when looking for the partition table, +etc. + +So to limit this, we make grub_malloc() pick addresses below 4GB on +x86_64, but the direct EFI page allocation functions can get addresses +above that. + +Additionally, we now try to locate kernel+initrd+cmdline+etc below +0x7fffffff, and if they're too big to fit any memory window there, then +we try a higher address. + +Signed-off-by: Peter Jones +[david.abdurachmanov: fix macro for riscv64] +Signed-off-by: David Abdurachmanov +Signed-off-by: Robbie Harwood +--- + grub-core/kern/efi/mm.c | 8 ++++---- + grub-core/loader/i386/efi/linux.c | 24 +++++++++++++++++------- + include/grub/arm/efi/memory.h | 1 + + include/grub/arm64/efi/memory.h | 1 + + include/grub/i386/efi/memory.h | 1 + + include/grub/ia64/efi/memory.h | 1 + + include/grub/riscv64/efi/memory.h | 1 + + include/grub/x86_64/efi/memory.h | 4 +++- + 8 files changed, 29 insertions(+), 12 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 85ad4b4494..e84961d078 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -122,7 +122,7 @@ grub_efi_allocate_pages_max (grub_efi_physical_address_t max, + grub_efi_boot_services_t *b; + grub_efi_physical_address_t address = max; + +- if (max > 0xffffffff) ++ if (max > GRUB_EFI_MAX_USABLE_ADDRESS) + return 0; + + b = grub_efi_system_table->boot_services; +@@ -480,7 +480,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY + #if 1 +- && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS ++ && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS + #endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 + && desc->num_pages != 0) +@@ -498,9 +498,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + #if 1 + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages +- > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)) ++ > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) + filtered_desc->num_pages +- = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS) ++ = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS) + - BYTES_TO_PAGES (filtered_desc->physical_start)); + #endif + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 3017d0f3e5..33e981e76e 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -106,7 +107,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); ++ if (!initrd_mem) ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); + if (!initrd_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +@@ -202,8 +205,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (0x3fffffff, ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); + if (! params) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +@@ -273,8 +279,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + #endif + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ if (!linux_cmdline) ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + if (!linux_cmdline) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +@@ -301,11 +310,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->init_size)); ++ if (!kernel_mem) ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h +index 2c64918e3f..a4c2ec8350 100644 +--- a/include/grub/arm/efi/memory.h ++++ b/include/grub/arm/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h +index c6cb324171..acb61dca44 100644 +--- a/include/grub/arm64/efi/memory.h ++++ b/include/grub/arm64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h +index 2c64918e3f..a4c2ec8350 100644 +--- a/include/grub/i386/efi/memory.h ++++ b/include/grub/i386/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h +index 2c64918e3f..a4c2ec8350 100644 +--- a/include/grub/ia64/efi/memory.h ++++ b/include/grub/ia64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h +index c6cb324171..acb61dca44 100644 +--- a/include/grub/riscv64/efi/memory.h ++++ b/include/grub/riscv64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h +index 46e9145a30..e81cfb3221 100644 +--- a/include/grub/x86_64/efi/memory.h ++++ b/include/grub/x86_64/efi/memory.h +@@ -2,9 +2,11 @@ + #include + + #if defined (__code_model_large__) +-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__ ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff + #else + #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + #endif + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/0099-arm-arm64-loader-Better-memory-allocation-and-error-.patch b/0099-arm-arm64-loader-Better-memory-allocation-and-error-.patch deleted file mode 100644 index 57d937c..0000000 --- a/0099-arm-arm64-loader-Better-memory-allocation-and-error-.patch +++ /dev/null @@ -1,279 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 11 Jul 2019 14:38:57 +0200 -Subject: [PATCH] arm/arm64 loader: Better memory allocation and error - messages. - -On mustang, our memory map looks like: - -Type Physical start - end #Pages Size Attributes -reserved 0000004000000000-00000040001fffff 00000200 2MiB UC WC WT WB -conv-mem 0000004000200000-0000004393ffffff 00393e00 14654MiB UC WC WT WB -ldr-code 0000004394000000-00000043f7ffffff 00064000 1600MiB UC WC WT WB -BS-data 00000043f8000000-00000043f801ffff 00000020 128KiB UC WC WT WB -conv-mem 00000043f8020000-00000043fa15bfff 0000213c 34032KiB UC WC WT WB -ldr-code 00000043fa15c000-00000043fa2a1fff 00000146 1304KiB UC WC WT WB -ldr-data 00000043fa2a2000-00000043fa3e8fff 00000147 1308KiB UC WC WT WB -conv-mem 00000043fa3e9000-00000043fa3e9fff 00000001 4KiB UC WC WT WB -ldr-data 00000043fa3ea000-00000043fa3eafff 00000001 4KiB UC WC WT WB -ldr-code 00000043fa3eb000-00000043fa4affff 000000c5 788KiB UC WC WT WB -BS-code 00000043fa4b0000-00000043fa59ffff 000000f0 960KiB UC WC WT WB -RT-code 00000043fa5a0000-00000043fa5affff 00000010 64KiB RT UC WC WT WB -RT-data 00000043fa5b0000-00000043fa5bffff 00000010 64KiB RT UC WC WT WB -RT-code 00000043fa5c0000-00000043fa5cffff 00000010 64KiB RT UC WC WT WB -ldr-data 00000043fa5d0000-00000043fa5d0fff 00000001 4KiB UC WC WT WB -BS-code 00000043fa5d1000-00000043fa5ddfff 0000000d 52KiB UC WC WT WB -reserved 00000043fa5de000-00000043fa60ffff 00000032 200KiB UC WC WT WB -ACPI-rec 00000043fa610000-00000043fa6affff 000000a0 640KiB UC WC WT WB -ACPI-nvs 00000043fa6b0000-00000043fa6bffff 00000010 64KiB UC WC WT WB -ACPI-rec 00000043fa6c0000-00000043fa70ffff 00000050 320KiB UC WC WT WB -RT-code 00000043fa710000-00000043fa72ffff 00000020 128KiB RT UC WC WT WB -RT-data 00000043fa730000-00000043fa78ffff 00000060 384KiB RT UC WC WT WB -RT-code 00000043fa790000-00000043fa79ffff 00000010 64KiB RT UC WC WT WB -RT-data 00000043fa7a0000-00000043fa99ffff 00000200 2MiB RT UC WC WT WB -RT-code 00000043fa9a0000-00000043fa9affff 00000010 64KiB RT UC WC WT WB -RT-data 00000043fa9b0000-00000043fa9cffff 00000020 128KiB RT UC WC WT WB -BS-code 00000043fa9d0000-00000043fa9d9fff 0000000a 40KiB UC WC WT WB -reserved 00000043fa9da000-00000043fa9dbfff 00000002 8KiB UC WC WT WB -conv-mem 00000043fa9dc000-00000043fc29dfff 000018c2 25352KiB UC WC WT WB -BS-data 00000043fc29e000-00000043fc78afff 000004ed 5044KiB UC WC WT WB -conv-mem 00000043fc78b000-00000043fca01fff 00000277 2524KiB UC WC WT WB -BS-data 00000043fca02000-00000043fcea3fff 000004a2 4744KiB UC WC WT WB -conv-mem 00000043fcea4000-00000043fcea4fff 00000001 4KiB UC WC WT WB -BS-data 00000043fcea5000-00000043fd192fff 000002ee 3000KiB UC WC WT WB -conv-mem 00000043fd193000-00000043fd2b0fff 0000011e 1144KiB UC WC WT WB -BS-data 00000043fd2b1000-00000043ff80ffff 0000255f 38268KiB UC WC WT WB -BS-code 00000043ff810000-00000043ff99ffff 00000190 1600KiB UC WC WT WB -RT-code 00000043ff9a0000-00000043ff9affff 00000010 64KiB RT UC WC WT WB -conv-mem 00000043ff9b0000-00000043ff9bffff 00000010 64KiB UC WC WT WB -RT-data 00000043ff9c0000-00000043ff9effff 00000030 192KiB RT UC WC WT WB -conv-mem 00000043ff9f0000-00000043ffa05fff 00000016 88KiB UC WC WT WB -BS-data 00000043ffa06000-00000043ffffffff 000005fa 6120KiB UC WC WT WB -MMIO 0000000010510000-0000000010510fff 00000001 4KiB RT -MMIO 0000000010548000-0000000010549fff 00000002 8KiB RT -MMIO 0000000017000000-0000000017001fff 00000002 8KiB RT -MMIO 000000001c025000-000000001c025fff 00000001 4KiB RT - -This patch adds a requirement when we're trying to find the base of ram, that -the memory we choose is actually /allocatable/ conventional memory, not merely -write-combining. On this machine that means we wind up with an allocation -around 0x4392XXXXXX, which is a reasonable address. - -This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it -tries to allocate again starting with the same max address it did the first -time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any -per-platform constraints on its given address are maintained. - -Signed-off-by: Peter Jones ---- - grub-core/kern/efi/mm.c | 33 +++++++++++++++----- - grub-core/loader/arm64/linux.c | 68 +++++++++++++++++++++++++++++++----------- - 2 files changed, 76 insertions(+), 25 deletions(-) - -diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c -index f6aef0ef64..85ad4b4494 100644 ---- a/grub-core/kern/efi/mm.c -+++ b/grub-core/kern/efi/mm.c -@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, - { - grub_efi_status_t status; - grub_efi_boot_services_t *b; -+ grub_efi_physical_address_t ret = address; - - /* Limit the memory access to less than 4GB for 32-bit platforms. */ - if (address > GRUB_EFI_MAX_USABLE_ADDRESS) -@@ -170,19 +171,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, - } - - b = grub_efi_system_table->boot_services; -- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); -+ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); - if (status != GRUB_EFI_SUCCESS) - { -+ grub_dprintf ("efi", -+ "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n", -+ alloctype, memtype, pages, address, status); - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); - return NULL; - } - -- if (address == 0) -+ if (ret == 0) - { - /* Uggh, the address 0 was allocated... This is too annoying, - so reallocate another one. */ -- address = GRUB_EFI_MAX_USABLE_ADDRESS; -- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); -+ ret = address; -+ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); - grub_efi_free_pages (0, pages); - if (status != GRUB_EFI_SUCCESS) - { -@@ -191,9 +195,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, - } - } - -- grub_efi_store_alloc (address, pages); -+ grub_efi_store_alloc (ret, pages); - -- return (void *) ((grub_addr_t) address); -+ return (void *) ((grub_addr_t) ret); - } - - void * -@@ -713,8 +717,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) - for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS; - (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size); - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) -- if (desc->attribute & GRUB_EFI_MEMORY_WB) -- *base_addr = grub_min (*base_addr, desc->physical_start); -+ { -+ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY && -+ (desc->attribute & GRUB_EFI_MEMORY_WB)) -+ { -+ *base_addr = grub_min (*base_addr, desc->physical_start); -+ grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr); -+ } -+ else -+ { -+ grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start); -+ } -+ } -+ -+ if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS) -+ grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr); - - grub_free(memory_map); - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index 04994d5c67..70a0075ec5 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -71,20 +71,25 @@ finalize_params_linux (void) - { - grub_efi_loaded_image_t *loaded_image = NULL; - int node, retval, len; -- -+ grub_err_t err = GRUB_ERR_NONE; - void *fdt; - - fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); -- - if (!fdt) -- goto failure; -+ { -+ err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT"); -+ goto failure; -+ } - - node = grub_fdt_find_subnode (fdt, 0, "chosen"); - if (node < 0) - node = grub_fdt_add_subnode (fdt, 0, "chosen"); - - if (node < 1) -- goto failure; -+ { -+ err = grub_error(grub_errno, "failed to load chosen fdt node."); -+ goto failure; -+ } - - /* Set initrd info */ - if (initrd_start && initrd_end > initrd_start) -@@ -95,15 +100,26 @@ finalize_params_linux (void) - retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", - initrd_start); - if (retval) -- goto failure; -+ { -+ err = grub_error(retval, "Failed to set linux,initrd-start property"); -+ goto failure; -+ } -+ - retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", - initrd_end); - if (retval) -- goto failure; -+ { -+ err = grub_error(retval, "Failed to set linux,initrd-end property"); -+ goto failure; -+ } - } - -- if (grub_fdt_install() != GRUB_ERR_NONE) -- goto failure; -+ retval = grub_fdt_install(); -+ if (retval != GRUB_ERR_NONE) -+ { -+ err = grub_error(retval, "Failed to install fdt"); -+ goto failure; -+ } - - grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", - fdt); -@@ -111,14 +127,20 @@ finalize_params_linux (void) - /* Convert command line to UCS-2 */ - loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); - if (!loaded_image) -- goto failure; -+ { -+ err = grub_error(grub_errno, "Failed to install fdt"); -+ goto failure; -+ } - - loaded_image->load_options_size = len = - (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); - loaded_image->load_options = - grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); - if (!loaded_image->load_options) -- return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); -+ { -+ err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); -+ goto failure; -+ } - - loaded_image->load_options_size = - 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, -@@ -128,7 +150,7 @@ finalize_params_linux (void) - - failure: - grub_fdt_unload(); -- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); -+ return err; - } - - static void -@@ -212,16 +234,28 @@ grub_linux_unload (void) - static void * - allocate_initrd_mem (int initrd_pages) - { -- grub_addr_t max_addr; -+ grub_addr_t max_addr = 0; -+ grub_err_t err; -+ void *ret; - -- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) -- return NULL; -+ err = grub_efi_get_ram_base (&max_addr); -+ if (err != GRUB_ERR_NONE) -+ { -+ grub_error (err, "grub_efi_get_ram_base() failed"); -+ return NULL; -+ } -+ -+ grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n", -+ max_addr, INITRD_MAX_ADDRESS_OFFSET); - - max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; -+ grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages); - -- return grub_efi_allocate_pages_real (max_addr, initrd_pages, -- GRUB_EFI_ALLOCATE_MAX_ADDRESS, -- GRUB_EFI_LOADER_DATA); -+ ret = grub_efi_allocate_pages_real (max_addr, initrd_pages, -+ GRUB_EFI_ALLOCATE_MAX_ADDRESS, -+ GRUB_EFI_LOADER_DATA); -+ grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret); -+ return ret; - } - - static grub_err_t diff --git a/0100-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch b/0100-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch new file mode 100644 index 0000000..e94df4e --- /dev/null +++ b/0100-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch @@ -0,0 +1,199 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 18:03:25 +0200 +Subject: [PATCH] Attempt to fix up all the places -Wsign-compare=error finds. + +Signed-off-by: Peter Jones +--- + grub-core/kern/emu/misc.c | 2 +- + grub-core/lib/reed_solomon.c | 4 ++-- + grub-core/osdep/linux/blocklist.c | 2 +- + grub-core/osdep/linux/getroot.c | 2 +- + grub-core/osdep/linux/hostdisk.c | 2 +- + util/grub-fstest.c | 2 +- + util/grub-menulst2cfg.c | 2 +- + util/grub-mkfont.c | 13 +++++++------ + util/grub-probe.c | 2 +- + util/setup.c | 2 +- + 10 files changed, 17 insertions(+), 16 deletions(-) + +diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c +index eeea092752..f08a1bb841 100644 +--- a/grub-core/kern/emu/misc.c ++++ b/grub-core/kern/emu/misc.c +@@ -189,7 +189,7 @@ grub_util_get_image_size (const char *path) + sz = ftello (f); + if (sz < 0) + grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); +- if (sz != (size_t) sz) ++ if (sz > (off_t)(GRUB_SIZE_MAX >> 1)) + grub_util_error (_("file `%s' is too big"), path); + ret = (size_t) sz; + +diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c +index 467305b46a..79037c093f 100644 +--- a/grub-core/lib/reed_solomon.c ++++ b/grub-core/lib/reed_solomon.c +@@ -157,7 +157,7 @@ static void + rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) + { + gf_single_t *rs_polynomial; +- int i, j; ++ unsigned int i, j; + gf_single_t *m; + m = xcalloc (s + rs, sizeof (gf_single_t)); + grub_memcpy (m, data, s * sizeof (gf_single_t)); +@@ -324,7 +324,7 @@ static void + encode_block (gf_single_t *ptr, grub_size_t s, + gf_single_t *rptr, grub_size_t rs) + { +- int i, j; ++ unsigned int i, j; + for (i = 0; i < SECTOR_SIZE; i++) + { + grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; +diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c +index c77d6085cc..42a315031f 100644 +--- a/grub-core/osdep/linux/blocklist.c ++++ b/grub-core/osdep/linux/blocklist.c +@@ -109,7 +109,7 @@ grub_install_get_blocklist (grub_device_t root_dev, + else + { + struct fiemap *fie2; +- int i; ++ unsigned int i; + fie2 = xmalloc (sizeof (*fie2) + + fie1.fm_mapped_extents + * sizeof (fie1.fm_extents[1])); +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 28790307e0..9f730b3518 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -236,7 +236,7 @@ grub_find_root_devices_from_btrfs (const char *dir) + { + int fd; + struct btrfs_ioctl_fs_info_args fsi; +- int i, j = 0; ++ unsigned int i, j = 0; + char **ret; + + fd = open (dir, 0); +diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c +index da62f924e3..7bc99ac1c1 100644 +--- a/grub-core/osdep/linux/hostdisk.c ++++ b/grub-core/osdep/linux/hostdisk.c +@@ -83,7 +83,7 @@ grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_sec + if (sector_size & (sector_size - 1) || !sector_size) + return -1; + for (log_sector_size = 0; +- (1 << log_sector_size) < sector_size; ++ (1U << log_sector_size) < sector_size; + log_sector_size++); + + if (log_secsize) +diff --git a/util/grub-fstest.c b/util/grub-fstest.c +index 8386564200..bfcef852d8 100644 +--- a/util/grub-fstest.c ++++ b/util/grub-fstest.c +@@ -323,7 +323,7 @@ cmd_cmp (char *src, char *dest) + read_file (src, cmp_hook, ff); + + { +- grub_uint64_t pre; ++ long long pre; + pre = ftell (ff); + fseek (ff, 0, SEEK_END); + if (pre != ftell (ff)) +diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c +index a39f869394..358d604210 100644 +--- a/util/grub-menulst2cfg.c ++++ b/util/grub-menulst2cfg.c +@@ -34,7 +34,7 @@ main (int argc, char **argv) + char *buf = NULL; + size_t bufsize = 0; + char *suffix = xstrdup (""); +- int suffixlen = 0; ++ size_t suffixlen = 0; + const char *out_fname = 0; + + grub_util_host_init (&argc, &argv); +diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c +index 0fe45a6103..3e09240b99 100644 +--- a/util/grub-mkfont.c ++++ b/util/grub-mkfont.c +@@ -138,7 +138,8 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + int width, height; + int cuttop, cutbottom, cutleft, cutright; + grub_uint8_t *data; +- int mask, i, j, bitmap_size; ++ int mask, i, bitmap_size; ++ unsigned int j; + FT_GlyphSlot glyph; + int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; + FT_Error err; +@@ -183,7 +184,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + cuttop = cutbottom = cutleft = cutright = 0; + else + { +- for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++) ++ for (cuttop = 0; cuttop < (long)glyph->bitmap.rows; cuttop++) + { + for (j = 0; j < glyph->bitmap.width; j++) + if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch] +@@ -203,10 +204,10 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + break; + } + cutbottom = glyph->bitmap.rows - 1 - cutbottom; +- if (cutbottom + cuttop >= glyph->bitmap.rows) ++ if (cutbottom + cuttop >= (long)glyph->bitmap.rows) + cutbottom = 0; + +- for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++) ++ for (cutleft = 0; cutleft < (long)glyph->bitmap.width; cutleft++) + { + for (j = 0; j < glyph->bitmap.rows; j++) + if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch] +@@ -225,7 +226,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + break; + } + cutright = glyph->bitmap.width - 1 - cutright; +- if (cutright + cutleft >= glyph->bitmap.width) ++ if (cutright + cutleft >= (long)glyph->bitmap.width) + cutright = 0; + } + +@@ -262,7 +263,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + + mask = 0; + data = &glyph_info->bitmap[0] - 1; +- for (j = cuttop; j < height + cuttop; j++) ++ for (j = cuttop; j < (long)height + cuttop; j++) + for (i = cutleft; i < width + cutleft; i++) + add_pixel (&data, &mask, + glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & +diff --git a/util/grub-probe.c b/util/grub-probe.c +index c08e46bbb4..c6fac732b4 100644 +--- a/util/grub-probe.c ++++ b/util/grub-probe.c +@@ -798,7 +798,7 @@ argp_parser (int key, char *arg, struct argp_state *state) + + case 't': + { +- int i; ++ unsigned int i; + + for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++) + if (strcmp (arg, targets[i]) == 0) +diff --git a/util/setup.c b/util/setup.c +index da5f2c07f5..8b22bb8cca 100644 +--- a/util/setup.c ++++ b/util/setup.c +@@ -406,7 +406,7 @@ SETUP (const char *dir, + int is_ldm; + grub_err_t err; + grub_disk_addr_t *sectors; +- int i; ++ unsigned int i; + grub_fs_t fs; + unsigned int nsec, maxsec; + diff --git a/0100-Try-to-pick-better-locations-for-kernel-and-initrd.patch b/0100-Try-to-pick-better-locations-for-kernel-and-initrd.patch deleted file mode 100644 index 4f42ea5..0000000 --- a/0100-Try-to-pick-better-locations-for-kernel-and-initrd.patch +++ /dev/null @@ -1,211 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 11 Jul 2019 17:17:02 +0200 -Subject: [PATCH] Try to pick better locations for kernel and initrd - -- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if - we're using the "large" code model ; use __UINTPTR_MAX__. -- Get the comparison right to check the address we've allocated. -- Fix the allocation for the command line as well. - -*But*, when we did this some systems started failing badly; coudln't -parse partition tables, etc. What's going on here is the disk controller -is silently failing DMAs to addresses above 4GB, so we're trying to parse -uninitialized (or HW zeroed) ram when looking for the partition table, -etc. - -So to limit this, we make grub_malloc() pick addresses below 4GB on -x86_64, but the direct EFI page allocation functions can get addresses -above that. - -Additionally, we now try to locate kernel+initrd+cmdline+etc below -0x7fffffff, and if they're too big to fit any memory window there, then -we try a higher address. - -Signed-off-by: Peter Jones -[david.abdurachmanov: fix macro for riscv64] -Signed-off-by: David Abdurachmanov -Signed-off-by: Robbie Harwood ---- - grub-core/kern/efi/mm.c | 8 ++++---- - grub-core/loader/i386/efi/linux.c | 24 +++++++++++++++++------- - include/grub/arm/efi/memory.h | 1 + - include/grub/arm64/efi/memory.h | 1 + - include/grub/i386/efi/memory.h | 1 + - include/grub/ia64/efi/memory.h | 1 + - include/grub/riscv64/efi/memory.h | 1 + - include/grub/x86_64/efi/memory.h | 4 +++- - 8 files changed, 29 insertions(+), 12 deletions(-) - -diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c -index 85ad4b4494..e84961d078 100644 ---- a/grub-core/kern/efi/mm.c -+++ b/grub-core/kern/efi/mm.c -@@ -122,7 +122,7 @@ grub_efi_allocate_pages_max (grub_efi_physical_address_t max, - grub_efi_boot_services_t *b; - grub_efi_physical_address_t address = max; - -- if (max > 0xffffffff) -+ if (max > GRUB_EFI_MAX_USABLE_ADDRESS) - return 0; - - b = grub_efi_system_table->boot_services; -@@ -480,7 +480,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, - { - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - #if 1 -- && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS -+ && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS - #endif - && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 - && desc->num_pages != 0) -@@ -498,9 +498,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, - #if 1 - if (BYTES_TO_PAGES (filtered_desc->physical_start) - + filtered_desc->num_pages -- > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)) -+ > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) - filtered_desc->num_pages -- = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS) -+ = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS) - - BYTES_TO_PAGES (filtered_desc->physical_start)); - #endif - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 3017d0f3e5..33e981e76e 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -106,7 +107,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - size += ALIGN_UP (grub_file_size (files[i]), 4); - } - -- initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); -+ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); -+ if (!initrd_mem) -+ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); - if (!initrd_mem) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); -@@ -202,8 +205,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -- params = grub_efi_allocate_pages_max (0x3fffffff, -+ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, - BYTES_TO_PAGES(sizeof(*params))); -+ if (!params) -+ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, -+ BYTES_TO_PAGES(sizeof(*params))); - if (! params) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); -@@ -273,8 +279,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - #endif - - grub_dprintf ("linux", "setting up cmdline\n"); -- linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, -- BYTES_TO_PAGES(lh->cmdline_size + 1)); -+ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, -+ BYTES_TO_PAGES(lh->cmdline_size + 1)); -+ if (!linux_cmdline) -+ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, -+ BYTES_TO_PAGES(lh->cmdline_size + 1)); - if (!linux_cmdline) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); -@@ -301,11 +310,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, - BYTES_TO_PAGES(lh->init_size)); -- - if (!kernel_mem) -- kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, -+ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, -+ BYTES_TO_PAGES(lh->init_size)); -+ if (!kernel_mem) -+ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, - BYTES_TO_PAGES(lh->init_size)); -- - if (!kernel_mem) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); -diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h -index 2c64918e3f..a4c2ec8350 100644 ---- a/include/grub/arm/efi/memory.h -+++ b/include/grub/arm/efi/memory.h -@@ -2,5 +2,6 @@ - #include - - #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS - - #endif /* ! GRUB_MEMORY_CPU_HEADER */ -diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h -index c6cb324171..acb61dca44 100644 ---- a/include/grub/arm64/efi/memory.h -+++ b/include/grub/arm64/efi/memory.h -@@ -2,5 +2,6 @@ - #include - - #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS - - #endif /* ! GRUB_MEMORY_CPU_HEADER */ -diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h -index 2c64918e3f..a4c2ec8350 100644 ---- a/include/grub/i386/efi/memory.h -+++ b/include/grub/i386/efi/memory.h -@@ -2,5 +2,6 @@ - #include - - #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS - - #endif /* ! GRUB_MEMORY_CPU_HEADER */ -diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h -index 2c64918e3f..a4c2ec8350 100644 ---- a/include/grub/ia64/efi/memory.h -+++ b/include/grub/ia64/efi/memory.h -@@ -2,5 +2,6 @@ - #include - - #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS - - #endif /* ! GRUB_MEMORY_CPU_HEADER */ -diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h -index c6cb324171..acb61dca44 100644 ---- a/include/grub/riscv64/efi/memory.h -+++ b/include/grub/riscv64/efi/memory.h -@@ -2,5 +2,6 @@ - #include - - #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS - - #endif /* ! GRUB_MEMORY_CPU_HEADER */ -diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h -index 46e9145a30..e81cfb3221 100644 ---- a/include/grub/x86_64/efi/memory.h -+++ b/include/grub/x86_64/efi/memory.h -@@ -2,9 +2,11 @@ - #include - - #if defined (__code_model_large__) --#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff -+#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__ -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff - #else - #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS - #endif - - #endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/0101-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch b/0101-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch deleted file mode 100644 index 3ebf4b3..0000000 --- a/0101-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch +++ /dev/null @@ -1,213 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 11 Jul 2019 18:03:25 +0200 -Subject: [PATCH] Attempt to fix up all the places -Wsign-compare=error finds. - -Signed-off-by: Peter Jones ---- - grub-core/kern/emu/misc.c | 2 +- - grub-core/lib/reed_solomon.c | 4 ++-- - grub-core/osdep/linux/blocklist.c | 2 +- - grub-core/osdep/linux/getroot.c | 2 +- - grub-core/osdep/linux/hostdisk.c | 2 +- - util/grub-fstest.c | 2 +- - util/grub-menulst2cfg.c | 2 +- - util/grub-mkfont.c | 13 +++++++------ - util/grub-probe.c | 2 +- - util/grub-rpm-sort.c | 2 +- - util/setup.c | 2 +- - 11 files changed, 18 insertions(+), 17 deletions(-) - -diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c -index eeea092752..f08a1bb841 100644 ---- a/grub-core/kern/emu/misc.c -+++ b/grub-core/kern/emu/misc.c -@@ -189,7 +189,7 @@ grub_util_get_image_size (const char *path) - sz = ftello (f); - if (sz < 0) - grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); -- if (sz != (size_t) sz) -+ if (sz > (off_t)(GRUB_SIZE_MAX >> 1)) - grub_util_error (_("file `%s' is too big"), path); - ret = (size_t) sz; - -diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c -index 467305b46a..79037c093f 100644 ---- a/grub-core/lib/reed_solomon.c -+++ b/grub-core/lib/reed_solomon.c -@@ -157,7 +157,7 @@ static void - rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) - { - gf_single_t *rs_polynomial; -- int i, j; -+ unsigned int i, j; - gf_single_t *m; - m = xcalloc (s + rs, sizeof (gf_single_t)); - grub_memcpy (m, data, s * sizeof (gf_single_t)); -@@ -324,7 +324,7 @@ static void - encode_block (gf_single_t *ptr, grub_size_t s, - gf_single_t *rptr, grub_size_t rs) - { -- int i, j; -+ unsigned int i, j; - for (i = 0; i < SECTOR_SIZE; i++) - { - grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; -diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c -index c77d6085cc..42a315031f 100644 ---- a/grub-core/osdep/linux/blocklist.c -+++ b/grub-core/osdep/linux/blocklist.c -@@ -109,7 +109,7 @@ grub_install_get_blocklist (grub_device_t root_dev, - else - { - struct fiemap *fie2; -- int i; -+ unsigned int i; - fie2 = xmalloc (sizeof (*fie2) - + fie1.fm_mapped_extents - * sizeof (fie1.fm_extents[1])); -diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c -index 28790307e0..9f730b3518 100644 ---- a/grub-core/osdep/linux/getroot.c -+++ b/grub-core/osdep/linux/getroot.c -@@ -236,7 +236,7 @@ grub_find_root_devices_from_btrfs (const char *dir) - { - int fd; - struct btrfs_ioctl_fs_info_args fsi; -- int i, j = 0; -+ unsigned int i, j = 0; - char **ret; - - fd = open (dir, 0); -diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c -index da62f924e3..7bc99ac1c1 100644 ---- a/grub-core/osdep/linux/hostdisk.c -+++ b/grub-core/osdep/linux/hostdisk.c -@@ -83,7 +83,7 @@ grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_sec - if (sector_size & (sector_size - 1) || !sector_size) - return -1; - for (log_sector_size = 0; -- (1 << log_sector_size) < sector_size; -+ (1U << log_sector_size) < sector_size; - log_sector_size++); - - if (log_secsize) -diff --git a/util/grub-fstest.c b/util/grub-fstest.c -index 8386564200..bfcef852d8 100644 ---- a/util/grub-fstest.c -+++ b/util/grub-fstest.c -@@ -323,7 +323,7 @@ cmd_cmp (char *src, char *dest) - read_file (src, cmp_hook, ff); - - { -- grub_uint64_t pre; -+ long long pre; - pre = ftell (ff); - fseek (ff, 0, SEEK_END); - if (pre != ftell (ff)) -diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c -index a39f869394..358d604210 100644 ---- a/util/grub-menulst2cfg.c -+++ b/util/grub-menulst2cfg.c -@@ -34,7 +34,7 @@ main (int argc, char **argv) - char *buf = NULL; - size_t bufsize = 0; - char *suffix = xstrdup (""); -- int suffixlen = 0; -+ size_t suffixlen = 0; - const char *out_fname = 0; - - grub_util_host_init (&argc, &argv); -diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c -index 0fe45a6103..3e09240b99 100644 ---- a/util/grub-mkfont.c -+++ b/util/grub-mkfont.c -@@ -138,7 +138,8 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, - int width, height; - int cuttop, cutbottom, cutleft, cutright; - grub_uint8_t *data; -- int mask, i, j, bitmap_size; -+ int mask, i, bitmap_size; -+ unsigned int j; - FT_GlyphSlot glyph; - int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; - FT_Error err; -@@ -183,7 +184,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, - cuttop = cutbottom = cutleft = cutright = 0; - else - { -- for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++) -+ for (cuttop = 0; cuttop < (long)glyph->bitmap.rows; cuttop++) - { - for (j = 0; j < glyph->bitmap.width; j++) - if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch] -@@ -203,10 +204,10 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, - break; - } - cutbottom = glyph->bitmap.rows - 1 - cutbottom; -- if (cutbottom + cuttop >= glyph->bitmap.rows) -+ if (cutbottom + cuttop >= (long)glyph->bitmap.rows) - cutbottom = 0; - -- for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++) -+ for (cutleft = 0; cutleft < (long)glyph->bitmap.width; cutleft++) - { - for (j = 0; j < glyph->bitmap.rows; j++) - if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch] -@@ -225,7 +226,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, - break; - } - cutright = glyph->bitmap.width - 1 - cutright; -- if (cutright + cutleft >= glyph->bitmap.width) -+ if (cutright + cutleft >= (long)glyph->bitmap.width) - cutright = 0; - } - -@@ -262,7 +263,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, - - mask = 0; - data = &glyph_info->bitmap[0] - 1; -- for (j = cuttop; j < height + cuttop; j++) -+ for (j = cuttop; j < (long)height + cuttop; j++) - for (i = cutleft; i < width + cutleft; i++) - add_pixel (&data, &mask, - glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & -diff --git a/util/grub-probe.c b/util/grub-probe.c -index c08e46bbb4..c6fac732b4 100644 ---- a/util/grub-probe.c -+++ b/util/grub-probe.c -@@ -798,7 +798,7 @@ argp_parser (int key, char *arg, struct argp_state *state) - - case 't': - { -- int i; -+ unsigned int i; - - for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++) - if (strcmp (arg, targets[i]) == 0) -diff --git a/util/grub-rpm-sort.c b/util/grub-rpm-sort.c -index f33bd1ed56..8345944105 100644 ---- a/util/grub-rpm-sort.c -+++ b/util/grub-rpm-sort.c -@@ -232,7 +232,7 @@ main (int argc, char *argv[]) - struct arguments arguments; - char **package_names = NULL; - size_t n_package_names = 0; -- int i; -+ unsigned int i; - - grub_util_host_init (&argc, &argv); - -diff --git a/util/setup.c b/util/setup.c -index da5f2c07f5..8b22bb8cca 100644 ---- a/util/setup.c -+++ b/util/setup.c -@@ -406,7 +406,7 @@ SETUP (const char *dir, - int is_ldm; - grub_err_t err; - grub_disk_addr_t *sectors; -- int i; -+ unsigned int i; - grub_fs_t fs; - unsigned int nsec, maxsec; - diff --git a/0101-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch b/0101-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch new file mode 100644 index 0000000..03b4bbf --- /dev/null +++ b/0101-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 18:20:37 +0200 +Subject: [PATCH] Don't use -Wno-sign-compare -Wno-conversion -Wno-error, do + use -Wextra. + +Signed-off-by: Peter Jones +--- + configure.ac | 14 +++++++++++--- + conf/Makefile.common | 2 +- + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 7b4e1854d3..490353713a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1452,11 +1452,11 @@ fi + # Set them to their new values for the tests below. + CC="$TARGET_CC" + if test x"$platform" = xemu ; then +-CFLAGS="$TARGET_CFLAGS -Wno-error" ++CFLAGS="$TARGET_CFLAGS" + elif test "x$TARGET_APPLE_LINKER" = x1 ; then +-CFLAGS="$TARGET_CFLAGS -nostdlib -static -Wno-error" ++CFLAGS="$TARGET_CFLAGS -nostdlib -static" + else +-CFLAGS="$TARGET_CFLAGS -nostdlib -Wno-error" ++CFLAGS="$TARGET_CFLAGS -nostdlib" + fi + CPPFLAGS="$TARGET_CPPFLAGS" + +@@ -1990,6 +1990,14 @@ if test x"$enable_werror" != xno ; then + HOST_CFLAGS="$HOST_CFLAGS -Werror" + fi + ++AC_ARG_ENABLE([wextra], ++ [AS_HELP_STRING([--disable-wextra], ++ [do not use -Wextra when building GRUB])]) ++if test x"$enable_wextra" != xno ; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -Wextra" ++ HOST_CFLAGS="$HOST_CFLAGS -Wextra" ++fi ++ + TARGET_CPP="$TARGET_CC -E" + TARGET_CCAS=$TARGET_CC + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 2ff9b39357..35e14ff017 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d + platformdir = $(pkglibdir)/$(target_cpu)-$(platform) + starfielddir = $(pkgdatadir)/themes/starfield + +-CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion ++CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code + CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib + + CFLAGS_POSIX = -fno-builtin diff --git a/0102-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch b/0102-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch deleted file mode 100644 index 6e18f66..0000000 --- a/0102-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 11 Jul 2019 18:20:37 +0200 -Subject: [PATCH] Don't use -Wno-sign-compare -Wno-conversion -Wno-error, do - use -Wextra. - -Signed-off-by: Peter Jones ---- - configure.ac | 14 +++++++++++--- - conf/Makefile.common | 2 +- - 2 files changed, 12 insertions(+), 4 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 2af5f23adf..091ab32836 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1453,11 +1453,11 @@ fi - # Set them to their new values for the tests below. - CC="$TARGET_CC" - if test x"$platform" = xemu ; then --CFLAGS="$TARGET_CFLAGS -Wno-error" -+CFLAGS="$TARGET_CFLAGS" - elif test "x$TARGET_APPLE_LINKER" = x1 ; then --CFLAGS="$TARGET_CFLAGS -nostdlib -static -Wno-error" -+CFLAGS="$TARGET_CFLAGS -nostdlib -static" - else --CFLAGS="$TARGET_CFLAGS -nostdlib -Wno-error" -+CFLAGS="$TARGET_CFLAGS -nostdlib" - fi - CPPFLAGS="$TARGET_CPPFLAGS" - -@@ -2020,6 +2020,14 @@ if test x"$enable_werror" != xno ; then - HOST_CFLAGS="$HOST_CFLAGS -Werror" - fi - -+AC_ARG_ENABLE([wextra], -+ [AS_HELP_STRING([--disable-wextra], -+ [do not use -Wextra when building GRUB])]) -+if test x"$enable_wextra" != xno ; then -+ TARGET_CFLAGS="$TARGET_CFLAGS -Wextra" -+ HOST_CFLAGS="$HOST_CFLAGS -Wextra" -+fi -+ - TARGET_CPP="$TARGET_CC -E" - TARGET_CCAS=$TARGET_CC - -diff --git a/conf/Makefile.common b/conf/Makefile.common -index 2ff9b39357..35e14ff017 100644 ---- a/conf/Makefile.common -+++ b/conf/Makefile.common -@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d - platformdir = $(pkglibdir)/$(target_cpu)-$(platform) - starfielddir = $(pkgdatadir)/themes/starfield - --CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion -+CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code - CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib - - CFLAGS_POSIX = -fno-builtin diff --git a/0102-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch b/0102-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch new file mode 100644 index 0000000..5a9c6f2 --- /dev/null +++ b/0102-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 12 Jul 2019 09:53:32 +0200 +Subject: [PATCH] x86-efi: Use bounce buffers for reading to addresses > 4GB + +Lots of machines apparently can't DMA correctly above 4GB during UEFI, +so use bounce buffers for the initramfs read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 52 +++++++++++++++++++++++++++++++++------ + 1 file changed, 45 insertions(+), 7 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 33e981e76e..2f0336809e 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -35,11 +35,16 @@ static grub_dl_t my_mod; + static int loaded; + static void *kernel_mem; + static grub_uint64_t kernel_size; +-static grub_uint8_t *initrd_mem; ++static void *initrd_mem; + static grub_uint32_t handover_offset; + struct linux_kernel_params *params; + static char *linux_cmdline; + ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + + static grub_err_t +@@ -73,6 +78,44 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + ++#define BOUNCE_BUFFER_MAX 0x10000000ull ++ ++static grub_ssize_t ++read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) ++{ ++ grub_ssize_t bufpos = 0; ++ static grub_size_t bbufsz = 0; ++ static char *bbuf = NULL; ++ ++ if (bbufsz == 0) ++ bbufsz = MIN(BOUNCE_BUFFER_MAX, len); ++ ++ while (!bbuf && bbufsz) ++ { ++ bbuf = grub_malloc(bbufsz); ++ if (!bbuf) ++ bbufsz >>= 1; ++ } ++ if (!bbuf) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); ++ ++ while (bufpos < (long long)len) ++ { ++ grub_ssize_t sz; ++ ++ sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); ++ if (sz < 0) ++ return sz; ++ if (sz == 0) ++ break; ++ ++ grub_memcpy(bufp + bufpos, bbuf, sz); ++ bufpos += sz; ++ } ++ ++ return bufpos; ++} ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -126,7 +169,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + for (i = 0; i < nfiles; i++) + { + grub_ssize_t cursize = grub_file_size (files[i]); +- if (grub_file_read (files[i], ptr, cursize) != cursize) ++ if (read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), +@@ -152,11 +195,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) diff --git a/0103-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch b/0103-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch new file mode 100644 index 0000000..9b10d68 --- /dev/null +++ b/0103-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 13 Sep 2018 14:42:34 -0400 +Subject: [PATCH] x86-efi: Re-arrange grub_cmd_linux() a little bit. + +This just helps the next patch be easier to read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 75 +++++++++++++++++++++------------------ + 1 file changed, 41 insertions(+), 34 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 2f0336809e..5f48fa5561 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -243,32 +243,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } ++ lh = (struct linux_i386_kernel_header *)kernel; ++ grub_dprintf ("linux", "original lh is at %p\n", kernel); + +- grub_dprintf ("linux", "params = %p\n", params); +- +- grub_memset (params, 0, sizeof(*params)); +- +- setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); +- grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", +- MIN((grub_size_t)0x202+setup_header_end_offset, +- sizeof (*params)) - 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- (grub_uint8_t *)params + 0x1f1); +- grub_memcpy ((grub_uint8_t *)params + 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); +- lh = (struct linux_i386_kernel_header *)params; +- grub_dprintf ("linux", "lh is at %p\n", lh); + grub_dprintf ("linux", "checking lh->boot_flag\n"); + if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) + { +@@ -316,6 +293,34 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (! params) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "params = %p\n", params); ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "new lh is at %p\n", lh); ++ + grub_dprintf ("linux", "setting up cmdline\n"); + linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(lh->cmdline_size + 1)); +@@ -341,8 +346,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); + lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; + +- grub_dprintf ("linux", "computing handover offset\n"); + handover_offset = lh->handover_offset; ++ grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +@@ -359,26 +364,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); + goto fail; + } +- +- grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- loaded=1; ++ ++ loaded = 1; ++ + grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); + lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +- grub_dprintf ("linux", "setting lh->type_of_loader\n"); + lh->type_of_loader = 0x6; ++ grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", ++ lh->type_of_loader); + +- grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); + params->ext_loader_type = 0; + params->ext_loader_ver = 2; +- grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", +- kernel_mem, handover_offset); ++ grub_dprintf ("linux", ++ "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", ++ params->ext_loader_type, params->ext_loader_ver); + +- fail: ++fail: + if (file) + grub_file_close (file); + diff --git a/0103-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch b/0103-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch deleted file mode 100644 index 5a9c6f2..0000000 --- a/0103-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 12 Jul 2019 09:53:32 +0200 -Subject: [PATCH] x86-efi: Use bounce buffers for reading to addresses > 4GB - -Lots of machines apparently can't DMA correctly above 4GB during UEFI, -so use bounce buffers for the initramfs read. - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 52 +++++++++++++++++++++++++++++++++------ - 1 file changed, 45 insertions(+), 7 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 33e981e76e..2f0336809e 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -35,11 +35,16 @@ static grub_dl_t my_mod; - static int loaded; - static void *kernel_mem; - static grub_uint64_t kernel_size; --static grub_uint8_t *initrd_mem; -+static void *initrd_mem; - static grub_uint32_t handover_offset; - struct linux_kernel_params *params; - static char *linux_cmdline; - -+#define MIN(a, b) \ -+ ({ typeof (a) _a = (a); \ -+ typeof (b) _b = (b); \ -+ _a < _b ? _a : _b; }) -+ - #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) - - static grub_err_t -@@ -73,6 +78,44 @@ grub_linuxefi_unload (void) - return GRUB_ERR_NONE; - } - -+#define BOUNCE_BUFFER_MAX 0x10000000ull -+ -+static grub_ssize_t -+read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) -+{ -+ grub_ssize_t bufpos = 0; -+ static grub_size_t bbufsz = 0; -+ static char *bbuf = NULL; -+ -+ if (bbufsz == 0) -+ bbufsz = MIN(BOUNCE_BUFFER_MAX, len); -+ -+ while (!bbuf && bbufsz) -+ { -+ bbuf = grub_malloc(bbufsz); -+ if (!bbuf) -+ bbufsz >>= 1; -+ } -+ if (!bbuf) -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); -+ -+ while (bufpos < (long long)len) -+ { -+ grub_ssize_t sz; -+ -+ sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); -+ if (sz < 0) -+ return sz; -+ if (sz == 0) -+ break; -+ -+ grub_memcpy(bufp + bufpos, bbuf, sz); -+ bufpos += sz; -+ } -+ -+ return bufpos; -+} -+ - static grub_err_t - grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -@@ -126,7 +169,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - for (i = 0; i < nfiles; i++) - { - grub_ssize_t cursize = grub_file_size (files[i]); -- if (grub_file_read (files[i], ptr, cursize) != cursize) -+ if (read (files[i], ptr, cursize) != cursize) - { - if (!grub_errno) - grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), -@@ -152,11 +195,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - return grub_errno; - } - --#define MIN(a, b) \ -- ({ typeof (a) _a = (a); \ -- typeof (b) _b = (b); \ -- _a < _b ? _a : _b; }) -- - static grub_err_t - grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) diff --git a/0104-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch b/0104-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch new file mode 100644 index 0000000..700c98b --- /dev/null +++ b/0104-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch @@ -0,0 +1,258 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:03:55 -0400 +Subject: [PATCH] x86-efi: Make our own allocator for kernel stuff + +This helps enable allocations above 4GB. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 167 +++++++++++++++++++++----------------- + 1 file changed, 94 insertions(+), 73 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 5f48fa5561..3e4f7ef39f 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -47,6 +47,65 @@ static char *linux_cmdline; + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + ++struct allocation_choice { ++ grub_efi_physical_address_t addr; ++ grub_efi_allocate_type_t alloc_type; ++}; ++ ++static struct allocation_choice max_addresses[] = ++ { ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { 0, 0 } ++ }; ++ ++static inline void ++kernel_free(void *addr, grub_efi_uintn_t size) ++{ ++ if (addr && size) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr, ++ BYTES_TO_PAGES(size)); ++} ++ ++static void * ++kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) ++{ ++ void *addr = 0; ++ unsigned int i; ++ grub_efi_physical_address_t prev_max = 0; ++ ++ for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++) ++ { ++ grub_uint64_t max = max_addresses[i].addr; ++ grub_efi_uintn_t pages; ++ ++ if (max == prev_max) ++ continue; ++ ++ pages = BYTES_TO_PAGES(size); ++ grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", ++ pages, (void *)max); ++ ++ prev_max = max; ++ addr = grub_efi_allocate_pages_real (max, pages, ++ max_addresses[i].alloc_type, ++ GRUB_EFI_LOADER_DATA); ++ if (addr) ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ } ++ ++ while (grub_error_pop ()) ++ { ++ ; ++ } ++ ++ if (addr == NULL) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg); ++ ++ return addr; ++} ++ + static grub_err_t + grub_linuxefi_boot (void) + { +@@ -62,19 +121,12 @@ grub_linuxefi_unload (void) + { + grub_dl_unref (my_mod); + loaded = 0; +- if (initrd_mem) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, +- BYTES_TO_PAGES(params->ramdisk_size)); +- if (linux_cmdline) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) +- linux_cmdline, +- BYTES_TO_PAGES(params->cmdline_size + 1)); +- if (kernel_mem) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, +- BYTES_TO_PAGES(kernel_size)); +- if (params) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, +- BYTES_TO_PAGES(16384)); ++ ++ kernel_free(initrd_mem, params->ramdisk_size); ++ kernel_free(linux_cmdline, params->cmdline_size + 1); ++ kernel_free(kernel_mem, kernel_size); ++ kernel_free(params, sizeof(*params)); ++ + return GRUB_ERR_NONE; + } + +@@ -150,19 +202,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +- goto fail; +- } +- +- grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem); ++ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (initrd_mem == NULL) ++ goto fail; ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + + params->ramdisk_size = size; +- params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; ++ params->ramdisk_image = initrd_mem; + + ptr = initrd_mem; + +@@ -221,7 +267,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + filelen = grub_file_size (file); + + kernel = grub_malloc(filelen); +- + if (!kernel) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); +@@ -274,7 +319,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +-#if defined(__x86_64__) || defined(__aarch64__) ++#if defined(__x86_64__) + grub_dprintf ("linux", "checking lh->xloadflags\n"); + if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) + { +@@ -293,17 +338,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); ++ params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } +- ++ goto fail; + grub_dprintf ("linux", "params = %p\n", params); + + grub_memset (params, 0, sizeof(*params)); +@@ -322,19 +359,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); + if (!linux_cmdline) +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); +- if (!linux_cmdline) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +- goto fail; +- } +- +- grub_dprintf ("linux", "linux_cmdline = %lx\n", +- (unsigned long)linux_cmdline); ++ goto fail; ++ grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); + + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, +@@ -343,27 +371,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + GRUB_VERIFY_KERNEL_CMDLINE); + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); +- grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); +- lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", ++ linux_cmdline); ++ lh->cmd_line_ptr = linux_cmdline; + + handover_offset = lh->handover_offset; +- grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); ++ grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +- kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) ++ grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); ++ if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +- goto fail; ++ max_addresses[0].addr = lh->pref_address; ++ max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ if (!kernel_mem) ++ goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +@@ -398,18 +423,14 @@ fail: + loaded = 0; + } + +- if (linux_cmdline && lh && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) +- linux_cmdline, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ if (!loaded) ++ { ++ if (lh) ++ kernel_free (linux_cmdline, lh->cmdline_size + 1); + +- if (kernel_mem && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, +- BYTES_TO_PAGES(kernel_size)); +- +- if (params && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, +- BYTES_TO_PAGES(16384)); ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); ++ } + + return grub_errno; + } diff --git a/0104-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch b/0104-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch deleted file mode 100644 index 9b10d68..0000000 --- a/0104-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 13 Sep 2018 14:42:34 -0400 -Subject: [PATCH] x86-efi: Re-arrange grub_cmd_linux() a little bit. - -This just helps the next patch be easier to read. - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 75 +++++++++++++++++++++------------------ - 1 file changed, 41 insertions(+), 34 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 2f0336809e..5f48fa5561 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -243,32 +243,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, -- BYTES_TO_PAGES(sizeof(*params))); -- if (!params) -- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, -- BYTES_TO_PAGES(sizeof(*params))); -- if (! params) -- { -- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); -- goto fail; -- } -+ lh = (struct linux_i386_kernel_header *)kernel; -+ grub_dprintf ("linux", "original lh is at %p\n", kernel); - -- grub_dprintf ("linux", "params = %p\n", params); -- -- grub_memset (params, 0, sizeof(*params)); -- -- setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); -- grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", -- MIN((grub_size_t)0x202+setup_header_end_offset, -- sizeof (*params)) - 0x1f1, -- (grub_uint8_t *)kernel + 0x1f1, -- (grub_uint8_t *)params + 0x1f1); -- grub_memcpy ((grub_uint8_t *)params + 0x1f1, -- (grub_uint8_t *)kernel + 0x1f1, -- MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); -- lh = (struct linux_i386_kernel_header *)params; -- grub_dprintf ("linux", "lh is at %p\n", lh); - grub_dprintf ("linux", "checking lh->boot_flag\n"); - if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) - { -@@ -316,6 +293,34 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - #endif - -+ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, -+ BYTES_TO_PAGES(sizeof(*params))); -+ if (!params) -+ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, -+ BYTES_TO_PAGES(sizeof(*params))); -+ if (! params) -+ { -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); -+ goto fail; -+ } -+ -+ grub_dprintf ("linux", "params = %p\n", params); -+ -+ grub_memset (params, 0, sizeof(*params)); -+ -+ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); -+ grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", -+ MIN((grub_size_t)0x202+setup_header_end_offset, -+ sizeof (*params)) - 0x1f1, -+ (grub_uint8_t *)kernel + 0x1f1, -+ (grub_uint8_t *)params + 0x1f1); -+ grub_memcpy ((grub_uint8_t *)params + 0x1f1, -+ (grub_uint8_t *)kernel + 0x1f1, -+ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); -+ -+ lh = (struct linux_i386_kernel_header *)params; -+ grub_dprintf ("linux", "new lh is at %p\n", lh); -+ - grub_dprintf ("linux", "setting up cmdline\n"); - linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, - BYTES_TO_PAGES(lh->cmdline_size + 1)); -@@ -341,8 +346,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); - lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; - -- grub_dprintf ("linux", "computing handover offset\n"); - handover_offset = lh->handover_offset; -+ grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); - - start = (lh->setup_sects + 1) * 512; - -@@ -359,26 +364,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); - goto fail; - } -- -- grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); -+ grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); - - grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); -- loaded=1; -+ -+ loaded = 1; -+ - grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); - lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; - - grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); - -- grub_dprintf ("linux", "setting lh->type_of_loader\n"); - lh->type_of_loader = 0x6; -+ grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", -+ lh->type_of_loader); - -- grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); - params->ext_loader_type = 0; - params->ext_loader_ver = 2; -- grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", -- kernel_mem, handover_offset); -+ grub_dprintf ("linux", -+ "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", -+ params->ext_loader_type, params->ext_loader_ver); - -- fail: -+fail: - if (file) - grub_file_close (file); - diff --git a/0105-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch b/0105-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch new file mode 100644 index 0000000..6ac11a1 --- /dev/null +++ b/0105-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch @@ -0,0 +1,171 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:12:27 -0400 +Subject: [PATCH] x86-efi: Allow initrd+params+cmdline allocations above 4GB. + +This enables everything except the kernel itself to be above 4GB. +Putting the kernel up there still doesn't work, because of the way +params->code32_start is used. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++++++++++---- + include/grub/i386/linux.h | 6 +++- + 2 files changed, 65 insertions(+), 8 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 3e4f7ef39f..6bc18d5aef 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -52,13 +52,22 @@ struct allocation_choice { + grub_efi_allocate_type_t alloc_type; + }; + +-static struct allocation_choice max_addresses[] = ++static struct allocation_choice max_addresses[4] = + { ++ /* the kernel overrides this one with pref_address and ++ * GRUB_EFI_ALLOCATE_ADDRESS */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this one is always below 4GB, which we still *prefer* even if the flag ++ * is set. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* If the flag in params is set, this one gets changed to be above 4GB. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { 0, 0 } + }; ++static struct allocation_choice saved_addresses[4]; ++ ++#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) ++#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) + + static inline void + kernel_free(void *addr, grub_efi_uintn_t size) +@@ -80,6 +89,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + grub_uint64_t max = max_addresses[i].addr; + grub_efi_uintn_t pages; + ++ /* ++ * When we're *not* loading the kernel, or >4GB allocations aren't ++ * supported, these entries are basically all the same, so don't re-try ++ * the same parameters. ++ */ + if (max == prev_max) + continue; + +@@ -168,6 +182,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) + return bufpos; + } + ++#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull)) ++#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -207,8 +224,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + +- params->ramdisk_size = size; +- params->ramdisk_image = initrd_mem; ++ params->ramdisk_size = LOW_U32(size); ++ params->ramdisk_image = LOW_U32(initrd_mem); ++#if defined(__x86_64__) ++ params->ext_ramdisk_size = HIGH_U32(size); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++#endif + + ptr = initrd_mem; + +@@ -338,6 +359,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++#if defined(__x86_64__) ++ if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); ++ max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ } ++ else ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n"); ++ } ++#endif ++ + params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -372,21 +405,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", +- linux_cmdline); +- lh->cmd_line_ptr = linux_cmdline; ++ LOW_U32(linux_cmdline)); ++ lh->cmd_line_ptr = LOW_U32(linux_cmdline); ++#if defined(__x86_64__) ++ if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) ++ { ++ grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", ++ HIGH_U32(linux_cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); ++ } ++#endif + + handover_offset = lh->handover_offset; + grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + ++ /* ++ * AFAICS >4GB for kernel *cannot* work because of params->code32_start being ++ * 32-bit and getting called unconditionally in head_64.S from either entry ++ * point. ++ * ++ * so nerf that out here... ++ */ ++ save_addresses(); + grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); + if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { + max_addresses[0].addr = lh->pref_address; + max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ restore_addresses(); + if (!kernel_mem) + goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); +@@ -395,8 +447,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + loaded = 1; + +- grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); +- lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; ++ grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", ++ LOW_U32(kernel_mem)); ++ lh->code32_start = LOW_U32(kernel_mem); + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index 25ef52c04e..fac22476cc 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -236,7 +236,11 @@ struct linux_kernel_params + grub_uint32_t ofw_cif_handler; /* b8 */ + grub_uint32_t ofw_idt; /* bc */ + +- grub_uint8_t padding7[0x1b8 - 0xc0]; ++ grub_uint32_t ext_ramdisk_image; /* 0xc0 */ ++ grub_uint32_t ext_ramdisk_size; /* 0xc4 */ ++ grub_uint32_t ext_cmd_line_ptr; /* 0xc8 */ ++ ++ grub_uint8_t padding7[0x1b8 - 0xcc]; + + union + { diff --git a/0105-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch b/0105-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch deleted file mode 100644 index 700c98b..0000000 --- a/0105-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch +++ /dev/null @@ -1,258 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 12 Sep 2018 16:03:55 -0400 -Subject: [PATCH] x86-efi: Make our own allocator for kernel stuff - -This helps enable allocations above 4GB. - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 167 +++++++++++++++++++++----------------- - 1 file changed, 94 insertions(+), 73 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 5f48fa5561..3e4f7ef39f 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -47,6 +47,65 @@ static char *linux_cmdline; - - #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) - -+struct allocation_choice { -+ grub_efi_physical_address_t addr; -+ grub_efi_allocate_type_t alloc_type; -+}; -+ -+static struct allocation_choice max_addresses[] = -+ { -+ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ { 0, 0 } -+ }; -+ -+static inline void -+kernel_free(void *addr, grub_efi_uintn_t size) -+{ -+ if (addr && size) -+ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr, -+ BYTES_TO_PAGES(size)); -+} -+ -+static void * -+kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) -+{ -+ void *addr = 0; -+ unsigned int i; -+ grub_efi_physical_address_t prev_max = 0; -+ -+ for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++) -+ { -+ grub_uint64_t max = max_addresses[i].addr; -+ grub_efi_uintn_t pages; -+ -+ if (max == prev_max) -+ continue; -+ -+ pages = BYTES_TO_PAGES(size); -+ grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", -+ pages, (void *)max); -+ -+ prev_max = max; -+ addr = grub_efi_allocate_pages_real (max, pages, -+ max_addresses[i].alloc_type, -+ GRUB_EFI_LOADER_DATA); -+ if (addr) -+ grub_dprintf ("linux", "Allocated at %p\n", addr); -+ } -+ -+ while (grub_error_pop ()) -+ { -+ ; -+ } -+ -+ if (addr == NULL) -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg); -+ -+ return addr; -+} -+ - static grub_err_t - grub_linuxefi_boot (void) - { -@@ -62,19 +121,12 @@ grub_linuxefi_unload (void) - { - grub_dl_unref (my_mod); - loaded = 0; -- if (initrd_mem) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, -- BYTES_TO_PAGES(params->ramdisk_size)); -- if (linux_cmdline) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) -- linux_cmdline, -- BYTES_TO_PAGES(params->cmdline_size + 1)); -- if (kernel_mem) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, -- BYTES_TO_PAGES(kernel_size)); -- if (params) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, -- BYTES_TO_PAGES(16384)); -+ -+ kernel_free(initrd_mem, params->ramdisk_size); -+ kernel_free(linux_cmdline, params->cmdline_size + 1); -+ kernel_free(kernel_mem, kernel_size); -+ kernel_free(params, sizeof(*params)); -+ - return GRUB_ERR_NONE; - } - -@@ -150,19 +202,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - size += ALIGN_UP (grub_file_size (files[i]), 4); - } - -- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); -- if (!initrd_mem) -- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); -- if (!initrd_mem) -- { -- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); -- goto fail; -- } -- -- grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem); -+ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); -+ if (initrd_mem == NULL) -+ goto fail; -+ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); - - params->ramdisk_size = size; -- params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; -+ params->ramdisk_image = initrd_mem; - - ptr = initrd_mem; - -@@ -221,7 +267,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - filelen = grub_file_size (file); - - kernel = grub_malloc(filelen); -- - if (!kernel) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); -@@ -274,7 +319,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - --#if defined(__x86_64__) || defined(__aarch64__) -+#if defined(__x86_64__) - grub_dprintf ("linux", "checking lh->xloadflags\n"); - if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) - { -@@ -293,17 +338,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - #endif - -- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, -- BYTES_TO_PAGES(sizeof(*params))); -+ params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); - if (!params) -- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, -- BYTES_TO_PAGES(sizeof(*params))); -- if (! params) -- { -- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); -- goto fail; -- } -- -+ goto fail; - grub_dprintf ("linux", "params = %p\n", params); - - grub_memset (params, 0, sizeof(*params)); -@@ -322,19 +359,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_dprintf ("linux", "new lh is at %p\n", lh); - - grub_dprintf ("linux", "setting up cmdline\n"); -- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, -- BYTES_TO_PAGES(lh->cmdline_size + 1)); -+ linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); - if (!linux_cmdline) -- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, -- BYTES_TO_PAGES(lh->cmdline_size + 1)); -- if (!linux_cmdline) -- { -- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); -- goto fail; -- } -- -- grub_dprintf ("linux", "linux_cmdline = %lx\n", -- (unsigned long)linux_cmdline); -+ goto fail; -+ grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); - - grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, -@@ -343,27 +371,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - GRUB_VERIFY_KERNEL_CMDLINE); - - grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); -- grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); -- lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; -+ grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", -+ linux_cmdline); -+ lh->cmd_line_ptr = linux_cmdline; - - handover_offset = lh->handover_offset; -- grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); -+ grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); - - start = (lh->setup_sects + 1) * 512; - -- kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, -- BYTES_TO_PAGES(lh->init_size)); -- if (!kernel_mem) -- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, -- BYTES_TO_PAGES(lh->init_size)); -- if (!kernel_mem) -- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, -- BYTES_TO_PAGES(lh->init_size)); -- if (!kernel_mem) -+ grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); -+ if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) - { -- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); -- goto fail; -+ max_addresses[0].addr = lh->pref_address; -+ max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; - } -+ kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); -+ if (!kernel_mem) -+ goto fail; - grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); - - grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); -@@ -398,18 +423,14 @@ fail: - loaded = 0; - } - -- if (linux_cmdline && lh && !loaded) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) -- linux_cmdline, -- BYTES_TO_PAGES(lh->cmdline_size + 1)); -+ if (!loaded) -+ { -+ if (lh) -+ kernel_free (linux_cmdline, lh->cmdline_size + 1); - -- if (kernel_mem && !loaded) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, -- BYTES_TO_PAGES(kernel_size)); -- -- if (params && !loaded) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, -- BYTES_TO_PAGES(16384)); -+ kernel_free (kernel_mem, kernel_size); -+ kernel_free (params, sizeof(*params)); -+ } - - return grub_errno; - } diff --git a/0106-Fix-getroot.c-s-trampolines.patch b/0106-Fix-getroot.c-s-trampolines.patch new file mode 100644 index 0000000..e744b77 --- /dev/null +++ b/0106-Fix-getroot.c-s-trampolines.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 28 Sep 2018 15:42:19 -0400 +Subject: [PATCH] Fix getroot.c's trampolines. + +This makes the stack executable on most of the grub utilities, which is +bad, and rpmdiff complains about it. + +Signed-off-by: Peter Jones +--- + grub-core/osdep/linux/getroot.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 9f730b3518..f0c503f43d 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -1264,22 +1264,20 @@ grub_util_get_grub_dev_os (const char *os_dev) + return grub_dev; + } + ++static void *mp = NULL; ++static void ++btrfs_mount_path_hook(const char *m) ++{ ++ mp = strdup (m); ++} + + char * + grub_util_get_btrfs_subvol (const char *path, char **mount_path) + { +- char *mp = NULL; +- + if (mount_path) + *mount_path = NULL; + +- auto void +- mount_path_hook (const char *m) +- { +- mp = strdup (m); +- } +- +- grub_find_root_btrfs_mount_path_hook = mount_path_hook; ++ grub_find_root_btrfs_mount_path_hook = btrfs_mount_path_hook; + grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); + grub_find_root_btrfs_mount_path_hook = NULL; + diff --git a/0106-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch b/0106-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch deleted file mode 100644 index 6ac11a1..0000000 --- a/0106-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 12 Sep 2018 16:12:27 -0400 -Subject: [PATCH] x86-efi: Allow initrd+params+cmdline allocations above 4GB. - -This enables everything except the kernel itself to be above 4GB. -Putting the kernel up there still doesn't work, because of the way -params->code32_start is used. - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++++++++++---- - include/grub/i386/linux.h | 6 +++- - 2 files changed, 65 insertions(+), 8 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 3e4f7ef39f..6bc18d5aef 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -52,13 +52,22 @@ struct allocation_choice { - grub_efi_allocate_type_t alloc_type; - }; - --static struct allocation_choice max_addresses[] = -+static struct allocation_choice max_addresses[4] = - { -+ /* the kernel overrides this one with pref_address and -+ * GRUB_EFI_ALLOCATE_ADDRESS */ - { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ /* this one is always below 4GB, which we still *prefer* even if the flag -+ * is set. */ - { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ /* If the flag in params is set, this one gets changed to be above 4GB. */ - { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, - { 0, 0 } - }; -+static struct allocation_choice saved_addresses[4]; -+ -+#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) -+#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) - - static inline void - kernel_free(void *addr, grub_efi_uintn_t size) -@@ -80,6 +89,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) - grub_uint64_t max = max_addresses[i].addr; - grub_efi_uintn_t pages; - -+ /* -+ * When we're *not* loading the kernel, or >4GB allocations aren't -+ * supported, these entries are basically all the same, so don't re-try -+ * the same parameters. -+ */ - if (max == prev_max) - continue; - -@@ -168,6 +182,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) - return bufpos; - } - -+#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull)) -+#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) -+ - static grub_err_t - grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -@@ -207,8 +224,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - goto fail; - grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); - -- params->ramdisk_size = size; -- params->ramdisk_image = initrd_mem; -+ params->ramdisk_size = LOW_U32(size); -+ params->ramdisk_image = LOW_U32(initrd_mem); -+#if defined(__x86_64__) -+ params->ext_ramdisk_size = HIGH_U32(size); -+ params->ext_ramdisk_image = HIGH_U32(initrd_mem); -+#endif - - ptr = initrd_mem; - -@@ -338,6 +359,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - #endif - -+#if defined(__x86_64__) -+ if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) -+ { -+ grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); -+ max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; -+ } -+ else -+ { -+ grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n"); -+ } -+#endif -+ - params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); - if (!params) - goto fail; -@@ -372,21 +405,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); - grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", -- linux_cmdline); -- lh->cmd_line_ptr = linux_cmdline; -+ LOW_U32(linux_cmdline)); -+ lh->cmd_line_ptr = LOW_U32(linux_cmdline); -+#if defined(__x86_64__) -+ if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) -+ { -+ grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", -+ HIGH_U32(linux_cmdline)); -+ params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); -+ } -+#endif - - handover_offset = lh->handover_offset; - grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); - - start = (lh->setup_sects + 1) * 512; - -+ /* -+ * AFAICS >4GB for kernel *cannot* work because of params->code32_start being -+ * 32-bit and getting called unconditionally in head_64.S from either entry -+ * point. -+ * -+ * so nerf that out here... -+ */ -+ save_addresses(); - grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); - if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) - { - max_addresses[0].addr = lh->pref_address; - max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; - } -+ max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; -+ max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; - kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); -+ restore_addresses(); - if (!kernel_mem) - goto fail; - grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); -@@ -395,8 +447,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - loaded = 1; - -- grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); -- lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; -+ grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", -+ LOW_U32(kernel_mem)); -+ lh->code32_start = LOW_U32(kernel_mem); - - grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); - -diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h -index 25ef52c04e..fac22476cc 100644 ---- a/include/grub/i386/linux.h -+++ b/include/grub/i386/linux.h -@@ -236,7 +236,11 @@ struct linux_kernel_params - grub_uint32_t ofw_cif_handler; /* b8 */ - grub_uint32_t ofw_idt; /* bc */ - -- grub_uint8_t padding7[0x1b8 - 0xc0]; -+ grub_uint32_t ext_ramdisk_image; /* 0xc0 */ -+ grub_uint32_t ext_ramdisk_size; /* 0xc4 */ -+ grub_uint32_t ext_cmd_line_ptr; /* 0xc8 */ -+ -+ grub_uint8_t padding7[0x1b8 - 0xcc]; - - union - { diff --git a/0107-Do-not-allow-stack-trampolines-anywhere.patch b/0107-Do-not-allow-stack-trampolines-anywhere.patch new file mode 100644 index 0000000..658c7a4 --- /dev/null +++ b/0107-Do-not-allow-stack-trampolines-anywhere.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 12 Jul 2019 10:06:50 +0200 +Subject: [PATCH] Do not allow stack trampolines, anywhere. + +Signed-off-by: Peter Jones +--- + configure.ac | 3 +++ + conf/Makefile.common | 2 +- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 490353713a..a02d40a05b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1998,6 +1998,9 @@ if test x"$enable_wextra" != xno ; then + HOST_CFLAGS="$HOST_CFLAGS -Wextra" + fi + ++TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines" ++HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines" ++ + TARGET_CPP="$TARGET_CC -E" + TARGET_CCAS=$TARGET_CC + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 35e14ff017..0647c53b91 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d + platformdir = $(pkglibdir)/$(target_cpu)-$(platform) + starfielddir = $(pkgdatadir)/themes/starfield + +-CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code ++CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines + CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib + + CFLAGS_POSIX = -fno-builtin diff --git a/0107-Fix-getroot.c-s-trampolines.patch b/0107-Fix-getroot.c-s-trampolines.patch deleted file mode 100644 index e744b77..0000000 --- a/0107-Fix-getroot.c-s-trampolines.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 28 Sep 2018 15:42:19 -0400 -Subject: [PATCH] Fix getroot.c's trampolines. - -This makes the stack executable on most of the grub utilities, which is -bad, and rpmdiff complains about it. - -Signed-off-by: Peter Jones ---- - grub-core/osdep/linux/getroot.c | 16 +++++++--------- - 1 file changed, 7 insertions(+), 9 deletions(-) - -diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c -index 9f730b3518..f0c503f43d 100644 ---- a/grub-core/osdep/linux/getroot.c -+++ b/grub-core/osdep/linux/getroot.c -@@ -1264,22 +1264,20 @@ grub_util_get_grub_dev_os (const char *os_dev) - return grub_dev; - } - -+static void *mp = NULL; -+static void -+btrfs_mount_path_hook(const char *m) -+{ -+ mp = strdup (m); -+} - - char * - grub_util_get_btrfs_subvol (const char *path, char **mount_path) - { -- char *mp = NULL; -- - if (mount_path) - *mount_path = NULL; - -- auto void -- mount_path_hook (const char *m) -- { -- mp = strdup (m); -- } -- -- grub_find_root_btrfs_mount_path_hook = mount_path_hook; -+ grub_find_root_btrfs_mount_path_hook = btrfs_mount_path_hook; - grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); - grub_find_root_btrfs_mount_path_hook = NULL; - diff --git a/0108-Do-not-allow-stack-trampolines-anywhere.patch b/0108-Do-not-allow-stack-trampolines-anywhere.patch deleted file mode 100644 index 08995fc..0000000 --- a/0108-Do-not-allow-stack-trampolines-anywhere.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 12 Jul 2019 10:06:50 +0200 -Subject: [PATCH] Do not allow stack trampolines, anywhere. - -Signed-off-by: Peter Jones ---- - configure.ac | 3 +++ - conf/Makefile.common | 2 +- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 091ab32836..de707f7e0b 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2028,6 +2028,9 @@ if test x"$enable_wextra" != xno ; then - HOST_CFLAGS="$HOST_CFLAGS -Wextra" - fi - -+TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines" -+HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines" -+ - TARGET_CPP="$TARGET_CC -E" - TARGET_CCAS=$TARGET_CC - -diff --git a/conf/Makefile.common b/conf/Makefile.common -index 35e14ff017..0647c53b91 100644 ---- a/conf/Makefile.common -+++ b/conf/Makefile.common -@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d - platformdir = $(pkglibdir)/$(target_cpu)-$(platform) - starfielddir = $(pkgdatadir)/themes/starfield - --CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -+CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines - CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib - - CFLAGS_POSIX = -fno-builtin diff --git a/0108-Reimplement-boot_counter.patch b/0108-Reimplement-boot_counter.patch new file mode 100644 index 0000000..6104b87 --- /dev/null +++ b/0108-Reimplement-boot_counter.patch @@ -0,0 +1,196 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 4 Oct 2018 14:22:09 -0400 +Subject: [PATCH] Reimplement boot_counter + +This adds "increment" and "decrement" commands, and uses them to maintain our +variables in 01_fallback_counter. It also simplifies the counter logic, so +that there are no nested tests that conflict with each other. + +Apparently, this *really* wasn't tested well enough. + +Resolves: rhbz#1614637 +Signed-off-by: Peter Jones +[lorbus: add comments and revert logic changes in 01_fallback_counting] +Signed-off-by: Christian Glombek +--- + Makefile.util.def | 6 +++ + grub-core/Makefile.core.def | 5 ++ + grub-core/commands/increment.c | 105 ++++++++++++++++++++++++++++++++++++ + util/grub.d/01_fallback_counting.in | 22 ++++++++ + 4 files changed, 138 insertions(+) + create mode 100644 grub-core/commands/increment.c + create mode 100644 util/grub.d/01_fallback_counting.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index d066652e9b..e10fe766d1 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -458,6 +458,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '01_fallback_counting'; ++ common = util/grub.d/01_fallback_counting.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '01_menu_auto_hide'; + common = util/grub.d/01_menu_auto_hide.in; +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 498ca11762..1e15345107 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -398,6 +398,11 @@ kernel = { + extra_dist = kern/mips/cache_flush.S; + }; + ++module = { ++ name = increment; ++ common = commands/increment.c; ++}; ++ + program = { + name = grub-emu; + mansection = 1; +diff --git a/grub-core/commands/increment.c b/grub-core/commands/increment.c +new file mode 100644 +index 0000000000..79cf137656 +--- /dev/null ++++ b/grub-core/commands/increment.c +@@ -0,0 +1,105 @@ ++/* increment.c - Commands to increment and decrement variables. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef enum { ++ INCREMENT, ++ DECREMENT, ++} operation; ++ ++static grub_err_t ++incr_decr(operation op, int argc, char **args) ++{ ++ const char *old; ++ char *new; ++ long value; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no variable specified")); ++ if (argc > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("too many arguments")); ++ ++ old = grub_env_get (*args); ++ if (!old) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable \"%s\""), ++ *args); ++ ++ value = grub_strtol (old, NULL, 0); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ switch (op) ++ { ++ case INCREMENT: ++ value += 1; ++ break; ++ case DECREMENT: ++ value -= 1; ++ break; ++ } ++ ++ new = grub_xasprintf ("%ld", value); ++ if (!new) ++ return grub_errno; ++ ++ grub_env_set (*args, new); ++ grub_free (new); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_incr(struct grub_command *cmd UNUSED, ++ int argc, char **args) ++{ ++ return incr_decr(INCREMENT, argc, args); ++} ++ ++static grub_err_t ++grub_cmd_decr(struct grub_command *cmd UNUSED, ++ int argc, char **args) ++{ ++ return incr_decr(DECREMENT, argc, args); ++} ++ ++static grub_command_t cmd_incr, cmd_decr; ++ ++GRUB_MOD_INIT(increment) ++{ ++ cmd_incr = grub_register_command ("increment", grub_cmd_incr, N_("VARIABLE"), ++ N_("increment VARIABLE")); ++ cmd_decr = grub_register_command ("decrement", grub_cmd_decr, N_("VARIABLE"), ++ N_("decrement VARIABLE")); ++} ++ ++GRUB_MOD_FINI(increment) ++{ ++ grub_unregister_command (cmd_incr); ++ grub_unregister_command (cmd_decr); ++} +diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/01_fallback_counting.in +new file mode 100644 +index 0000000000..be0e770ea8 +--- /dev/null ++++ b/util/grub.d/01_fallback_counting.in +@@ -0,0 +1,22 @@ ++#! /bin/sh -e ++ ++# Boot Counting ++# The boot_counter env var can be used to count down boot attempts after an ++# OSTree upgrade and choose the rollback deployment when 0 is reached. Both ++# boot_counter and boot_success need to be (re-)set from userspace. ++cat << EOF ++insmod increment ++# Check if boot_counter exists and boot_success=0 to activate this behaviour. ++if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then ++ # if countdown has ended, choose to boot rollback deployment (default=1 on ++ # OSTree-based systems) ++ if [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then ++ set default=1 ++ set boot_counter=-1 ++ # otherwise decrement boot_counter ++ else ++ decrement boot_counter ++ fi ++ save_env boot_counter ++fi ++EOF diff --git a/0109-Fix-menu-entry-selection-based-on-ID-and-title.patch b/0109-Fix-menu-entry-selection-based-on-ID-and-title.patch new file mode 100644 index 0000000..af74901 --- /dev/null +++ b/0109-Fix-menu-entry-selection-based-on-ID-and-title.patch @@ -0,0 +1,233 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 19 Oct 2018 10:57:52 -0400 +Subject: [PATCH] Fix menu entry selection based on ID and title + +Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an +error, we assume the value it has produced is a correct index into our +menu entry list, and do not try to interpret the value as the "id" or +"title" . In cases where "id" or "title" start with a numeral, this +makes them impossible to use as selection criteria. + +This patch splits the search into three phases - matching id, matching +title, and only once those have been exhausted, trying to interpret the +ID as a numeral. In that case, we also require that the entire string +is numeric, not merely a string with leading numeric characters. + +Resolves: rhbz#1640979 + +Signed-off-by: Peter Jones +[javierm: fix menu entry selection based on title] +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/menu.c | 141 ++++++++++++++++++++++++------------------------ + 1 file changed, 71 insertions(+), 70 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index d7a222e681..4a02aadb01 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout) + } + + static int +-menuentry_eq (const char *id, const char *spec) ++menuentry_eq (const char *id, const char *spec, int limit) + { + const char *ptr1, *ptr2; + ptr1 = id; + ptr2 = spec; +- while (1) ++ while (limit == -1 || ptr1 - id <= limit) + { + if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) + return ptr2 - spec; +@@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec) + if (*ptr2 == '>') + ptr2++; + if (*ptr1 != *ptr2) +- return 0; ++ { ++ if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2)) ++ return ptr1 -id -1; ++ return 0; ++ } + if (*ptr1 == 0) + return ptr1 - id; + ptr1++; +@@ -187,6 +191,58 @@ menuentry_eq (const char *id, const char *spec) + return 0; + } + ++static int ++get_entry_number_helper(grub_menu_t menu, ++ const char * const val, const char ** const tail) ++{ ++ /* See if the variable matches the title of a menu entry. */ ++ int entry = -1; ++ grub_menu_entry_t e; ++ int i; ++ ++ for (i = 0, e = menu->entry_list; e; i++) ++ { ++ int l = 0; ++ while (val[l] && !grub_isspace(val[l])) ++ l++; ++ ++ if (menuentry_eq (e->id, val, l)) ++ { ++ if (tail) ++ *tail = val + l; ++ return i; ++ } ++ e = e->next; ++ } ++ ++ for (i = 0, e = menu->entry_list; e; i++) ++ { ++ ++ if (menuentry_eq (e->title, val, -1)) ++ { ++ if (tail) ++ *tail = NULL; ++ return i; ++ } ++ e = e->next; ++ } ++ ++ if (tail) ++ *tail = NULL; ++ ++ entry = (int) grub_strtoul (val, tail, 0); ++ if (grub_errno == GRUB_ERR_BAD_NUMBER || ++ (*tail && **tail && !grub_isspace(**tail))) ++ { ++ entry = -1; ++ if (tail) ++ *tail = NULL; ++ grub_errno = GRUB_ERR_NONE; ++ } ++ ++ return entry; ++} ++ + /* Get the first entry number from the value of the environment variable NAME, + which is a space-separated list of non-negative integers. The entry number + which is returned is stripped from the value of NAME. If no entry number +@@ -196,7 +252,6 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + { + const char *val, *tail; + int entry; +- int sz = 0; + + val = grub_env_get (name); + if (! val) +@@ -204,50 +259,24 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + + grub_error_push (); + +- entry = (int) grub_strtoul (val, &tail, 0); ++ entry = get_entry_number_helper(menu, val, &tail); ++ if (!(*tail == 0 || grub_isspace(*tail))) ++ entry = -1; + +- if (grub_errno == GRUB_ERR_BAD_NUMBER) ++ if (entry >= 0) + { +- /* See if the variable matches the title of a menu entry. */ +- grub_menu_entry_t e = menu->entry_list; +- int i; +- +- for (i = 0; e; i++) +- { +- sz = menuentry_eq (e->title, val); +- if (sz < 1) +- sz = menuentry_eq (e->id, val); +- +- if (sz >= 1) +- { +- entry = i; +- break; +- } +- e = e->next; +- } +- +- if (sz > 0) +- grub_errno = GRUB_ERR_NONE; +- +- if (! e) +- entry = -1; +- } +- +- if (grub_errno == GRUB_ERR_NONE) +- { +- if (sz > 0) +- tail += sz; +- + /* Skip whitespace to find the next entry. */ + while (*tail && grub_isspace (*tail)) + tail++; +- grub_env_set (name, tail); ++ if (*tail) ++ grub_env_set (name, tail); ++ else ++ grub_env_unset (name); + } + else + { + grub_env_unset (name); + grub_errno = GRUB_ERR_NONE; +- entry = -1; + } + + grub_error_pop (); +@@ -524,6 +553,7 @@ static int + get_entry_number (grub_menu_t menu, const char *name) + { + const char *val; ++ const char *tail; + int entry; + + val = grub_env_get (name); +@@ -531,38 +561,9 @@ get_entry_number (grub_menu_t menu, const char *name) + return -1; + + grub_error_push (); +- +- entry = (int) grub_strtoul (val, 0, 0); +- +- if (grub_errno == GRUB_ERR_BAD_NUMBER) +- { +- /* See if the variable matches the title of a menu entry. */ +- grub_menu_entry_t e = menu->entry_list; +- int i; +- +- grub_errno = GRUB_ERR_NONE; +- +- for (i = 0; e; i++) +- { +- if (menuentry_eq (e->title, val) +- || menuentry_eq (e->id, val)) +- { +- entry = i; +- break; +- } +- e = e->next; +- } +- +- if (! e) +- entry = -1; +- } +- +- if (grub_errno != GRUB_ERR_NONE) +- { +- grub_errno = GRUB_ERR_NONE; +- entry = -1; +- } +- ++ entry = get_entry_number_helper(menu, val, &tail); ++ if (tail && *tail != '\0') ++ entry = -1; + grub_error_pop (); + + return entry; diff --git a/0109-Reimplement-boot_counter.patch b/0109-Reimplement-boot_counter.patch deleted file mode 100644 index 22bd4ef..0000000 --- a/0109-Reimplement-boot_counter.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 4 Oct 2018 14:22:09 -0400 -Subject: [PATCH] Reimplement boot_counter - -This adds "increment" and "decrement" commands, and uses them to maintain our -variables in 01_fallback_counter. It also simplifies the counter logic, so -that there are no nested tests that conflict with each other. - -Apparently, this *really* wasn't tested well enough. - -Resolves: rhbz#1614637 -Signed-off-by: Peter Jones -[lorbus: add comments and revert logic changes in 01_fallback_counting] -Signed-off-by: Christian Glombek ---- - Makefile.util.def | 6 +++ - grub-core/Makefile.core.def | 5 ++ - grub-core/commands/increment.c | 105 ++++++++++++++++++++++++++++++++++++ - util/grub.d/01_fallback_counting.in | 22 ++++++++ - 4 files changed, 138 insertions(+) - create mode 100644 grub-core/commands/increment.c - create mode 100644 util/grub.d/01_fallback_counting.in - -diff --git a/Makefile.util.def b/Makefile.util.def -index 0b85a7fce4..27a13bc734 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -458,6 +458,12 @@ script = { - installdir = grubconf; - }; - -+script = { -+ name = '01_fallback_counting'; -+ common = util/grub.d/01_fallback_counting.in; -+ installdir = grubconf; -+}; -+ - script = { - name = '01_menu_auto_hide'; - common = util/grub.d/01_menu_auto_hide.in; -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 498ca11762..1e15345107 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -398,6 +398,11 @@ kernel = { - extra_dist = kern/mips/cache_flush.S; - }; - -+module = { -+ name = increment; -+ common = commands/increment.c; -+}; -+ - program = { - name = grub-emu; - mansection = 1; -diff --git a/grub-core/commands/increment.c b/grub-core/commands/increment.c -new file mode 100644 -index 0000000000..79cf137656 ---- /dev/null -+++ b/grub-core/commands/increment.c -@@ -0,0 +1,105 @@ -+/* increment.c - Commands to increment and decrement variables. */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+typedef enum { -+ INCREMENT, -+ DECREMENT, -+} operation; -+ -+static grub_err_t -+incr_decr(operation op, int argc, char **args) -+{ -+ const char *old; -+ char *new; -+ long value; -+ -+ if (argc < 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no variable specified")); -+ if (argc > 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("too many arguments")); -+ -+ old = grub_env_get (*args); -+ if (!old) -+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable \"%s\""), -+ *args); -+ -+ value = grub_strtol (old, NULL, 0); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; -+ -+ switch (op) -+ { -+ case INCREMENT: -+ value += 1; -+ break; -+ case DECREMENT: -+ value -= 1; -+ break; -+ } -+ -+ new = grub_xasprintf ("%ld", value); -+ if (!new) -+ return grub_errno; -+ -+ grub_env_set (*args, new); -+ grub_free (new); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_cmd_incr(struct grub_command *cmd UNUSED, -+ int argc, char **args) -+{ -+ return incr_decr(INCREMENT, argc, args); -+} -+ -+static grub_err_t -+grub_cmd_decr(struct grub_command *cmd UNUSED, -+ int argc, char **args) -+{ -+ return incr_decr(DECREMENT, argc, args); -+} -+ -+static grub_command_t cmd_incr, cmd_decr; -+ -+GRUB_MOD_INIT(increment) -+{ -+ cmd_incr = grub_register_command ("increment", grub_cmd_incr, N_("VARIABLE"), -+ N_("increment VARIABLE")); -+ cmd_decr = grub_register_command ("decrement", grub_cmd_decr, N_("VARIABLE"), -+ N_("decrement VARIABLE")); -+} -+ -+GRUB_MOD_FINI(increment) -+{ -+ grub_unregister_command (cmd_incr); -+ grub_unregister_command (cmd_decr); -+} -diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/01_fallback_counting.in -new file mode 100644 -index 0000000000..be0e770ea8 ---- /dev/null -+++ b/util/grub.d/01_fallback_counting.in -@@ -0,0 +1,22 @@ -+#! /bin/sh -e -+ -+# Boot Counting -+# The boot_counter env var can be used to count down boot attempts after an -+# OSTree upgrade and choose the rollback deployment when 0 is reached. Both -+# boot_counter and boot_success need to be (re-)set from userspace. -+cat << EOF -+insmod increment -+# Check if boot_counter exists and boot_success=0 to activate this behaviour. -+if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then -+ # if countdown has ended, choose to boot rollback deployment (default=1 on -+ # OSTree-based systems) -+ if [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then -+ set default=1 -+ set boot_counter=-1 -+ # otherwise decrement boot_counter -+ else -+ decrement boot_counter -+ fi -+ save_env boot_counter -+fi -+EOF diff --git a/0110-Fix-menu-entry-selection-based-on-ID-and-title.patch b/0110-Fix-menu-entry-selection-based-on-ID-and-title.patch deleted file mode 100644 index af74901..0000000 --- a/0110-Fix-menu-entry-selection-based-on-ID-and-title.patch +++ /dev/null @@ -1,233 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 19 Oct 2018 10:57:52 -0400 -Subject: [PATCH] Fix menu entry selection based on ID and title - -Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an -error, we assume the value it has produced is a correct index into our -menu entry list, and do not try to interpret the value as the "id" or -"title" . In cases where "id" or "title" start with a numeral, this -makes them impossible to use as selection criteria. - -This patch splits the search into three phases - matching id, matching -title, and only once those have been exhausted, trying to interpret the -ID as a numeral. In that case, we also require that the entire string -is numeric, not merely a string with leading numeric characters. - -Resolves: rhbz#1640979 - -Signed-off-by: Peter Jones -[javierm: fix menu entry selection based on title] -Signed-off-by: Javier Martinez Canillas ---- - grub-core/normal/menu.c | 141 ++++++++++++++++++++++++------------------------ - 1 file changed, 71 insertions(+), 70 deletions(-) - -diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index d7a222e681..4a02aadb01 100644 ---- a/grub-core/normal/menu.c -+++ b/grub-core/normal/menu.c -@@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout) - } - - static int --menuentry_eq (const char *id, const char *spec) -+menuentry_eq (const char *id, const char *spec, int limit) - { - const char *ptr1, *ptr2; - ptr1 = id; - ptr2 = spec; -- while (1) -+ while (limit == -1 || ptr1 - id <= limit) - { - if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) - return ptr2 - spec; -@@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec) - if (*ptr2 == '>') - ptr2++; - if (*ptr1 != *ptr2) -- return 0; -+ { -+ if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2)) -+ return ptr1 -id -1; -+ return 0; -+ } - if (*ptr1 == 0) - return ptr1 - id; - ptr1++; -@@ -187,6 +191,58 @@ menuentry_eq (const char *id, const char *spec) - return 0; - } - -+static int -+get_entry_number_helper(grub_menu_t menu, -+ const char * const val, const char ** const tail) -+{ -+ /* See if the variable matches the title of a menu entry. */ -+ int entry = -1; -+ grub_menu_entry_t e; -+ int i; -+ -+ for (i = 0, e = menu->entry_list; e; i++) -+ { -+ int l = 0; -+ while (val[l] && !grub_isspace(val[l])) -+ l++; -+ -+ if (menuentry_eq (e->id, val, l)) -+ { -+ if (tail) -+ *tail = val + l; -+ return i; -+ } -+ e = e->next; -+ } -+ -+ for (i = 0, e = menu->entry_list; e; i++) -+ { -+ -+ if (menuentry_eq (e->title, val, -1)) -+ { -+ if (tail) -+ *tail = NULL; -+ return i; -+ } -+ e = e->next; -+ } -+ -+ if (tail) -+ *tail = NULL; -+ -+ entry = (int) grub_strtoul (val, tail, 0); -+ if (grub_errno == GRUB_ERR_BAD_NUMBER || -+ (*tail && **tail && !grub_isspace(**tail))) -+ { -+ entry = -1; -+ if (tail) -+ *tail = NULL; -+ grub_errno = GRUB_ERR_NONE; -+ } -+ -+ return entry; -+} -+ - /* Get the first entry number from the value of the environment variable NAME, - which is a space-separated list of non-negative integers. The entry number - which is returned is stripped from the value of NAME. If no entry number -@@ -196,7 +252,6 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) - { - const char *val, *tail; - int entry; -- int sz = 0; - - val = grub_env_get (name); - if (! val) -@@ -204,50 +259,24 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) - - grub_error_push (); - -- entry = (int) grub_strtoul (val, &tail, 0); -+ entry = get_entry_number_helper(menu, val, &tail); -+ if (!(*tail == 0 || grub_isspace(*tail))) -+ entry = -1; - -- if (grub_errno == GRUB_ERR_BAD_NUMBER) -+ if (entry >= 0) - { -- /* See if the variable matches the title of a menu entry. */ -- grub_menu_entry_t e = menu->entry_list; -- int i; -- -- for (i = 0; e; i++) -- { -- sz = menuentry_eq (e->title, val); -- if (sz < 1) -- sz = menuentry_eq (e->id, val); -- -- if (sz >= 1) -- { -- entry = i; -- break; -- } -- e = e->next; -- } -- -- if (sz > 0) -- grub_errno = GRUB_ERR_NONE; -- -- if (! e) -- entry = -1; -- } -- -- if (grub_errno == GRUB_ERR_NONE) -- { -- if (sz > 0) -- tail += sz; -- - /* Skip whitespace to find the next entry. */ - while (*tail && grub_isspace (*tail)) - tail++; -- grub_env_set (name, tail); -+ if (*tail) -+ grub_env_set (name, tail); -+ else -+ grub_env_unset (name); - } - else - { - grub_env_unset (name); - grub_errno = GRUB_ERR_NONE; -- entry = -1; - } - - grub_error_pop (); -@@ -524,6 +553,7 @@ static int - get_entry_number (grub_menu_t menu, const char *name) - { - const char *val; -+ const char *tail; - int entry; - - val = grub_env_get (name); -@@ -531,38 +561,9 @@ get_entry_number (grub_menu_t menu, const char *name) - return -1; - - grub_error_push (); -- -- entry = (int) grub_strtoul (val, 0, 0); -- -- if (grub_errno == GRUB_ERR_BAD_NUMBER) -- { -- /* See if the variable matches the title of a menu entry. */ -- grub_menu_entry_t e = menu->entry_list; -- int i; -- -- grub_errno = GRUB_ERR_NONE; -- -- for (i = 0; e; i++) -- { -- if (menuentry_eq (e->title, val) -- || menuentry_eq (e->id, val)) -- { -- entry = i; -- break; -- } -- e = e->next; -- } -- -- if (! e) -- entry = -1; -- } -- -- if (grub_errno != GRUB_ERR_NONE) -- { -- grub_errno = GRUB_ERR_NONE; -- entry = -1; -- } -- -+ entry = get_entry_number_helper(menu, val, &tail); -+ if (tail && *tail != '\0') -+ entry = -1; - grub_error_pop (); - - return entry; diff --git a/0110-Make-the-menu-entry-users-option-argument-to-be-opti.patch b/0110-Make-the-menu-entry-users-option-argument-to-be-opti.patch new file mode 100644 index 0000000..68779eb --- /dev/null +++ b/0110-Make-the-menu-entry-users-option-argument-to-be-opti.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 26 Nov 2018 10:06:42 +0100 +Subject: [PATCH] Make the menu entry users option argument to be optional + +The --users option is used to restrict the access to specific menu entries +only to a set of users. But the option requires an argument to either be a +constant or a variable that has been set. So for example the following: + + menuentry "May be run by superusers or users in $users" --users $users { + linux /vmlinuz + } + +Would fail if $users is not defined and grub would discard the menu entry. +Instead, allow the --users option to have an optional argument and ignore +the option if the argument was not set. + +Related: rhbz#1652434 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/commands/menuentry.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index b194123eb6..b175a1b43b 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -29,7 +29,7 @@ static const struct grub_arg_option options[] = + { + {"class", 1, GRUB_ARG_OPTION_REPEATABLE, + N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING}, +- {"users", 2, 0, ++ {"users", 2, GRUB_ARG_OPTION_OPTIONAL, + N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"), + ARG_TYPE_STRING}, + {"hotkey", 3, 0, +@@ -281,7 +281,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + if (! ctxt->state[3].set && ! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); + +- if (ctxt->state[1].set) ++ if (ctxt->state[1].set && ctxt->state[1].arg) + users = ctxt->state[1].arg; + else if (ctxt->state[5].set) + users = NULL; diff --git a/0111-Add-efi-export-env-and-efi-load-env-commands.patch b/0111-Add-efi-export-env-and-efi-load-env-commands.patch new file mode 100644 index 0000000..ac02876 --- /dev/null +++ b/0111-Add-efi-export-env-and-efi-load-env-commands.patch @@ -0,0 +1,346 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 16 Jan 2019 13:21:46 -0500 +Subject: [PATCH] Add efi-export-env and efi-load-env commands + +This adds "efi-export-env VARIABLE" and "efi-load-env", which manipulate the +environment block stored in the EFI variable +GRUB_ENV-91376aff-cba6-42be-949d-06fde81128e8. + +Signed-off-by: Peter Jones +--- + grub-core/Makefile.core.def | 6 ++ + grub-core/commands/efi/env.c | 168 +++++++++++++++++++++++++++++++++++++++++++ + grub-core/kern/efi/efi.c | 3 + + grub-core/kern/efi/init.c | 5 -- + grub-core/lib/envblk.c | 43 +++++++++++ + util/grub-set-bootflag.c | 1 + + include/grub/efi/efi.h | 5 ++ + include/grub/lib/envblk.h | 3 + + 8 files changed, 229 insertions(+), 5 deletions(-) + create mode 100644 grub-core/commands/efi/env.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 1e15345107..81fc274148 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -820,6 +820,12 @@ module = { + enable = efi; + }; + ++module = { ++ name = efienv; ++ common = commands/efi/env.c; ++ enable = efi; ++}; ++ + module = { + name = efifwsetup; + efi = commands/efi/efifwsetup.c; +diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c +new file mode 100644 +index 0000000000..cbd13e03e8 +--- /dev/null ++++ b/grub-core/commands/efi/env.c +@@ -0,0 +1,168 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2012 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static const grub_efi_guid_t grub_env_guid = GRUB_EFI_GRUB_VARIABLE_GUID; ++ ++static grub_err_t ++grub_efi_export_env(grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ const char *value; ++ char *old_value; ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ grub_err_t err; ++ int changed = 1; ++ grub_efi_status_t status; ++ ++ grub_dprintf ("efienv", "argc:%d\n", argc); ++ for (int i = 0; i < argc; i++) ++ grub_dprintf ("efienv", "argv[%d]: %s\n", i, argv[i]); ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected")); ++ ++ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ { ++ char *buf = grub_malloc (1025); ++ if (!buf) ++ return grub_errno; ++ ++ grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); ++ grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', ++ DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); ++ buf[1024] = '\0'; ++ ++ envblk_s.buf = buf; ++ envblk_s.size = 1024; ++ } ++ else ++ { ++ char *buf = grub_realloc (envblk_s.buf, envblk_s.size + 1); ++ if (!buf) ++ return grub_errno; ++ ++ envblk_s.buf = buf; ++ envblk_s.buf[envblk_s.size] = '\0'; ++ } ++ ++ err = grub_envblk_get(envblk, argv[0], &old_value); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("efienv", "grub_envblk_get returned %d\n", err); ++ return err; ++ } ++ ++ value = grub_env_get(argv[0]); ++ if ((!value && !old_value) || ++ (value && old_value && !grub_strcmp(old_value, value))) ++ changed = 0; ++ ++ if (old_value) ++ grub_free(old_value); ++ ++ if (changed == 0) ++ { ++ grub_dprintf ("efienv", "No changes necessary\n"); ++ return 0; ++ } ++ ++ if (value) ++ { ++ grub_dprintf ("efienv", "setting \"%s\" to \"%s\"\n", argv[0], value); ++ grub_envblk_set(envblk, argv[0], value); ++ } ++ else ++ { ++ grub_dprintf ("efienv", "deleting \"%s\" from envblk\n", argv[0]); ++ grub_envblk_delete(envblk, argv[0]); ++ } ++ ++ grub_dprintf ("efienv", "envblk is %lu bytes:\n\"%s\"\n", envblk_s.size, envblk_s.buf); ++ ++ grub_dprintf ("efienv", "removing GRUB_ENV\n"); ++ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, NULL, 0); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efienv", "removal returned %ld\n", status); ++ ++ grub_dprintf ("efienv", "setting GRUB_ENV\n"); ++ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, ++ envblk_s.buf, envblk_s.size); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efienv", "setting GRUB_ENV returned %ld\n", status); ++ ++ return 0; ++} ++ ++static int ++set_var (const char *name, const char *value, ++ void *whitelist __attribute__((__unused__))) ++{ ++ grub_env_set (name, value); ++ return 0; ++} ++ ++static grub_err_t ++grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[] __attribute__((__unused__))) ++{ ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ ++ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ return 0; ++ ++ if (argc > 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected argument")); ++ ++ grub_envblk_iterate (envblk, NULL, set_var); ++ grub_free (envblk_s.buf); ++} ++ ++static grub_command_t export_cmd, loadenv_cmd; ++ ++GRUB_MOD_INIT(lsefi) ++{ ++ export_cmd = grub_register_command ("efi-export-env", grub_efi_export_env, ++ N_("VARIABLE_NAME"), N_("Export environment variable to UEFI.")); ++ loadenv_cmd = grub_register_command ("efi-load-env", grub_efi_load_env, ++ NULL, N_("Load the grub environment from UEFI.")); ++} ++ ++GRUB_MOD_FINI(lsefi) ++{ ++ grub_unregister_command (export_cmd); ++ grub_unregister_command (loadenv_cmd); ++} +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 2a446f5031..14bc10eb56 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -225,6 +225,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + ++ if (status == GRUB_EFI_NOT_FOUND && datasize == 0) ++ return GRUB_ERR_NONE; ++ + return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); + } + +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 2d12e6188f..0574d8d621 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -85,11 +85,6 @@ stack_protector_init (void) + + grub_addr_t grub_modbase; + +-#define GRUB_EFI_GRUB_VARIABLE_GUID \ +- { 0x91376aff, 0xcba6, 0x42be, \ +- { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ +- } +- + /* Helper for grub_efi_env_init */ + static int + set_var (const char *name, const char *value, +diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c +index 2e4e78b132..874506da16 100644 +--- a/grub-core/lib/envblk.c ++++ b/grub-core/lib/envblk.c +@@ -223,6 +223,49 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name) + } + } + ++struct get_var_state { ++ const char * const name; ++ char * value; ++ int found; ++}; ++ ++static int ++get_var (const char * const name, const char * const value, void *statep) ++{ ++ struct get_var_state *state = (struct get_var_state *)statep; ++ ++ if (!grub_strcmp(state->name, name)) ++ { ++ state->found = 1; ++ state->value = grub_strdup(value); ++ if (!state->value) ++ grub_errno = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++grub_err_t ++grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value) ++{ ++ struct get_var_state state = { ++ .name = name, ++ .value = NULL, ++ .found = 0, ++ }; ++ ++ grub_envblk_iterate(envblk, (void *)&state, get_var); ++ ++ *value = state.value; ++ ++ if (state.found && !state.value) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ + void + grub_envblk_iterate (grub_envblk_t envblk, + void *hook_data, +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index d506f7e75b..a6ccc11383 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -25,6 +25,7 @@ + + #include /* For *_DIR_NAME defines */ + #include ++#include + #include /* For GRUB_ENVBLK_DEFCFG define */ + #include + #include +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 2e0691454b..8dfc89a33b 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -24,6 +24,11 @@ + #include + #include + ++#define GRUB_EFI_GRUB_VARIABLE_GUID \ ++ { 0x91376aff, 0xcba6, 0x42be, \ ++ { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ ++ } ++ + /* Variables. */ + extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); + extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); +diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h +index c3e6559217..ab969af246 100644 +--- a/include/grub/lib/envblk.h ++++ b/include/grub/lib/envblk.h +@@ -22,6 +22,8 @@ + #define GRUB_ENVBLK_SIGNATURE "# GRUB Environment Block\n" + #define GRUB_ENVBLK_DEFCFG "grubenv" + ++#define DEFAULT_ENVBLK_SIZE 1024 ++ + #ifndef ASM_FILE + + struct grub_envblk +@@ -33,6 +35,7 @@ typedef struct grub_envblk *grub_envblk_t; + + grub_envblk_t grub_envblk_open (char *buf, grub_size_t size); + int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value); ++grub_err_t grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value); + void grub_envblk_delete (grub_envblk_t envblk, const char *name); + void grub_envblk_iterate (grub_envblk_t envblk, + void *hook_data, diff --git a/0111-Make-the-menu-entry-users-option-argument-to-be-opti.patch b/0111-Make-the-menu-entry-users-option-argument-to-be-opti.patch deleted file mode 100644 index 68779eb..0000000 --- a/0111-Make-the-menu-entry-users-option-argument-to-be-opti.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 26 Nov 2018 10:06:42 +0100 -Subject: [PATCH] Make the menu entry users option argument to be optional - -The --users option is used to restrict the access to specific menu entries -only to a set of users. But the option requires an argument to either be a -constant or a variable that has been set. So for example the following: - - menuentry "May be run by superusers or users in $users" --users $users { - linux /vmlinuz - } - -Would fail if $users is not defined and grub would discard the menu entry. -Instead, allow the --users option to have an optional argument and ignore -the option if the argument was not set. - -Related: rhbz#1652434 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/commands/menuentry.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c -index b194123eb6..b175a1b43b 100644 ---- a/grub-core/commands/menuentry.c -+++ b/grub-core/commands/menuentry.c -@@ -29,7 +29,7 @@ static const struct grub_arg_option options[] = - { - {"class", 1, GRUB_ARG_OPTION_REPEATABLE, - N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING}, -- {"users", 2, 0, -+ {"users", 2, GRUB_ARG_OPTION_OPTIONAL, - N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"), - ARG_TYPE_STRING}, - {"hotkey", 3, 0, -@@ -281,7 +281,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) - if (! ctxt->state[3].set && ! ctxt->script) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); - -- if (ctxt->state[1].set) -+ if (ctxt->state[1].set && ctxt->state[1].arg) - users = ctxt->state[1].arg; - else if (ctxt->state[5].set) - users = NULL; diff --git a/0112-Add-efi-export-env-and-efi-load-env-commands.patch b/0112-Add-efi-export-env-and-efi-load-env-commands.patch deleted file mode 100644 index ac02876..0000000 --- a/0112-Add-efi-export-env-and-efi-load-env-commands.patch +++ /dev/null @@ -1,346 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 16 Jan 2019 13:21:46 -0500 -Subject: [PATCH] Add efi-export-env and efi-load-env commands - -This adds "efi-export-env VARIABLE" and "efi-load-env", which manipulate the -environment block stored in the EFI variable -GRUB_ENV-91376aff-cba6-42be-949d-06fde81128e8. - -Signed-off-by: Peter Jones ---- - grub-core/Makefile.core.def | 6 ++ - grub-core/commands/efi/env.c | 168 +++++++++++++++++++++++++++++++++++++++++++ - grub-core/kern/efi/efi.c | 3 + - grub-core/kern/efi/init.c | 5 -- - grub-core/lib/envblk.c | 43 +++++++++++ - util/grub-set-bootflag.c | 1 + - include/grub/efi/efi.h | 5 ++ - include/grub/lib/envblk.h | 3 + - 8 files changed, 229 insertions(+), 5 deletions(-) - create mode 100644 grub-core/commands/efi/env.c - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 1e15345107..81fc274148 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -820,6 +820,12 @@ module = { - enable = efi; - }; - -+module = { -+ name = efienv; -+ common = commands/efi/env.c; -+ enable = efi; -+}; -+ - module = { - name = efifwsetup; - efi = commands/efi/efifwsetup.c; -diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c -new file mode 100644 -index 0000000000..cbd13e03e8 ---- /dev/null -+++ b/grub-core/commands/efi/env.c -@@ -0,0 +1,168 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2012 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static const grub_efi_guid_t grub_env_guid = GRUB_EFI_GRUB_VARIABLE_GUID; -+ -+static grub_err_t -+grub_efi_export_env(grub_command_t cmd __attribute__ ((unused)), -+ int argc, char *argv[]) -+{ -+ const char *value; -+ char *old_value; -+ struct grub_envblk envblk_s = { NULL, 0 }; -+ grub_envblk_t envblk = &envblk_s; -+ grub_err_t err; -+ int changed = 1; -+ grub_efi_status_t status; -+ -+ grub_dprintf ("efienv", "argc:%d\n", argc); -+ for (int i = 0; i < argc; i++) -+ grub_dprintf ("efienv", "argv[%d]: %s\n", i, argv[i]); -+ -+ if (argc != 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected")); -+ -+ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, -+ (void **) &envblk_s.buf); -+ if (!envblk_s.buf || envblk_s.size < 1) -+ { -+ char *buf = grub_malloc (1025); -+ if (!buf) -+ return grub_errno; -+ -+ grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); -+ grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', -+ DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); -+ buf[1024] = '\0'; -+ -+ envblk_s.buf = buf; -+ envblk_s.size = 1024; -+ } -+ else -+ { -+ char *buf = grub_realloc (envblk_s.buf, envblk_s.size + 1); -+ if (!buf) -+ return grub_errno; -+ -+ envblk_s.buf = buf; -+ envblk_s.buf[envblk_s.size] = '\0'; -+ } -+ -+ err = grub_envblk_get(envblk, argv[0], &old_value); -+ if (err != GRUB_ERR_NONE) -+ { -+ grub_dprintf ("efienv", "grub_envblk_get returned %d\n", err); -+ return err; -+ } -+ -+ value = grub_env_get(argv[0]); -+ if ((!value && !old_value) || -+ (value && old_value && !grub_strcmp(old_value, value))) -+ changed = 0; -+ -+ if (old_value) -+ grub_free(old_value); -+ -+ if (changed == 0) -+ { -+ grub_dprintf ("efienv", "No changes necessary\n"); -+ return 0; -+ } -+ -+ if (value) -+ { -+ grub_dprintf ("efienv", "setting \"%s\" to \"%s\"\n", argv[0], value); -+ grub_envblk_set(envblk, argv[0], value); -+ } -+ else -+ { -+ grub_dprintf ("efienv", "deleting \"%s\" from envblk\n", argv[0]); -+ grub_envblk_delete(envblk, argv[0]); -+ } -+ -+ grub_dprintf ("efienv", "envblk is %lu bytes:\n\"%s\"\n", envblk_s.size, envblk_s.buf); -+ -+ grub_dprintf ("efienv", "removing GRUB_ENV\n"); -+ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, NULL, 0); -+ if (status != GRUB_EFI_SUCCESS) -+ grub_dprintf ("efienv", "removal returned %ld\n", status); -+ -+ grub_dprintf ("efienv", "setting GRUB_ENV\n"); -+ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, -+ envblk_s.buf, envblk_s.size); -+ if (status != GRUB_EFI_SUCCESS) -+ grub_dprintf ("efienv", "setting GRUB_ENV returned %ld\n", status); -+ -+ return 0; -+} -+ -+static int -+set_var (const char *name, const char *value, -+ void *whitelist __attribute__((__unused__))) -+{ -+ grub_env_set (name, value); -+ return 0; -+} -+ -+static grub_err_t -+grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)), -+ int argc, char *argv[] __attribute__((__unused__))) -+{ -+ struct grub_envblk envblk_s = { NULL, 0 }; -+ grub_envblk_t envblk = &envblk_s; -+ -+ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, -+ (void **) &envblk_s.buf); -+ if (!envblk_s.buf || envblk_s.size < 1) -+ return 0; -+ -+ if (argc > 0) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected argument")); -+ -+ grub_envblk_iterate (envblk, NULL, set_var); -+ grub_free (envblk_s.buf); -+} -+ -+static grub_command_t export_cmd, loadenv_cmd; -+ -+GRUB_MOD_INIT(lsefi) -+{ -+ export_cmd = grub_register_command ("efi-export-env", grub_efi_export_env, -+ N_("VARIABLE_NAME"), N_("Export environment variable to UEFI.")); -+ loadenv_cmd = grub_register_command ("efi-load-env", grub_efi_load_env, -+ NULL, N_("Load the grub environment from UEFI.")); -+} -+ -+GRUB_MOD_FINI(lsefi) -+{ -+ grub_unregister_command (export_cmd); -+ grub_unregister_command (loadenv_cmd); -+} -diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c -index 2a446f5031..14bc10eb56 100644 ---- a/grub-core/kern/efi/efi.c -+++ b/grub-core/kern/efi/efi.c -@@ -225,6 +225,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, - if (status == GRUB_EFI_SUCCESS) - return GRUB_ERR_NONE; - -+ if (status == GRUB_EFI_NOT_FOUND && datasize == 0) -+ return GRUB_ERR_NONE; -+ - return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); - } - -diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c -index 2d12e6188f..0574d8d621 100644 ---- a/grub-core/kern/efi/init.c -+++ b/grub-core/kern/efi/init.c -@@ -85,11 +85,6 @@ stack_protector_init (void) - - grub_addr_t grub_modbase; - --#define GRUB_EFI_GRUB_VARIABLE_GUID \ -- { 0x91376aff, 0xcba6, 0x42be, \ -- { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ -- } -- - /* Helper for grub_efi_env_init */ - static int - set_var (const char *name, const char *value, -diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c -index 2e4e78b132..874506da16 100644 ---- a/grub-core/lib/envblk.c -+++ b/grub-core/lib/envblk.c -@@ -223,6 +223,49 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name) - } - } - -+struct get_var_state { -+ const char * const name; -+ char * value; -+ int found; -+}; -+ -+static int -+get_var (const char * const name, const char * const value, void *statep) -+{ -+ struct get_var_state *state = (struct get_var_state *)statep; -+ -+ if (!grub_strcmp(state->name, name)) -+ { -+ state->found = 1; -+ state->value = grub_strdup(value); -+ if (!state->value) -+ grub_errno = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); -+ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+grub_err_t -+grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value) -+{ -+ struct get_var_state state = { -+ .name = name, -+ .value = NULL, -+ .found = 0, -+ }; -+ -+ grub_envblk_iterate(envblk, (void *)&state, get_var); -+ -+ *value = state.value; -+ -+ if (state.found && !state.value) -+ return grub_errno; -+ -+ return GRUB_ERR_NONE; -+} -+ - void - grub_envblk_iterate (grub_envblk_t envblk, - void *hook_data, -diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c -index d506f7e75b..a6ccc11383 100644 ---- a/util/grub-set-bootflag.c -+++ b/util/grub-set-bootflag.c -@@ -25,6 +25,7 @@ - - #include /* For *_DIR_NAME defines */ - #include -+#include - #include /* For GRUB_ENVBLK_DEFCFG define */ - #include - #include -diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h -index 2e0691454b..8dfc89a33b 100644 ---- a/include/grub/efi/efi.h -+++ b/include/grub/efi/efi.h -@@ -24,6 +24,11 @@ - #include - #include - -+#define GRUB_EFI_GRUB_VARIABLE_GUID \ -+ { 0x91376aff, 0xcba6, 0x42be, \ -+ { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ -+ } -+ - /* Variables. */ - extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); - extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); -diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h -index c3e6559217..ab969af246 100644 ---- a/include/grub/lib/envblk.h -+++ b/include/grub/lib/envblk.h -@@ -22,6 +22,8 @@ - #define GRUB_ENVBLK_SIGNATURE "# GRUB Environment Block\n" - #define GRUB_ENVBLK_DEFCFG "grubenv" - -+#define DEFAULT_ENVBLK_SIZE 1024 -+ - #ifndef ASM_FILE - - struct grub_envblk -@@ -33,6 +35,7 @@ typedef struct grub_envblk *grub_envblk_t; - - grub_envblk_t grub_envblk_open (char *buf, grub_size_t size); - int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value); -+grub_err_t grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value); - void grub_envblk_delete (grub_envblk_t envblk, const char *name); - void grub_envblk_iterate (grub_envblk_t envblk, - void *hook_data, diff --git a/0112-Make-it-possible-to-subtract-conditions-from-debug.patch b/0112-Make-it-possible-to-subtract-conditions-from-debug.patch new file mode 100644 index 0000000..15305f8 --- /dev/null +++ b/0112-Make-it-possible-to-subtract-conditions-from-debug.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 17 Jan 2019 13:10:39 -0500 +Subject: [PATCH] Make it possible to subtract conditions from debug= + +This makes it so you can do set debug to "all,-scripting,-lexer" and get the +obvious outcome. Any negation present will take preference over that +conditional, so "all,-scripting,scripting" is the same thing as +"all,-scripting". + +Signed-off-by: Peter Jones +--- + grub-core/kern/misc.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 9a2fae6398..578bf51a5f 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -164,12 +164,24 @@ int + grub_debug_enabled (const char * condition) + { + const char *debug; ++ char *negcond; ++ int negated = 0; + + debug = grub_env_get ("debug"); + if (!debug) + return 0; + +- if (grub_strword (debug, "all") || grub_strword (debug, condition)) ++ negcond = grub_zalloc (grub_strlen (condition) + 2); ++ if (negcond) ++ { ++ grub_strcpy (negcond, "-"); ++ grub_strcpy (negcond+1, condition); ++ negated = grub_strword (debug, negcond); ++ grub_free (negcond); ++ } ++ ++ if (!negated && ++ (grub_strword (debug, "all") || grub_strword (debug, condition))) + return 1; + + return 0; diff --git a/0113-Export-all-variables-from-the-initial-context-when-c.patch b/0113-Export-all-variables-from-the-initial-context-when-c.patch new file mode 100644 index 0000000..214fa4f --- /dev/null +++ b/0113-Export-all-variables-from-the-initial-context-when-c.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 22 Jan 2019 15:40:25 +0100 +Subject: [PATCH] Export all variables from the initial context when creating a + submenu + +When a submenu is created, only the exported variables are copied to the +new menu context. But we want the variables to be global, so export lets +export all variables to the new created submenu. + +Also, don't unset the default variable when a new submenu is created. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/context.c | 2 +- + grub-core/normal/menu.c | 2 -- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c +index ee53d4a68e..87edd254c4 100644 +--- a/grub-core/normal/context.c ++++ b/grub-core/normal/context.c +@@ -99,7 +99,7 @@ grub_env_new_context (int export_all) + grub_err_t + grub_env_context_open (void) + { +- return grub_env_new_context (0); ++ return grub_env_new_context (1); + } + + int grub_extractor_level = 0; +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 4a02aadb01..fe2e77a43e 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -375,8 +375,6 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + + if (ptr && ptr[0] && ptr[1]) + grub_env_set ("default", ptr + 1); +- else +- grub_env_unset ("default"); + + grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); + diff --git a/0113-Make-it-possible-to-subtract-conditions-from-debug.patch b/0113-Make-it-possible-to-subtract-conditions-from-debug.patch deleted file mode 100644 index 15305f8..0000000 --- a/0113-Make-it-possible-to-subtract-conditions-from-debug.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 17 Jan 2019 13:10:39 -0500 -Subject: [PATCH] Make it possible to subtract conditions from debug= - -This makes it so you can do set debug to "all,-scripting,-lexer" and get the -obvious outcome. Any negation present will take preference over that -conditional, so "all,-scripting,scripting" is the same thing as -"all,-scripting". - -Signed-off-by: Peter Jones ---- - grub-core/kern/misc.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index 9a2fae6398..578bf51a5f 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -164,12 +164,24 @@ int - grub_debug_enabled (const char * condition) - { - const char *debug; -+ char *negcond; -+ int negated = 0; - - debug = grub_env_get ("debug"); - if (!debug) - return 0; - -- if (grub_strword (debug, "all") || grub_strword (debug, condition)) -+ negcond = grub_zalloc (grub_strlen (condition) + 2); -+ if (negcond) -+ { -+ grub_strcpy (negcond, "-"); -+ grub_strcpy (negcond+1, condition); -+ negated = grub_strword (debug, negcond); -+ grub_free (negcond); -+ } -+ -+ if (!negated && -+ (grub_strword (debug, "all") || grub_strword (debug, condition))) - return 1; - - return 0; diff --git a/0114-Export-all-variables-from-the-initial-context-when-c.patch b/0114-Export-all-variables-from-the-initial-context-when-c.patch deleted file mode 100644 index 214fa4f..0000000 --- a/0114-Export-all-variables-from-the-initial-context-when-c.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 22 Jan 2019 15:40:25 +0100 -Subject: [PATCH] Export all variables from the initial context when creating a - submenu - -When a submenu is created, only the exported variables are copied to the -new menu context. But we want the variables to be global, so export lets -export all variables to the new created submenu. - -Also, don't unset the default variable when a new submenu is created. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/normal/context.c | 2 +- - grub-core/normal/menu.c | 2 -- - 2 files changed, 1 insertion(+), 3 deletions(-) - -diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c -index ee53d4a68e..87edd254c4 100644 ---- a/grub-core/normal/context.c -+++ b/grub-core/normal/context.c -@@ -99,7 +99,7 @@ grub_env_new_context (int export_all) - grub_err_t - grub_env_context_open (void) - { -- return grub_env_new_context (0); -+ return grub_env_new_context (1); - } - - int grub_extractor_level = 0; -diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index 4a02aadb01..fe2e77a43e 100644 ---- a/grub-core/normal/menu.c -+++ b/grub-core/normal/menu.c -@@ -375,8 +375,6 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) - - if (ptr && ptr[0] && ptr[1]) - grub_env_set ("default", ptr + 1); -- else -- grub_env_unset ("default"); - - grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); - diff --git a/0114-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch b/0114-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch new file mode 100644 index 0000000..43e8d16 --- /dev/null +++ b/0114-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch @@ -0,0 +1,168 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christian Glombek +Date: Tue, 2 Apr 2019 16:22:21 +0200 +Subject: [PATCH] grub.d: Split out boot success reset from menu auto hide + script + +Also rename fallback and menu auto hide script to be executed +before and after boot success reset script. +In menu auto hide script, rename last_boot_ok var to menu_hide_ok + +Signed-off-by: Christian Glombek +Signed-off-by: Robbie Harwood +--- + Makefile.util.def | 14 ++++++++---- + ...allback_counting.in => 08_fallback_counting.in} | 14 ++++++------ + util/grub.d/10_reset_boot_success.in | 25 ++++++++++++++++++++++ + .../{01_menu_auto_hide.in => 12_menu_auto_hide.in} | 23 +++++--------------- + 4 files changed, 48 insertions(+), 28 deletions(-) + rename util/grub.d/{01_fallback_counting.in => 08_fallback_counting.in} (65%) + create mode 100644 util/grub.d/10_reset_boot_success.in + rename util/grub.d/{01_menu_auto_hide.in => 12_menu_auto_hide.in} (58%) + +diff --git a/Makefile.util.def b/Makefile.util.def +index e10fe766d1..b4ce5383b7 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -459,14 +459,14 @@ script = { + }; + + script = { +- name = '01_fallback_counting'; +- common = util/grub.d/01_fallback_counting.in; ++ name = '08_fallback_counting'; ++ common = util/grub.d/08_fallback_counting.in; + installdir = grubconf; + }; + + script = { +- name = '01_menu_auto_hide'; +- common = util/grub.d/01_menu_auto_hide.in; ++ name = '12_menu_auto_hide'; ++ common = util/grub.d/12_menu_auto_hide.in; + installdir = grubconf; + }; + +@@ -518,6 +518,12 @@ script = { + condition = COND_HOST_LINUX; + }; + ++script = { ++ name = '10_reset_boot_success'; ++ common = util/grub.d/10_reset_boot_success.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '10_xnu'; + common = util/grub.d/10_xnu.in; +diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/08_fallback_counting.in +similarity index 65% +rename from util/grub.d/01_fallback_counting.in +rename to util/grub.d/08_fallback_counting.in +index be0e770ea8..2e2c3ff7d3 100644 +--- a/util/grub.d/01_fallback_counting.in ++++ b/util/grub.d/08_fallback_counting.in +@@ -1,15 +1,17 @@ + #! /bin/sh -e +- +-# Boot Counting ++# Fallback Countdown ++# ++# This snippet depends on 10_reset_boot_success and needs to be kept in sync. ++# + # The boot_counter env var can be used to count down boot attempts after an +-# OSTree upgrade and choose the rollback deployment when 0 is reached. Both +-# boot_counter and boot_success need to be (re-)set from userspace. ++# OSTree upgrade and choose the rollback deployment when 0 is reached. ++# Both boot_counter=X and boot_success=1 need to be set from userspace. + cat << EOF + insmod increment + # Check if boot_counter exists and boot_success=0 to activate this behaviour. + if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then +- # if countdown has ended, choose to boot rollback deployment (default=1 on +- # OSTree-based systems) ++ # if countdown has ended, choose to boot rollback deployment, ++ # i.e. default=1 on OSTree-based systems. + if [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then + set default=1 + set boot_counter=-1 +diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in +new file mode 100644 +index 0000000000..6c88d933dd +--- /dev/null ++++ b/util/grub.d/10_reset_boot_success.in +@@ -0,0 +1,25 @@ ++#! /bin/sh -e ++# Reset Boot Success ++# ++# The 08_fallback_counting and 12_menu_auto_hide snippets rely on this one ++# and need to be kept in sync. ++# ++# The boot_success var needs to be set to 1 from userspace to mark a boot successful. ++cat << EOF ++insmod increment ++# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry ++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then ++ set menu_hide_ok=1 ++else ++ set menu_hide_ok=0 ++fi ++# Reset boot_indeterminate after a successful boot, increment otherwise ++if [ "\${boot_success}" = "1" ] ; then ++ set boot_indeterminate=0 ++else ++ increment boot_indeterminate ++fi ++# Reset boot_success for current boot ++set boot_success=0 ++save_env boot_success boot_indeterminate ++EOF +diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in +similarity index 58% +rename from util/grub.d/01_menu_auto_hide.in +rename to util/grub.d/12_menu_auto_hide.in +index ad175870a5..6a7c0fa0d4 100644 +--- a/util/grub.d/01_menu_auto_hide.in ++++ b/util/grub.d/12_menu_auto_hide.in +@@ -1,5 +1,8 @@ + #! /bin/sh +- ++# Menu Auto Hide ++# ++# This snippet depends on 10_reset_boot_success and needs to be kept in sync. ++# + # Disable / skip generating menu-auto-hide config parts on serial terminals + for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do + case "$x" in +@@ -10,29 +13,13 @@ for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do + done + + cat << EOF +-if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then +- set last_boot_ok=1 +-else +- set last_boot_ok=0 +-fi +- +-# Reset boot_indeterminate after a successful boot +-if [ "\${boot_success}" = "1" ] ; then +- set boot_indeterminate=0 +-# Avoid boot_indeterminate causing the menu to be hidden more then once +-elif [ "\${boot_indeterminate}" = "1" ]; then +- set boot_indeterminate=2 +-fi +-set boot_success=0 +-save_env boot_success boot_indeterminate +- + if [ x\$feature_timeout_style = xy ] ; then + if [ "\${menu_show_once}" ]; then + unset menu_show_once + save_env menu_show_once + set timeout_style=menu + set timeout=60 +- elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then ++ elif [ "\${menu_auto_hide}" -a "\${menu_hide_ok}" = "1" ]; then + set orig_timeout_style=\${timeout_style} + set orig_timeout=\${timeout} + if [ "\${fastboot}" = "1" ]; then diff --git a/0115-Fix-systemctl-kexec-exit-status-check.patch b/0115-Fix-systemctl-kexec-exit-status-check.patch new file mode 100644 index 0000000..567e678 --- /dev/null +++ b/0115-Fix-systemctl-kexec-exit-status-check.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 9 Apr 2019 12:30:38 +0200 +Subject: [PATCH] Fix systemctl kexec exit status check + +There's always an error printed even when the systemctl kexec command does +succeed. That's because systemctl executes it asynchronously, but the emu +loader seems to expect it to be synchronous and that should never return. + +Also, it's wrong to test if kexecute == 1 since we already know that's the +case or otherwise the function wouldn't had called grub_fatal() earlier. + +Finally, systemctl kexec failing shouldn't be a fatal error since the emu +loader fallbacks to executing the kexec command in case of a failure. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/emu/linux.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c +index fda9e00d24..5b85b225ee 100644 +--- a/grub-core/loader/emu/linux.c ++++ b/grub-core/loader/emu/linux.c +@@ -71,8 +71,10 @@ grub_linux_boot (void) + (kexecute==1) ? "do-or-die" : "just-in-case"); + rc = grub_util_exec (systemctl); + +- if (kexecute == 1) +- grub_fatal (N_("Error trying to perform 'systemctl kexec'")); ++ if (rc == GRUB_ERR_NONE) ++ return rc; ++ ++ grub_error (rc, N_("Error trying to perform 'systemctl kexec'")); + + /* need to check read-only root before resetting hard!? */ + grub_printf("Performing 'kexec -e'"); diff --git a/0115-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch b/0115-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch deleted file mode 100644 index 0abe8ed..0000000 --- a/0115-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Christian Glombek -Date: Tue, 2 Apr 2019 16:22:21 +0200 -Subject: [PATCH] grub.d: Split out boot success reset from menu auto hide - script - -Also rename fallback and menu auto hide script to be executed -before and after boot success reset script. -In menu auto hide script, rename last_boot_ok var to menu_hide_ok - -Signed-off-by: Christian Glombek -Signed-off-by: Robbie Harwood ---- - Makefile.util.def | 14 ++++++++---- - ...allback_counting.in => 08_fallback_counting.in} | 14 ++++++------ - util/grub.d/10_reset_boot_success.in | 25 ++++++++++++++++++++++ - .../{01_menu_auto_hide.in => 12_menu_auto_hide.in} | 23 +++++--------------- - 4 files changed, 48 insertions(+), 28 deletions(-) - rename util/grub.d/{01_fallback_counting.in => 08_fallback_counting.in} (65%) - create mode 100644 util/grub.d/10_reset_boot_success.in - rename util/grub.d/{01_menu_auto_hide.in => 12_menu_auto_hide.in} (58%) - -diff --git a/Makefile.util.def b/Makefile.util.def -index 27a13bc734..2e6ad979c3 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -459,14 +459,14 @@ script = { - }; - - script = { -- name = '01_fallback_counting'; -- common = util/grub.d/01_fallback_counting.in; -+ name = '08_fallback_counting'; -+ common = util/grub.d/08_fallback_counting.in; - installdir = grubconf; - }; - - script = { -- name = '01_menu_auto_hide'; -- common = util/grub.d/01_menu_auto_hide.in; -+ name = '12_menu_auto_hide'; -+ common = util/grub.d/12_menu_auto_hide.in; - installdir = grubconf; - }; - -@@ -518,6 +518,12 @@ script = { - condition = COND_HOST_LINUX; - }; - -+script = { -+ name = '10_reset_boot_success'; -+ common = util/grub.d/10_reset_boot_success.in; -+ installdir = grubconf; -+}; -+ - script = { - name = '10_xnu'; - common = util/grub.d/10_xnu.in; -diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/08_fallback_counting.in -similarity index 65% -rename from util/grub.d/01_fallback_counting.in -rename to util/grub.d/08_fallback_counting.in -index be0e770ea8..2e2c3ff7d3 100644 ---- a/util/grub.d/01_fallback_counting.in -+++ b/util/grub.d/08_fallback_counting.in -@@ -1,15 +1,17 @@ - #! /bin/sh -e -- --# Boot Counting -+# Fallback Countdown -+# -+# This snippet depends on 10_reset_boot_success and needs to be kept in sync. -+# - # The boot_counter env var can be used to count down boot attempts after an --# OSTree upgrade and choose the rollback deployment when 0 is reached. Both --# boot_counter and boot_success need to be (re-)set from userspace. -+# OSTree upgrade and choose the rollback deployment when 0 is reached. -+# Both boot_counter=X and boot_success=1 need to be set from userspace. - cat << EOF - insmod increment - # Check if boot_counter exists and boot_success=0 to activate this behaviour. - if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then -- # if countdown has ended, choose to boot rollback deployment (default=1 on -- # OSTree-based systems) -+ # if countdown has ended, choose to boot rollback deployment, -+ # i.e. default=1 on OSTree-based systems. - if [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then - set default=1 - set boot_counter=-1 -diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in -new file mode 100644 -index 0000000000..6c88d933dd ---- /dev/null -+++ b/util/grub.d/10_reset_boot_success.in -@@ -0,0 +1,25 @@ -+#! /bin/sh -e -+# Reset Boot Success -+# -+# The 08_fallback_counting and 12_menu_auto_hide snippets rely on this one -+# and need to be kept in sync. -+# -+# The boot_success var needs to be set to 1 from userspace to mark a boot successful. -+cat << EOF -+insmod increment -+# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry -+if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then -+ set menu_hide_ok=1 -+else -+ set menu_hide_ok=0 -+fi -+# Reset boot_indeterminate after a successful boot, increment otherwise -+if [ "\${boot_success}" = "1" ] ; then -+ set boot_indeterminate=0 -+else -+ increment boot_indeterminate -+fi -+# Reset boot_success for current boot -+set boot_success=0 -+save_env boot_success boot_indeterminate -+EOF -diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in -similarity index 58% -rename from util/grub.d/01_menu_auto_hide.in -rename to util/grub.d/12_menu_auto_hide.in -index ad175870a5..6a7c0fa0d4 100644 ---- a/util/grub.d/01_menu_auto_hide.in -+++ b/util/grub.d/12_menu_auto_hide.in -@@ -1,5 +1,8 @@ - #! /bin/sh -- -+# Menu Auto Hide -+# -+# This snippet depends on 10_reset_boot_success and needs to be kept in sync. -+# - # Disable / skip generating menu-auto-hide config parts on serial terminals - for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do - case "$x" in -@@ -10,29 +13,13 @@ for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do - done - - cat << EOF --if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then -- set last_boot_ok=1 --else -- set last_boot_ok=0 --fi -- --# Reset boot_indeterminate after a successful boot --if [ "\${boot_success}" = "1" ] ; then -- set boot_indeterminate=0 --# Avoid boot_indeterminate causing the menu to be hidden more then once --elif [ "\${boot_indeterminate}" = "1" ]; then -- set boot_indeterminate=2 --fi --set boot_success=0 --save_env boot_success boot_indeterminate -- - if [ x\$feature_timeout_style = xy ] ; then - if [ "\${menu_show_once}" ]; then - unset menu_show_once - save_env menu_show_once - set timeout_style=menu - set timeout=60 -- elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then -+ elif [ "\${menu_auto_hide}" -a "\${menu_hide_ok}" = "1" ]; then - set orig_timeout_style=\${timeout_style} - set orig_timeout=\${timeout} - if [ "\${fastboot}" = "1" ]; then diff --git a/0116-Fix-systemctl-kexec-exit-status-check.patch b/0116-Fix-systemctl-kexec-exit-status-check.patch deleted file mode 100644 index 567e678..0000000 --- a/0116-Fix-systemctl-kexec-exit-status-check.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 9 Apr 2019 12:30:38 +0200 -Subject: [PATCH] Fix systemctl kexec exit status check - -There's always an error printed even when the systemctl kexec command does -succeed. That's because systemctl executes it asynchronously, but the emu -loader seems to expect it to be synchronous and that should never return. - -Also, it's wrong to test if kexecute == 1 since we already know that's the -case or otherwise the function wouldn't had called grub_fatal() earlier. - -Finally, systemctl kexec failing shouldn't be a fatal error since the emu -loader fallbacks to executing the kexec command in case of a failure. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/loader/emu/linux.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c -index fda9e00d24..5b85b225ee 100644 ---- a/grub-core/loader/emu/linux.c -+++ b/grub-core/loader/emu/linux.c -@@ -71,8 +71,10 @@ grub_linux_boot (void) - (kexecute==1) ? "do-or-die" : "just-in-case"); - rc = grub_util_exec (systemctl); - -- if (kexecute == 1) -- grub_fatal (N_("Error trying to perform 'systemctl kexec'")); -+ if (rc == GRUB_ERR_NONE) -+ return rc; -+ -+ grub_error (rc, N_("Error trying to perform 'systemctl kexec'")); - - /* need to check read-only root before resetting hard!? */ - grub_printf("Performing 'kexec -e'"); diff --git a/0116-Print-grub-emu-linux-loader-messages-as-debug.patch b/0116-Print-grub-emu-linux-loader-messages-as-debug.patch new file mode 100644 index 0000000..2718a70 --- /dev/null +++ b/0116-Print-grub-emu-linux-loader-messages-as-debug.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 9 Apr 2019 12:42:37 +0200 +Subject: [PATCH] Print grub-emu linux loader messages as debug + +They just polute the output and should better be debug messages instead. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/emu/linux.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c +index 5b85b225ee..22ab6af172 100644 +--- a/grub-core/loader/emu/linux.c ++++ b/grub-core/loader/emu/linux.c +@@ -50,7 +50,7 @@ grub_linux_boot (void) + initrd_param = grub_xasprintf("%s", ""); + } + +- grub_printf("%serforming 'kexec -l %s %s %s'\n", ++ grub_dprintf ("linux", "%serforming 'kexec -l %s %s %s'\n", + (kexecute) ? "P" : "Not p", + kernel_path, initrd_param, boot_cmdline); + +@@ -67,7 +67,7 @@ grub_linux_boot (void) + if (kexecute < 1) + grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart.")); + +- grub_printf("Performing 'systemctl kexec' (%s) ", ++ grub_dprintf ("linux", "Performing 'systemctl kexec' (%s) ", + (kexecute==1) ? "do-or-die" : "just-in-case"); + rc = grub_util_exec (systemctl); + diff --git a/0117-Don-t-assume-that-boot-commands-will-only-return-on-.patch b/0117-Don-t-assume-that-boot-commands-will-only-return-on-.patch new file mode 100644 index 0000000..df36517 --- /dev/null +++ b/0117-Don-t-assume-that-boot-commands-will-only-return-on-.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 9 Apr 2019 13:12:40 +0200 +Subject: [PATCH] Don't assume that boot commands will only return on fail + +While it's true that for most loaders the boot command never returns, it +may be the case that it does. For example the GRUB emulator boot command +calls to systemctl kexec which in turn does an asynchonous call to kexec. + +So in this case GRUB will wrongly assume that the boot command fails and +print a "Failed to boot both default and fallback entries" even when the +kexec call later succeeds. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/menu.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index fe2e77a43e..ec0c92bade 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -285,7 +285,7 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + } + + /* Run a menu entry. */ +-static void ++static grub_err_t + grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + { + grub_err_t err = GRUB_ERR_NONE; +@@ -302,7 +302,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; +- return; ++ return grub_errno; + } + + errs_before = grub_err_printed_errors; +@@ -315,7 +315,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + grub_env_context_open (); + menu = grub_zalloc (sizeof (*menu)); + if (! menu) +- return; ++ return grub_errno; + grub_env_set_menu (menu); + if (auto_boot) + grub_env_set ("timeout", "0"); +@@ -385,7 +385,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + + if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) + /* Implicit execution of boot, only if something is loaded. */ +- grub_command_execute ("boot", 0, 0); ++ err = grub_command_execute ("boot", 0, 0); + + if (errs_before != grub_err_printed_errors) + grub_wait_after_message (); +@@ -408,6 +408,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + else + grub_env_unset ("default"); + grub_env_unset ("timeout"); ++ ++ return err; + } + + /* Execute ENTRY from the menu MENU, falling back to entries specified +@@ -422,10 +424,13 @@ grub_menu_execute_with_fallback (grub_menu_t menu, + void *callback_data) + { + int fallback_entry; ++ grub_err_t err; + + callback->notify_booting (entry, callback_data); + +- grub_menu_execute_entry (entry, 1); ++ err = grub_menu_execute_entry (entry, 1); ++ if (err == GRUB_ERR_NONE) ++ return; + + /* Deal with fallback entries. */ + while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback")) +@@ -436,11 +441,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu, + + entry = grub_menu_get_entry (menu, fallback_entry); + callback->notify_fallback (entry, callback_data); +- grub_menu_execute_entry (entry, 1); +- /* If the function call to execute the entry returns at all, then this is +- taken to indicate a boot failure. For menu entries that do something +- other than actually boot an operating system, this could assume +- incorrectly that something failed. */ ++ err = grub_menu_execute_entry (entry, 1); ++ if (err == GRUB_ERR_NONE) ++ return; + } + + if (!autobooted) diff --git a/0117-Print-grub-emu-linux-loader-messages-as-debug.patch b/0117-Print-grub-emu-linux-loader-messages-as-debug.patch deleted file mode 100644 index 2718a70..0000000 --- a/0117-Print-grub-emu-linux-loader-messages-as-debug.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 9 Apr 2019 12:42:37 +0200 -Subject: [PATCH] Print grub-emu linux loader messages as debug - -They just polute the output and should better be debug messages instead. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/loader/emu/linux.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c -index 5b85b225ee..22ab6af172 100644 ---- a/grub-core/loader/emu/linux.c -+++ b/grub-core/loader/emu/linux.c -@@ -50,7 +50,7 @@ grub_linux_boot (void) - initrd_param = grub_xasprintf("%s", ""); - } - -- grub_printf("%serforming 'kexec -l %s %s %s'\n", -+ grub_dprintf ("linux", "%serforming 'kexec -l %s %s %s'\n", - (kexecute) ? "P" : "Not p", - kernel_path, initrd_param, boot_cmdline); - -@@ -67,7 +67,7 @@ grub_linux_boot (void) - if (kexecute < 1) - grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart.")); - -- grub_printf("Performing 'systemctl kexec' (%s) ", -+ grub_dprintf ("linux", "Performing 'systemctl kexec' (%s) ", - (kexecute==1) ? "do-or-die" : "just-in-case"); - rc = grub_util_exec (systemctl); - diff --git a/0118-Don-t-assume-that-boot-commands-will-only-return-on-.patch b/0118-Don-t-assume-that-boot-commands-will-only-return-on-.patch deleted file mode 100644 index df36517..0000000 --- a/0118-Don-t-assume-that-boot-commands-will-only-return-on-.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 9 Apr 2019 13:12:40 +0200 -Subject: [PATCH] Don't assume that boot commands will only return on fail - -While it's true that for most loaders the boot command never returns, it -may be the case that it does. For example the GRUB emulator boot command -calls to systemctl kexec which in turn does an asynchonous call to kexec. - -So in this case GRUB will wrongly assume that the boot command fails and -print a "Failed to boot both default and fallback entries" even when the -kexec call later succeeds. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/normal/menu.c | 23 +++++++++++++---------- - 1 file changed, 13 insertions(+), 10 deletions(-) - -diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index fe2e77a43e..ec0c92bade 100644 ---- a/grub-core/normal/menu.c -+++ b/grub-core/normal/menu.c -@@ -285,7 +285,7 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) - } - - /* Run a menu entry. */ --static void -+static grub_err_t - grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) - { - grub_err_t err = GRUB_ERR_NONE; -@@ -302,7 +302,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; -- return; -+ return grub_errno; - } - - errs_before = grub_err_printed_errors; -@@ -315,7 +315,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) - grub_env_context_open (); - menu = grub_zalloc (sizeof (*menu)); - if (! menu) -- return; -+ return grub_errno; - grub_env_set_menu (menu); - if (auto_boot) - grub_env_set ("timeout", "0"); -@@ -385,7 +385,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) - - if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) - /* Implicit execution of boot, only if something is loaded. */ -- grub_command_execute ("boot", 0, 0); -+ err = grub_command_execute ("boot", 0, 0); - - if (errs_before != grub_err_printed_errors) - grub_wait_after_message (); -@@ -408,6 +408,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) - else - grub_env_unset ("default"); - grub_env_unset ("timeout"); -+ -+ return err; - } - - /* Execute ENTRY from the menu MENU, falling back to entries specified -@@ -422,10 +424,13 @@ grub_menu_execute_with_fallback (grub_menu_t menu, - void *callback_data) - { - int fallback_entry; -+ grub_err_t err; - - callback->notify_booting (entry, callback_data); - -- grub_menu_execute_entry (entry, 1); -+ err = grub_menu_execute_entry (entry, 1); -+ if (err == GRUB_ERR_NONE) -+ return; - - /* Deal with fallback entries. */ - while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback")) -@@ -436,11 +441,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu, - - entry = grub_menu_get_entry (menu, fallback_entry); - callback->notify_fallback (entry, callback_data); -- grub_menu_execute_entry (entry, 1); -- /* If the function call to execute the entry returns at all, then this is -- taken to indicate a boot failure. For menu entries that do something -- other than actually boot an operating system, this could assume -- incorrectly that something failed. */ -+ err = grub_menu_execute_entry (entry, 1); -+ if (err == GRUB_ERR_NONE) -+ return; - } - - if (!autobooted) diff --git a/0118-grub-set-bootflag-Update-comment-about-running-as-ro.patch b/0118-grub-set-bootflag-Update-comment-about-running-as-ro.patch new file mode 100644 index 0000000..9ffb3ae --- /dev/null +++ b/0118-grub-set-bootflag-Update-comment-about-running-as-ro.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 13 Nov 2019 12:15:43 +0100 +Subject: [PATCH] grub-set-bootflag: Update comment about running as root + through pkexec + +We have stopped using pkexec for grub-set-bootflag, instead it is now +installed suid root, update the comment accordingly. + +Signed-off-by: Hans de Goede +--- + util/grub-set-bootflag.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index a6ccc11383..3eb04beb5e 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -18,7 +18,7 @@ + */ + + /* +- * NOTE this gets run by users as root (through pkexec), so this does not ++ * NOTE this gets run by users as root (its suid root), so this does not + * use any grub library / util functions to allow for easy auditing. + * The grub headers are only included to get certain defines. + */ diff --git a/0119-grub-set-bootflag-Update-comment-about-running-as-ro.patch b/0119-grub-set-bootflag-Update-comment-about-running-as-ro.patch deleted file mode 100644 index 9ffb3ae..0000000 --- a/0119-grub-set-bootflag-Update-comment-about-running-as-ro.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 13 Nov 2019 12:15:43 +0100 -Subject: [PATCH] grub-set-bootflag: Update comment about running as root - through pkexec - -We have stopped using pkexec for grub-set-bootflag, instead it is now -installed suid root, update the comment accordingly. - -Signed-off-by: Hans de Goede ---- - util/grub-set-bootflag.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c -index a6ccc11383..3eb04beb5e 100644 ---- a/util/grub-set-bootflag.c -+++ b/util/grub-set-bootflag.c -@@ -18,7 +18,7 @@ - */ - - /* -- * NOTE this gets run by users as root (through pkexec), so this does not -+ * NOTE this gets run by users as root (its suid root), so this does not - * use any grub library / util functions to allow for easy auditing. - * The grub headers are only included to get certain defines. - */ diff --git a/0119-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch b/0119-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch new file mode 100644 index 0000000..11722d1 --- /dev/null +++ b/0119-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 13 Nov 2019 13:02:01 +0100 +Subject: [PATCH] grub-set-bootflag: Write new env to tmpfile and then rename + +Make the grubenv writing code in grub-set-bootflag more robust by +writing the modified grubenv to a tmpfile first and then renaming the +tmpfile over the old grubenv (following symlinks). + +Signed-off-by: Hans de Goede +--- + util/grub-set-bootflag.c | 87 +++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 78 insertions(+), 9 deletions(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index 3eb04beb5e..3b4c25ca2a 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -28,7 +28,9 @@ + #include + #include /* For GRUB_ENVBLK_DEFCFG define */ + #include ++#include + #include ++#include + #include + #include + +@@ -56,8 +58,10 @@ int main(int argc, char *argv[]) + { + /* NOTE buf must be at least the longest bootflag length + 4 bytes */ + char env[GRUBENV_SIZE + 1], buf[64], *s; ++ /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */ ++ char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1]; + const char *bootflag; +- int i, len, ret; ++ int i, fd, len, ret; + FILE *f; + + if (argc != 2) +@@ -89,7 +93,32 @@ int main(int argc, char *argv[]) + bootflag = bootflags[i]; + len = strlen (bootflag); + +- f = fopen (GRUBENV, "r"); ++ /* ++ * Really become root. setuid avoids an user killing us, possibly leaking ++ * the tmpfile. setgid avoids the new grubenv's gid being that of the user. ++ */ ++ ret = setuid(0); ++ if (ret) ++ { ++ perror ("Error setuid(0) failed"); ++ return 1; ++ } ++ ++ ret = setgid(0); ++ if (ret) ++ { ++ perror ("Error setgid(0) failed"); ++ return 1; ++ } ++ ++ /* Canonicalize GRUBENV filename, resolving symlinks, etc. */ ++ if (!realpath(GRUBENV, env_filename)) ++ { ++ perror ("Error canonicalizing " GRUBENV " filename"); ++ return 1; ++ } ++ ++ f = fopen (env_filename, "r"); + if (!f) + { + perror ("Error opening " GRUBENV " for reading"); +@@ -144,30 +173,70 @@ int main(int argc, char *argv[]) + snprintf(buf, sizeof(buf), "%s=1\n", bootflag); + memcpy(s, buf, len + 3); + +- /* "r+", don't truncate so that the diskspace stays reserved */ +- f = fopen (GRUBENV, "r+"); ++ ++ /* ++ * Create a tempfile for writing the new env. Use the canonicalized filename ++ * for the template so that the tmpfile is in the same dir / on same fs. ++ */ ++ snprintf(tmp_filename, sizeof(tmp_filename), "%sXXXXXX", env_filename); ++ fd = mkstemp(tmp_filename); ++ if (fd == -1) ++ { ++ perror ("Creating tmpfile failed"); ++ return 1; ++ } ++ ++ f = fdopen (fd, "w"); + if (!f) + { +- perror ("Error opening " GRUBENV " for writing"); ++ perror ("Error fdopen of tmpfile failed"); ++ unlink(tmp_filename); + return 1; + } + + ret = fwrite (env, 1, GRUBENV_SIZE, f); + if (ret != GRUBENV_SIZE) + { +- perror ("Error writing to " GRUBENV); ++ perror ("Error writing tmpfile"); ++ unlink(tmp_filename); + return 1; + } + + ret = fflush (f); + if (ret) + { +- perror ("Error flushing " GRUBENV); ++ perror ("Error flushing tmpfile"); ++ unlink(tmp_filename); + return 1; + } + +- fsync (fileno (f)); +- fclose (f); ++ ret = fsync (fileno (f)); ++ if (ret) ++ { ++ perror ("Error syncing tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ ret = fclose (f); ++ if (ret) ++ { ++ perror ("Error closing tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ /* ++ * And finally rename the tmpfile with the new env over the old env, the ++ * linux kernel guarantees that this is atomic (from a syscall pov). ++ */ ++ ret = rename(tmp_filename, env_filename); ++ if (ret) ++ { ++ perror ("Error renaming tmpfile to " GRUBENV " failed"); ++ unlink(tmp_filename); ++ return 1; ++ } + + return 0; + } diff --git a/0120-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch b/0120-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch deleted file mode 100644 index 11722d1..0000000 --- a/0120-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 13 Nov 2019 13:02:01 +0100 -Subject: [PATCH] grub-set-bootflag: Write new env to tmpfile and then rename - -Make the grubenv writing code in grub-set-bootflag more robust by -writing the modified grubenv to a tmpfile first and then renaming the -tmpfile over the old grubenv (following symlinks). - -Signed-off-by: Hans de Goede ---- - util/grub-set-bootflag.c | 87 +++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 78 insertions(+), 9 deletions(-) - -diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c -index 3eb04beb5e..3b4c25ca2a 100644 ---- a/util/grub-set-bootflag.c -+++ b/util/grub-set-bootflag.c -@@ -28,7 +28,9 @@ - #include - #include /* For GRUB_ENVBLK_DEFCFG define */ - #include -+#include - #include -+#include - #include - #include - -@@ -56,8 +58,10 @@ int main(int argc, char *argv[]) - { - /* NOTE buf must be at least the longest bootflag length + 4 bytes */ - char env[GRUBENV_SIZE + 1], buf[64], *s; -+ /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */ -+ char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1]; - const char *bootflag; -- int i, len, ret; -+ int i, fd, len, ret; - FILE *f; - - if (argc != 2) -@@ -89,7 +93,32 @@ int main(int argc, char *argv[]) - bootflag = bootflags[i]; - len = strlen (bootflag); - -- f = fopen (GRUBENV, "r"); -+ /* -+ * Really become root. setuid avoids an user killing us, possibly leaking -+ * the tmpfile. setgid avoids the new grubenv's gid being that of the user. -+ */ -+ ret = setuid(0); -+ if (ret) -+ { -+ perror ("Error setuid(0) failed"); -+ return 1; -+ } -+ -+ ret = setgid(0); -+ if (ret) -+ { -+ perror ("Error setgid(0) failed"); -+ return 1; -+ } -+ -+ /* Canonicalize GRUBENV filename, resolving symlinks, etc. */ -+ if (!realpath(GRUBENV, env_filename)) -+ { -+ perror ("Error canonicalizing " GRUBENV " filename"); -+ return 1; -+ } -+ -+ f = fopen (env_filename, "r"); - if (!f) - { - perror ("Error opening " GRUBENV " for reading"); -@@ -144,30 +173,70 @@ int main(int argc, char *argv[]) - snprintf(buf, sizeof(buf), "%s=1\n", bootflag); - memcpy(s, buf, len + 3); - -- /* "r+", don't truncate so that the diskspace stays reserved */ -- f = fopen (GRUBENV, "r+"); -+ -+ /* -+ * Create a tempfile for writing the new env. Use the canonicalized filename -+ * for the template so that the tmpfile is in the same dir / on same fs. -+ */ -+ snprintf(tmp_filename, sizeof(tmp_filename), "%sXXXXXX", env_filename); -+ fd = mkstemp(tmp_filename); -+ if (fd == -1) -+ { -+ perror ("Creating tmpfile failed"); -+ return 1; -+ } -+ -+ f = fdopen (fd, "w"); - if (!f) - { -- perror ("Error opening " GRUBENV " for writing"); -+ perror ("Error fdopen of tmpfile failed"); -+ unlink(tmp_filename); - return 1; - } - - ret = fwrite (env, 1, GRUBENV_SIZE, f); - if (ret != GRUBENV_SIZE) - { -- perror ("Error writing to " GRUBENV); -+ perror ("Error writing tmpfile"); -+ unlink(tmp_filename); - return 1; - } - - ret = fflush (f); - if (ret) - { -- perror ("Error flushing " GRUBENV); -+ perror ("Error flushing tmpfile"); -+ unlink(tmp_filename); - return 1; - } - -- fsync (fileno (f)); -- fclose (f); -+ ret = fsync (fileno (f)); -+ if (ret) -+ { -+ perror ("Error syncing tmpfile"); -+ unlink(tmp_filename); -+ return 1; -+ } -+ -+ ret = fclose (f); -+ if (ret) -+ { -+ perror ("Error closing tmpfile"); -+ unlink(tmp_filename); -+ return 1; -+ } -+ -+ /* -+ * And finally rename the tmpfile with the new env over the old env, the -+ * linux kernel guarantees that this is atomic (from a syscall pov). -+ */ -+ ret = rename(tmp_filename, env_filename); -+ if (ret) -+ { -+ perror ("Error renaming tmpfile to " GRUBENV " failed"); -+ unlink(tmp_filename); -+ return 1; -+ } - - return 0; - } diff --git a/0120-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch b/0120-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch new file mode 100644 index 0000000..948ff73 --- /dev/null +++ b/0120-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 26 Nov 2019 09:51:41 +0100 +Subject: [PATCH] grub.d: Fix boot_indeterminate getting set on boot_success=0 + boot +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The "grub.d: Split out boot success reset from menu auto hide script" +not only moved the code to clear boot_success and boot_indeterminate +but for some reason also mixed in some broken changes to the +boot_indeterminate handling. + +The boot_indeterminate var is meant to suppress the boot menu after +a reboot from either a selinux-relabel or offline-updates. These +2 special boot scenarios do not set boot_success since there is no +successfull interaction with the user. Instead they increment +boot_indeterminate, and if it is 1 and only when it is 1, so the +first reboot after a "special" boot we suppress the menu. + +To ensure that we do show the menu if we somehow get stuck in a +"special" boot loop where we do special-boots without them +incrementing boot_indeterminate, the code before the +"grub.d: Split out boot success reset from menu auto hide script" +commit would increment boot_indeterminate once when it is 1, so that +even if the "special" boot reboot-loop immediately we would show the +menu on the next boot. + +That commit broke this however, because it not only moves the code, +it also changes it from only "incrementing" boot_indeterminate once to +always incrementing it, except when boot_success == 1 (and we reset it). + +This broken behavior causes the following problem: + +1. Boot a broken kernel, system hangs, power-cycle +2. boot_success now != 1, so we increment boot_indeterminate from 0 + (unset!) to 1. User either simply tries again, or makes some changes + but the end-result still is a system hang, power-cycle +3. Now boot_indeterminate==1 so we do not show the menu even though the + previous boot failed -> BAD + +This commit fixes this by restoring the behavior of setting +boot_indeterminate to 2 when it was 1 before. + +Fixes: "grub.d: Split out boot success reset from menu auto hide script" +Signed-off-by: Hans de Goede +[jpokorny: 01_menu_auto_hide.in: fix a then/than typo] +Signed-off-by: Jan Pokorný +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_reset_boot_success.in | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in +index 6c88d933dd..e73f4137b3 100644 +--- a/util/grub.d/10_reset_boot_success.in ++++ b/util/grub.d/10_reset_boot_success.in +@@ -6,18 +6,18 @@ + # + # The boot_success var needs to be set to 1 from userspace to mark a boot successful. + cat << EOF +-insmod increment + # Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry + if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then + set menu_hide_ok=1 + else + set menu_hide_ok=0 + fi +-# Reset boot_indeterminate after a successful boot, increment otherwise ++# Reset boot_indeterminate after a successful boot + if [ "\${boot_success}" = "1" ] ; then + set boot_indeterminate=0 +-else +- increment boot_indeterminate ++# Avoid boot_indeterminate causing the menu to be hidden more than once ++elif [ "\${boot_indeterminate}" = "1" ]; then ++ set boot_indeterminate=2 + fi + # Reset boot_success for current boot + set boot_success=0 diff --git a/0121-Add-start-symbol-for-RISC-V.patch b/0121-Add-start-symbol-for-RISC-V.patch new file mode 100644 index 0000000..2746fa2 --- /dev/null +++ b/0121-Add-start-symbol-for-RISC-V.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Abdurachmanov +Date: Sat, 9 Nov 2019 19:51:57 +0000 +Subject: [PATCH] Add start symbol for RISC-V + +All other architectures have start symbol. + +Hopefully this resolves: + + BUILDSTDERR: ././grub-mkimage: error: undefined symbol start. + +Signed-off-by: David Abdurachmanov +--- + grub-core/kern/riscv/efi/startup.S | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/kern/riscv/efi/startup.S b/grub-core/kern/riscv/efi/startup.S +index f2a7b2b1ed..781773136e 100644 +--- a/grub-core/kern/riscv/efi/startup.S ++++ b/grub-core/kern/riscv/efi/startup.S +@@ -29,6 +29,7 @@ + + .file "startup.S" + .text ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. diff --git a/0121-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch b/0121-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch deleted file mode 100644 index 948ff73..0000000 --- a/0121-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 26 Nov 2019 09:51:41 +0100 -Subject: [PATCH] grub.d: Fix boot_indeterminate getting set on boot_success=0 - boot -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The "grub.d: Split out boot success reset from menu auto hide script" -not only moved the code to clear boot_success and boot_indeterminate -but for some reason also mixed in some broken changes to the -boot_indeterminate handling. - -The boot_indeterminate var is meant to suppress the boot menu after -a reboot from either a selinux-relabel or offline-updates. These -2 special boot scenarios do not set boot_success since there is no -successfull interaction with the user. Instead they increment -boot_indeterminate, and if it is 1 and only when it is 1, so the -first reboot after a "special" boot we suppress the menu. - -To ensure that we do show the menu if we somehow get stuck in a -"special" boot loop where we do special-boots without them -incrementing boot_indeterminate, the code before the -"grub.d: Split out boot success reset from menu auto hide script" -commit would increment boot_indeterminate once when it is 1, so that -even if the "special" boot reboot-loop immediately we would show the -menu on the next boot. - -That commit broke this however, because it not only moves the code, -it also changes it from only "incrementing" boot_indeterminate once to -always incrementing it, except when boot_success == 1 (and we reset it). - -This broken behavior causes the following problem: - -1. Boot a broken kernel, system hangs, power-cycle -2. boot_success now != 1, so we increment boot_indeterminate from 0 - (unset!) to 1. User either simply tries again, or makes some changes - but the end-result still is a system hang, power-cycle -3. Now boot_indeterminate==1 so we do not show the menu even though the - previous boot failed -> BAD - -This commit fixes this by restoring the behavior of setting -boot_indeterminate to 2 when it was 1 before. - -Fixes: "grub.d: Split out boot success reset from menu auto hide script" -Signed-off-by: Hans de Goede -[jpokorny: 01_menu_auto_hide.in: fix a then/than typo] -Signed-off-by: Jan Pokorný -Signed-off-by: Robbie Harwood ---- - util/grub.d/10_reset_boot_success.in | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in -index 6c88d933dd..e73f4137b3 100644 ---- a/util/grub.d/10_reset_boot_success.in -+++ b/util/grub.d/10_reset_boot_success.in -@@ -6,18 +6,18 @@ - # - # The boot_success var needs to be set to 1 from userspace to mark a boot successful. - cat << EOF --insmod increment - # Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry - if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then - set menu_hide_ok=1 - else - set menu_hide_ok=0 - fi --# Reset boot_indeterminate after a successful boot, increment otherwise -+# Reset boot_indeterminate after a successful boot - if [ "\${boot_success}" = "1" ] ; then - set boot_indeterminate=0 --else -- increment boot_indeterminate -+# Avoid boot_indeterminate causing the menu to be hidden more than once -+elif [ "\${boot_indeterminate}" = "1" ]; then -+ set boot_indeterminate=2 - fi - # Reset boot_success for current boot - set boot_success=0 diff --git a/0122-Add-start-symbol-for-RISC-V.patch b/0122-Add-start-symbol-for-RISC-V.patch deleted file mode 100644 index 2746fa2..0000000 --- a/0122-Add-start-symbol-for-RISC-V.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Abdurachmanov -Date: Sat, 9 Nov 2019 19:51:57 +0000 -Subject: [PATCH] Add start symbol for RISC-V - -All other architectures have start symbol. - -Hopefully this resolves: - - BUILDSTDERR: ././grub-mkimage: error: undefined symbol start. - -Signed-off-by: David Abdurachmanov ---- - grub-core/kern/riscv/efi/startup.S | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/grub-core/kern/riscv/efi/startup.S b/grub-core/kern/riscv/efi/startup.S -index f2a7b2b1ed..781773136e 100644 ---- a/grub-core/kern/riscv/efi/startup.S -+++ b/grub-core/kern/riscv/efi/startup.S -@@ -29,6 +29,7 @@ - - .file "startup.S" - .text -+FUNCTION(start) - FUNCTION(_start) - /* - * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. diff --git a/0122-bootstrap.conf-Force-autogen.sh-to-use-python3.patch b/0122-bootstrap.conf-Force-autogen.sh-to-use-python3.patch new file mode 100644 index 0000000..8bfc964 --- /dev/null +++ b/0122-bootstrap.conf-Force-autogen.sh-to-use-python3.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 15 Jan 2020 12:47:46 +0100 +Subject: [PATCH] bootstrap.conf: Force autogen.sh to use python3 + +The python-unversioned-command package is not installed in the buildroot, +but the bootstrap script expects the python command to be present if one +is not defined. So building the package leads to the following error: + +./autogen.sh: line 20: python: command not found + +This is harmless since gnulib is included as a source anyways, because the +builders can't download. But still the issue should be fixed by forcing to +use python3 that's the default in Fedora now. + +Signed-off-by: Javier Martinez Canillas +--- + bootstrap.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bootstrap.conf b/bootstrap.conf +index 6b043fc354..52d4af44be 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -92,7 +92,7 @@ bootstrap_post_import_hook () { + patch -d po -p3 \ + < "po/gettext-patches/$patchname.patch" + done +- FROM_BOOTSTRAP=1 ./autogen.sh ++ PYTHON=python3 FROM_BOOTSTRAP=1 ./autogen.sh + set +e # bootstrap expects this + } + diff --git a/0123-bootstrap.conf-Force-autogen.sh-to-use-python3.patch b/0123-bootstrap.conf-Force-autogen.sh-to-use-python3.patch deleted file mode 100644 index 8bfc964..0000000 --- a/0123-bootstrap.conf-Force-autogen.sh-to-use-python3.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 15 Jan 2020 12:47:46 +0100 -Subject: [PATCH] bootstrap.conf: Force autogen.sh to use python3 - -The python-unversioned-command package is not installed in the buildroot, -but the bootstrap script expects the python command to be present if one -is not defined. So building the package leads to the following error: - -./autogen.sh: line 20: python: command not found - -This is harmless since gnulib is included as a source anyways, because the -builders can't download. But still the issue should be fixed by forcing to -use python3 that's the default in Fedora now. - -Signed-off-by: Javier Martinez Canillas ---- - bootstrap.conf | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/bootstrap.conf b/bootstrap.conf -index 6b043fc354..52d4af44be 100644 ---- a/bootstrap.conf -+++ b/bootstrap.conf -@@ -92,7 +92,7 @@ bootstrap_post_import_hook () { - patch -d po -p3 \ - < "po/gettext-patches/$patchname.patch" - done -- FROM_BOOTSTRAP=1 ./autogen.sh -+ PYTHON=python3 FROM_BOOTSTRAP=1 ./autogen.sh - set +e # bootstrap expects this - } - diff --git a/0123-efi-http-Export-fw-http-_path-variables-to-make-them.patch b/0123-efi-http-Export-fw-http-_path-variables-to-make-them.patch new file mode 100644 index 0000000..f745782 --- /dev/null +++ b/0123-efi-http-Export-fw-http-_path-variables-to-make-them.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 5 Mar 2020 16:21:47 +0100 +Subject: [PATCH] efi/http: Export {fw,http}_path variables to make them global + +The fw_path environment variable is used by http_configure() function to +determine the HTTP path that should be used as prefix when using relative +HTTP paths. And this is stored in the http_path environment variable. + +Later, that variable is looked up by grub_efihttp_open() to generate the +complete path to be used in the HTTP request. + +But these variables are not exported, which means that are not global and +so are only found in the initial context. + +This can cause commands like configfile that create a new context to fail +because the fw_path and http_path variables will not be found. + +Resolves: rhbz#1616395 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/kern/main.c | 1 + + grub-core/net/efi/http.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 1c540fc8c2..b573be6650 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -143,6 +143,7 @@ grub_set_prefix_and_root (void) + if (fw_path) + { + grub_env_set ("fw_path", fw_path); ++ grub_env_export ("fw_path"); + grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path); + grub_free (fw_path); + } +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index de351b2cd0..755b7a6d05 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -39,6 +39,7 @@ http_configure (struct grub_efi_net_device *dev, int prefer_ip6) + http_path++; + grub_env_unset ("http_path"); + grub_env_set ("http_path", http_path); ++ grub_env_export ("http_path"); + } + } + diff --git a/0124-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch b/0124-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch new file mode 100644 index 0000000..03d85c2 --- /dev/null +++ b/0124-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch @@ -0,0 +1,114 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 5 Mar 2020 16:21:58 +0100 +Subject: [PATCH] efi/http: Enclose literal IPv6 addresses in square brackets + +According to RFC 2732 (https://www.ietf.org/rfc/rfc2732.txt), literal IPv6 +addresses must be enclosed in square brackets. But GRUB currently does not +do this and is causing HTTP servers to send Bad Request (400) responses. + +For example, the following is the HTTP stream when fetching a config file: + +HEAD /EFI/BOOT/grub.cfg HTTP/1.1 +Host: 2000:dead:beef:a::1 +Accept: */* +User-Agent: UefiHttpBoot/1.0 + +HTTP/1.1 400 Bad Request +Date: Thu, 05 Mar 2020 14:46:02 GMT +Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d +Connection: close +Content-Type: text/html; charset=iso-8859-1 + +and after enclosing the IPv6 address the HTTP request is successful: + +HEAD /EFI/BOOT/grub.cfg HTTP/1.1 +Host: [2000:dead:beef:a::1] +Accept: */* +User-Agent: UefiHttpBoot/1.0 + +HTTP/1.1 200 OK +Date: Thu, 05 Mar 2020 14:48:04 GMT +Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d +Last-Modified: Thu, 27 Feb 2020 17:45:58 GMT +ETag: "206-59f924b24b1da" +Accept-Ranges: bytes +Content-Length: 518 + +Resolves: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/http.c | 37 ++++++++++++++++++++++++++++--------- + 1 file changed, 28 insertions(+), 9 deletions(-) + +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index 755b7a6d05..fc8cb25ae0 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -158,13 +158,7 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + grub_efi_status_t status; + grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; + char *url = NULL; +- +- request_headers[0].field_name = (grub_efi_char8_t *)"Host"; +- request_headers[0].field_value = (grub_efi_char8_t *)server; +- request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; +- request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; +- request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; +- request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ char *hostname = NULL; + + { + grub_efi_ipv6_address_t address; +@@ -174,9 +168,24 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + const char *protocol = (use_https == 1) ? "https" : "http"; + + if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) +- url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); ++ { ++ hostname = grub_xasprintf ("[%s]", server); ++ if (!hostname) ++ return GRUB_ERR_OUT_OF_MEMORY; ++ ++ server = hostname; ++ ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ if (!url) ++ { ++ grub_free (hostname); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ } + else +- url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ { ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ } + + if (!url) + { +@@ -199,6 +208,13 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + request_data.url = ucs2_url; + } + ++ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; ++ request_headers[0].field_value = (grub_efi_char8_t *)server; ++ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; ++ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; ++ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; ++ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ + request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; + + request_message.data.request = &request_data; +@@ -228,6 +244,9 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + + status = efi_call_2 (http->request, http, &request_token); + ++ if (hostname) ++ grub_free (hostname); ++ + if (status != GRUB_EFI_SUCCESS) + { + efi_call_1 (b->close_event, request_token.event); diff --git a/0124-efi-http-Export-fw-http-_path-variables-to-make-them.patch b/0124-efi-http-Export-fw-http-_path-variables-to-make-them.patch deleted file mode 100644 index f745782..0000000 --- a/0124-efi-http-Export-fw-http-_path-variables-to-make-them.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Thu, 5 Mar 2020 16:21:47 +0100 -Subject: [PATCH] efi/http: Export {fw,http}_path variables to make them global - -The fw_path environment variable is used by http_configure() function to -determine the HTTP path that should be used as prefix when using relative -HTTP paths. And this is stored in the http_path environment variable. - -Later, that variable is looked up by grub_efihttp_open() to generate the -complete path to be used in the HTTP request. - -But these variables are not exported, which means that are not global and -so are only found in the initial context. - -This can cause commands like configfile that create a new context to fail -because the fw_path and http_path variables will not be found. - -Resolves: rhbz#1616395 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/kern/main.c | 1 + - grub-core/net/efi/http.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c -index 1c540fc8c2..b573be6650 100644 ---- a/grub-core/kern/main.c -+++ b/grub-core/kern/main.c -@@ -143,6 +143,7 @@ grub_set_prefix_and_root (void) - if (fw_path) - { - grub_env_set ("fw_path", fw_path); -+ grub_env_export ("fw_path"); - grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path); - grub_free (fw_path); - } -diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c -index de351b2cd0..755b7a6d05 100644 ---- a/grub-core/net/efi/http.c -+++ b/grub-core/net/efi/http.c -@@ -39,6 +39,7 @@ http_configure (struct grub_efi_net_device *dev, int prefer_ip6) - http_path++; - grub_env_unset ("http_path"); - grub_env_set ("http_path", http_path); -+ grub_env_export ("http_path"); - } - } - diff --git a/0125-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch b/0125-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch deleted file mode 100644 index 03d85c2..0000000 --- a/0125-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Thu, 5 Mar 2020 16:21:58 +0100 -Subject: [PATCH] efi/http: Enclose literal IPv6 addresses in square brackets - -According to RFC 2732 (https://www.ietf.org/rfc/rfc2732.txt), literal IPv6 -addresses must be enclosed in square brackets. But GRUB currently does not -do this and is causing HTTP servers to send Bad Request (400) responses. - -For example, the following is the HTTP stream when fetching a config file: - -HEAD /EFI/BOOT/grub.cfg HTTP/1.1 -Host: 2000:dead:beef:a::1 -Accept: */* -User-Agent: UefiHttpBoot/1.0 - -HTTP/1.1 400 Bad Request -Date: Thu, 05 Mar 2020 14:46:02 GMT -Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d -Connection: close -Content-Type: text/html; charset=iso-8859-1 - -and after enclosing the IPv6 address the HTTP request is successful: - -HEAD /EFI/BOOT/grub.cfg HTTP/1.1 -Host: [2000:dead:beef:a::1] -Accept: */* -User-Agent: UefiHttpBoot/1.0 - -HTTP/1.1 200 OK -Date: Thu, 05 Mar 2020 14:48:04 GMT -Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d -Last-Modified: Thu, 27 Feb 2020 17:45:58 GMT -ETag: "206-59f924b24b1da" -Accept-Ranges: bytes -Content-Length: 518 - -Resolves: rhbz#1732765 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/net/efi/http.c | 37 ++++++++++++++++++++++++++++--------- - 1 file changed, 28 insertions(+), 9 deletions(-) - -diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c -index 755b7a6d05..fc8cb25ae0 100644 ---- a/grub-core/net/efi/http.c -+++ b/grub-core/net/efi/http.c -@@ -158,13 +158,7 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, - grub_efi_status_t status; - grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; - char *url = NULL; -- -- request_headers[0].field_name = (grub_efi_char8_t *)"Host"; -- request_headers[0].field_value = (grub_efi_char8_t *)server; -- request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; -- request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; -- request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; -- request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; -+ char *hostname = NULL; - - { - grub_efi_ipv6_address_t address; -@@ -174,9 +168,24 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, - const char *protocol = (use_https == 1) ? "https" : "http"; - - if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) -- url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); -+ { -+ hostname = grub_xasprintf ("[%s]", server); -+ if (!hostname) -+ return GRUB_ERR_OUT_OF_MEMORY; -+ -+ server = hostname; -+ -+ url = grub_xasprintf ("%s://%s%s", protocol, server, name); -+ if (!url) -+ { -+ grub_free (hostname); -+ return GRUB_ERR_OUT_OF_MEMORY; -+ } -+ } - else -- url = grub_xasprintf ("%s://%s%s", protocol, server, name); -+ { -+ url = grub_xasprintf ("%s://%s%s", protocol, server, name); -+ } - - if (!url) - { -@@ -199,6 +208,13 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, - request_data.url = ucs2_url; - } - -+ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; -+ request_headers[0].field_value = (grub_efi_char8_t *)server; -+ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; -+ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; -+ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; -+ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; -+ - request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; - - request_message.data.request = &request_data; -@@ -228,6 +244,9 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, - - status = efi_call_2 (http->request, http, &request_token); - -+ if (hostname) -+ grub_free (hostname); -+ - if (status != GRUB_EFI_SUCCESS) - { - efi_call_1 (b->close_event, request_token.event); diff --git a/0125-efi-net-Allow-to-specify-a-port-number-in-addresses.patch b/0125-efi-net-Allow-to-specify-a-port-number-in-addresses.patch new file mode 100644 index 0000000..8fe26cd --- /dev/null +++ b/0125-efi-net-Allow-to-specify-a-port-number-in-addresses.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 9 Mar 2020 15:29:45 +0100 +Subject: [PATCH] efi/net: Allow to specify a port number in addresses + +The grub_efi_net_parse_address() function is not covering the case where a +port number is specified in an IPv4 or IPv6 address, so will fail to parse +the network address. + +For most cases the issue is harmless, because the function is only used to +match an address with a network interface and if fails the default is used. + +But still is a bug that has to be fixed and it causes error messages to be +printed like the following: + +error: net/efi/net.c:782:unrecognised network address '192.168.122.1:8080' + +error: net/efi/net.c:781:unrecognised network address '[2000:dead:beef:a::1]:8080' + +Resolves: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 6603cd83ed..84573937b1 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -742,7 +742,7 @@ grub_efi_net_parse_address (const char *address, + return GRUB_ERR_NONE; + } + } +- else if (*rest == 0) ++ else if (*rest == 0 || *rest == ':') + { + grub_uint32_t subnet_mask = 0xffffffffU; + grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); +@@ -768,7 +768,7 @@ grub_efi_net_parse_address (const char *address, + return GRUB_ERR_NONE; + } + } +- else if (*rest == 0) ++ else if (*rest == 0 || *rest == ':') + { + ip6->prefix_length = 128; + ip6->is_anycast = 0; diff --git a/0126-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch b/0126-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch new file mode 100644 index 0000000..2dc7001 --- /dev/null +++ b/0126-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 9 Mar 2020 15:30:05 +0100 +Subject: [PATCH] efi/ip4_config: Improve check to detect literal IPv6 + addresses + +The grub_efi_string_to_ip4_address() function wrongly assumes that an IPv6 +address is an IPv4 address, because it doesn't take into account the case +of a caller passing an IPv6 address as a string. + +This leads to the grub_efi_net_parse_address() function to fail and print +the following error message: + +error: net/efi/net.c:785:unrecognised network address '2000:dead:beef:a::1' + +Resolves: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/ip4_config.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +index b711a5d945..313c818b18 100644 +--- a/grub-core/net/efi/ip4_config.c ++++ b/grub-core/net/efi/ip4_config.c +@@ -56,9 +56,20 @@ int + grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) + { + grub_uint32_t newip = 0; +- int i; ++ int i, ncolon = 0; + const char *ptr = val; + ++ /* Check that is not an IPv6 address */ ++ for (i = 0; i < grub_strlen(ptr); i++) ++ { ++ if (ptr[i] == '[' && i == 0) ++ return 0; ++ ++ if (ptr[i] == ':') ++ if (i == 0 || ++ncolon == 2) ++ return 0; ++ } ++ + for (i = 0; i < 4; i++) + { + unsigned long t; diff --git a/0126-efi-net-Allow-to-specify-a-port-number-in-addresses.patch b/0126-efi-net-Allow-to-specify-a-port-number-in-addresses.patch deleted file mode 100644 index 8fe26cd..0000000 --- a/0126-efi-net-Allow-to-specify-a-port-number-in-addresses.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 9 Mar 2020 15:29:45 +0100 -Subject: [PATCH] efi/net: Allow to specify a port number in addresses - -The grub_efi_net_parse_address() function is not covering the case where a -port number is specified in an IPv4 or IPv6 address, so will fail to parse -the network address. - -For most cases the issue is harmless, because the function is only used to -match an address with a network interface and if fails the default is used. - -But still is a bug that has to be fixed and it causes error messages to be -printed like the following: - -error: net/efi/net.c:782:unrecognised network address '192.168.122.1:8080' - -error: net/efi/net.c:781:unrecognised network address '[2000:dead:beef:a::1]:8080' - -Resolves: rhbz#1732765 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/net/efi/net.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c -index 6603cd83ed..84573937b1 100644 ---- a/grub-core/net/efi/net.c -+++ b/grub-core/net/efi/net.c -@@ -742,7 +742,7 @@ grub_efi_net_parse_address (const char *address, - return GRUB_ERR_NONE; - } - } -- else if (*rest == 0) -+ else if (*rest == 0 || *rest == ':') - { - grub_uint32_t subnet_mask = 0xffffffffU; - grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); -@@ -768,7 +768,7 @@ grub_efi_net_parse_address (const char *address, - return GRUB_ERR_NONE; - } - } -- else if (*rest == 0) -+ else if (*rest == 0 || *rest == ':') - { - ip6->prefix_length = 128; - ip6->is_anycast = 0; diff --git a/0127-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch b/0127-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch deleted file mode 100644 index 2dc7001..0000000 --- a/0127-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 9 Mar 2020 15:30:05 +0100 -Subject: [PATCH] efi/ip4_config: Improve check to detect literal IPv6 - addresses - -The grub_efi_string_to_ip4_address() function wrongly assumes that an IPv6 -address is an IPv4 address, because it doesn't take into account the case -of a caller passing an IPv6 address as a string. - -This leads to the grub_efi_net_parse_address() function to fail and print -the following error message: - -error: net/efi/net.c:785:unrecognised network address '2000:dead:beef:a::1' - -Resolves: rhbz#1732765 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/net/efi/ip4_config.c | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c -index b711a5d945..313c818b18 100644 ---- a/grub-core/net/efi/ip4_config.c -+++ b/grub-core/net/efi/ip4_config.c -@@ -56,9 +56,20 @@ int - grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) - { - grub_uint32_t newip = 0; -- int i; -+ int i, ncolon = 0; - const char *ptr = val; - -+ /* Check that is not an IPv6 address */ -+ for (i = 0; i < grub_strlen(ptr); i++) -+ { -+ if (ptr[i] == '[' && i == 0) -+ return 0; -+ -+ if (ptr[i] == ':') -+ if (i == 0 || ++ncolon == 2) -+ return 0; -+ } -+ - for (i = 0; i < 4; i++) - { - unsigned long t; diff --git a/0127-efi-net-Print-a-debug-message-if-parsing-the-address.patch b/0127-efi-net-Print-a-debug-message-if-parsing-the-address.patch new file mode 100644 index 0000000..da94e08 --- /dev/null +++ b/0127-efi-net-Print-a-debug-message-if-parsing-the-address.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 10 Mar 2020 11:23:49 +0100 +Subject: [PATCH] efi/net: Print a debug message if parsing the address fails + +Currently if parsing the address fails an error message is printed. But in +most cases this isn't a fatal error since the grub_efi_net_parse_address() +function is only used to match an address with a network interface to use. + +And if this fails, the default interface is used which is good enough for +most cases. So instead of printing an error that would pollute the console +just print a debug message if the address is not parsed correctly. + +A user can enable debug messages for the efinet driver to have information +about the failure and the fact that the default interface is being used. + +Related: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/net.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 84573937b1..a3f0535d43 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -778,9 +778,9 @@ grub_efi_net_parse_address (const char *address, + } + } + +- return grub_error (GRUB_ERR_NET_BAD_ADDRESS, +- N_("unrecognised network address `%s'"), +- address); ++ grub_dprintf ("efinet", "unrecognised network address '%s'\n", address); ++ ++ return GRUB_ERR_NET_BAD_ADDRESS; + } + + static grub_efi_net_interface_t * +@@ -795,10 +795,7 @@ match_route (const char *server) + err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); + + if (err) +- { +- grub_print_error (); + return NULL; +- } + + if (is_ip6) + { +@@ -1233,8 +1230,15 @@ grub_net_open_real (const char *name __attribute__ ((unused))) + /*FIXME: Use DNS translate name to address */ + net_interface = match_route (server); + ++ if (!net_interface && net_default_interface) ++ { ++ net_interface = net_default_interface; ++ grub_dprintf ("efinet", "interface lookup failed, using default '%s'\n", ++ net_interface->name); ++ } ++ + /*XXX: should we check device with default gateway ? */ +- if (!net_interface && !(net_interface = net_default_interface)) ++ if (!net_interface) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), + name); diff --git a/0128-efi-net-Print-a-debug-message-if-parsing-the-address.patch b/0128-efi-net-Print-a-debug-message-if-parsing-the-address.patch deleted file mode 100644 index da94e08..0000000 --- a/0128-efi-net-Print-a-debug-message-if-parsing-the-address.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 10 Mar 2020 11:23:49 +0100 -Subject: [PATCH] efi/net: Print a debug message if parsing the address fails - -Currently if parsing the address fails an error message is printed. But in -most cases this isn't a fatal error since the grub_efi_net_parse_address() -function is only used to match an address with a network interface to use. - -And if this fails, the default interface is used which is good enough for -most cases. So instead of printing an error that would pollute the console -just print a debug message if the address is not parsed correctly. - -A user can enable debug messages for the efinet driver to have information -about the failure and the fact that the default interface is being used. - -Related: rhbz#1732765 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/net/efi/net.c | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c -index 84573937b1..a3f0535d43 100644 ---- a/grub-core/net/efi/net.c -+++ b/grub-core/net/efi/net.c -@@ -778,9 +778,9 @@ grub_efi_net_parse_address (const char *address, - } - } - -- return grub_error (GRUB_ERR_NET_BAD_ADDRESS, -- N_("unrecognised network address `%s'"), -- address); -+ grub_dprintf ("efinet", "unrecognised network address '%s'\n", address); -+ -+ return GRUB_ERR_NET_BAD_ADDRESS; - } - - static grub_efi_net_interface_t * -@@ -795,10 +795,7 @@ match_route (const char *server) - err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); - - if (err) -- { -- grub_print_error (); - return NULL; -- } - - if (is_ip6) - { -@@ -1233,8 +1230,15 @@ grub_net_open_real (const char *name __attribute__ ((unused))) - /*FIXME: Use DNS translate name to address */ - net_interface = match_route (server); - -+ if (!net_interface && net_default_interface) -+ { -+ net_interface = net_default_interface; -+ grub_dprintf ("efinet", "interface lookup failed, using default '%s'\n", -+ net_interface->name); -+ } -+ - /*XXX: should we check device with default gateway ? */ -- if (!net_interface && !(net_interface = net_default_interface)) -+ if (!net_interface) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), - name); diff --git a/0128-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch b/0128-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch new file mode 100644 index 0000000..8793b0d --- /dev/null +++ b/0128-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 22 Apr 2020 12:41:52 +0200 +Subject: [PATCH] kern/term: Also accept F8 as a user interrupt key + +Make F8, which used to be the hotkey to show the Windows boot menu during +boot for a long long time, also interrupt sleeps / stop the menu countdown. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/kern/term.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c +index 14d5964983..4d61f4e979 100644 +--- a/grub-core/kern/term.c ++++ b/grub-core/kern/term.c +@@ -144,9 +144,10 @@ grub_key_is_interrupt (int key) + /* + * ESC sometimes is the BIOS setup hotkey and may be hard to discover, also + * check F4, which was chosen because is not used as a hotkey to enter the +- * BIOS setup by any vendor. ++ * BIOS setup by any vendor. Also, F8 which was the key to get the Windows ++ * bootmenu for a long time. + */ +- if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4) ++ if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4 || key == GRUB_TERM_KEY_F8) + return 1; + + /* diff --git a/0129-efi-Set-image-base-address-before-jumping-to-the-PE-.patch b/0129-efi-Set-image-base-address-before-jumping-to-the-PE-.patch new file mode 100644 index 0000000..6aa5013 --- /dev/null +++ b/0129-efi-Set-image-base-address-before-jumping-to-the-PE-.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 23 Apr 2020 15:06:46 +0200 +Subject: [PATCH] efi: Set image base address before jumping to the PE/COFF + entry point + +Upstream GRUB uses the EFI LoadImage() and StartImage() to boot the Linux +kernel. But our custom EFI loader that supports Secure Boot instead uses +the EFI handover protocol (for x86) or jumping directly to the PE/COFF +entry point (for aarch64). + +This is done to allow the bootloader to verify the images using the shim +lock protocol to avoid booting untrusted binaries. + +Since the bootloader loads the kernel from the boot media instead of using +LoadImage(), it is responsible to set the Loaded Image base address before +booting the kernel. + +Otherwise the kernel EFI stub will complain that it was not set correctly +and print the following warning message: + +EFI stub: ERROR: FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value + +Resolves: rhbz#1814690 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/efi/linux.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 0622dfa48d..e8b9ecb17f 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -72,6 +72,7 @@ grub_err_t + grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + void *kernel_params) + { ++ grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + int offset = 0; + +@@ -79,6 +80,19 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + offset = 512; + #endif + ++ /* ++ * Since the EFI loader is not calling the LoadImage() and StartImage() ++ * services for loading the kernel and booting respectively, it has to ++ * set the Loaded Image base address. ++ */ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ loaded_image->image_base = kernel_addr; ++ else ++ grub_dprintf ("linux", "Loaded Image base address could not be set\n"); ++ ++ grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", ++ kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + diff --git a/0129-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch b/0129-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch deleted file mode 100644 index 8793b0d..0000000 --- a/0129-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 22 Apr 2020 12:41:52 +0200 -Subject: [PATCH] kern/term: Also accept F8 as a user interrupt key - -Make F8, which used to be the hotkey to show the Windows boot menu during -boot for a long long time, also interrupt sleeps / stop the menu countdown. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/kern/term.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c -index 14d5964983..4d61f4e979 100644 ---- a/grub-core/kern/term.c -+++ b/grub-core/kern/term.c -@@ -144,9 +144,10 @@ grub_key_is_interrupt (int key) - /* - * ESC sometimes is the BIOS setup hotkey and may be hard to discover, also - * check F4, which was chosen because is not used as a hotkey to enter the -- * BIOS setup by any vendor. -+ * BIOS setup by any vendor. Also, F8 which was the key to get the Windows -+ * bootmenu for a long time. - */ -- if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4) -+ if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4 || key == GRUB_TERM_KEY_F8) - return 1; - - /* diff --git a/0130-efi-Set-image-base-address-before-jumping-to-the-PE-.patch b/0130-efi-Set-image-base-address-before-jumping-to-the-PE-.patch deleted file mode 100644 index 6aa5013..0000000 --- a/0130-efi-Set-image-base-address-before-jumping-to-the-PE-.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Thu, 23 Apr 2020 15:06:46 +0200 -Subject: [PATCH] efi: Set image base address before jumping to the PE/COFF - entry point - -Upstream GRUB uses the EFI LoadImage() and StartImage() to boot the Linux -kernel. But our custom EFI loader that supports Secure Boot instead uses -the EFI handover protocol (for x86) or jumping directly to the PE/COFF -entry point (for aarch64). - -This is done to allow the bootloader to verify the images using the shim -lock protocol to avoid booting untrusted binaries. - -Since the bootloader loads the kernel from the boot media instead of using -LoadImage(), it is responsible to set the Loaded Image base address before -booting the kernel. - -Otherwise the kernel EFI stub will complain that it was not set correctly -and print the following warning message: - -EFI stub: ERROR: FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value - -Resolves: rhbz#1814690 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/loader/efi/linux.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c -index 0622dfa48d..e8b9ecb17f 100644 ---- a/grub-core/loader/efi/linux.c -+++ b/grub-core/loader/efi/linux.c -@@ -72,6 +72,7 @@ grub_err_t - grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, - void *kernel_params) - { -+ grub_efi_loaded_image_t *loaded_image = NULL; - handover_func hf; - int offset = 0; - -@@ -79,6 +80,19 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, - offset = 512; - #endif - -+ /* -+ * Since the EFI loader is not calling the LoadImage() and StartImage() -+ * services for loading the kernel and booting respectively, it has to -+ * set the Loaded Image base address. -+ */ -+ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); -+ if (loaded_image) -+ loaded_image->image_base = kernel_addr; -+ else -+ grub_dprintf ("linux", "Loaded Image base address could not be set\n"); -+ -+ grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", -+ kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); - hf = (handover_func)((char *)kernel_addr + handover_offset + offset); - hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); - diff --git a/0130-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch b/0130-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch new file mode 100644 index 0000000..d1c7b17 --- /dev/null +++ b/0130-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Sat, 16 May 2020 11:33:18 +0200 +Subject: [PATCH] tpm: Don't propagate TPM measurement errors to the verifiers + layer + +Currently if the EFI firmware fails to do a TPM measurement for a file, +the error will be propagated to the verifiers framework and so opening +the file will not succeed. + +This mean that buggy firmwares will prevent the system to boot since the +loader won't be able to open any file. But failing to do TPM measurements +shouldn't be a fatal error and the system should still be able to boot. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/commands/tpm.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c +index 2052c36eab..e287d042e6 100644 +--- a/grub-core/commands/tpm.c ++++ b/grub-core/commands/tpm.c +@@ -42,7 +42,8 @@ grub_tpm_verify_init (grub_file_t io, + static grub_err_t + grub_tpm_verify_write (void *context, void *buf, grub_size_t size) + { +- return grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context); ++ grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context); ++ return GRUB_ERR_NONE; + } + + static grub_err_t +@@ -50,7 +51,6 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type) + { + const char *prefix = NULL; + char *description; +- grub_err_t status; + + switch (type) + { +@@ -66,15 +66,15 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type) + } + description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1); + if (!description) +- return grub_errno; ++ return GRUB_ERR_NONE; + grub_memcpy (description, prefix, grub_strlen (prefix)); + grub_memcpy (description + grub_strlen (prefix), str, + grub_strlen (str) + 1); +- status = +- grub_tpm_measure ((unsigned char *) str, grub_strlen (str), +- GRUB_STRING_PCR, description); ++ ++ grub_tpm_measure ((unsigned char *) str, grub_strlen (str), GRUB_STRING_PCR, ++ description); + grub_free (description); +- return status; ++ return GRUB_ERR_NONE; + } + + struct grub_file_verifier grub_tpm_verifier = { diff --git a/0131-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch b/0131-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch deleted file mode 100644 index d1c7b17..0000000 --- a/0131-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Sat, 16 May 2020 11:33:18 +0200 -Subject: [PATCH] tpm: Don't propagate TPM measurement errors to the verifiers - layer - -Currently if the EFI firmware fails to do a TPM measurement for a file, -the error will be propagated to the verifiers framework and so opening -the file will not succeed. - -This mean that buggy firmwares will prevent the system to boot since the -loader won't be able to open any file. But failing to do TPM measurements -shouldn't be a fatal error and the system should still be able to boot. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/commands/tpm.c | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c -index 2052c36eab..e287d042e6 100644 ---- a/grub-core/commands/tpm.c -+++ b/grub-core/commands/tpm.c -@@ -42,7 +42,8 @@ grub_tpm_verify_init (grub_file_t io, - static grub_err_t - grub_tpm_verify_write (void *context, void *buf, grub_size_t size) - { -- return grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context); -+ grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context); -+ return GRUB_ERR_NONE; - } - - static grub_err_t -@@ -50,7 +51,6 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type) - { - const char *prefix = NULL; - char *description; -- grub_err_t status; - - switch (type) - { -@@ -66,15 +66,15 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type) - } - description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1); - if (!description) -- return grub_errno; -+ return GRUB_ERR_NONE; - grub_memcpy (description, prefix, grub_strlen (prefix)); - grub_memcpy (description + grub_strlen (prefix), str, - grub_strlen (str) + 1); -- status = -- grub_tpm_measure ((unsigned char *) str, grub_strlen (str), -- GRUB_STRING_PCR, description); -+ -+ grub_tpm_measure ((unsigned char *) str, grub_strlen (str), GRUB_STRING_PCR, -+ description); - grub_free (description); -- return status; -+ return GRUB_ERR_NONE; - } - - struct grub_file_verifier grub_tpm_verifier = { diff --git a/0131-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch b/0131-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch new file mode 100644 index 0000000..7c41e87 --- /dev/null +++ b/0131-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 26 May 2020 16:59:28 +0200 +Subject: [PATCH] x86-efi: Reduce maximum bounce buffer size to 16 MiB + +The EFI linux loader allocates a bounce buffer to copy the initrd since in +some machines doing DMA on addresses above 4GB is not possible during EFI. + +But the verifiers framework also allocates a buffer to copy the initrd in +its grub_file_open() handler. It does this since the data to verify has to +be passed as a single chunk to modules that use the verifiers framework. + +If the initrd image size is big there may not be enough memory in the heap +to allocate two buffers of that size. This causes an allocation failure in +the verifiers framework and leads to the initrd not being read. + +To prevent these allocation failures, let's reduce the maximum size of the +bounce buffer used in the EFI loader. Since the data read can be copied to +the actual initrd address in multilple chunks. + +Resolves: rhbz#1838633 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/i386/efi/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 6bc18d5aef..15d40d6e35 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -144,7 +144,7 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + +-#define BOUNCE_BUFFER_MAX 0x10000000ull ++#define BOUNCE_BUFFER_MAX 0x1000000ull + + static grub_ssize_t + read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) diff --git a/0132-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch b/0132-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch new file mode 100644 index 0000000..7fef93e --- /dev/null +++ b/0132-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 2 Jun 2020 13:25:01 +0200 +Subject: [PATCH] http: Prepend prefix when the HTTP path is relative as done + in efi/http + +There are two different HTTP drivers that can be used when requesting an +HTTP resource: the efi/http that uses the EFI_HTTP_PROTOCOL and the http +that uses GRUB's HTTP and TCP/IP implementation. + +The efi/http driver appends a prefix that is defined in the variable +http_path, but the http driver doesn't. + +So using this driver and attempting to fetch a resource using a relative +path fails. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/http.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index b52b558d63..7f878b5615 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -501,13 +501,20 @@ http_open (struct grub_file *file, const char *filename) + { + grub_err_t err; + struct http_data *data; ++ const char *http_path; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return grub_errno; + file->size = GRUB_FILE_SIZE_UNKNOWN; + +- data->filename = grub_strdup (filename); ++ /* If path is relative, prepend http_path */ ++ http_path = grub_env_get ("http_path"); ++ if (http_path && filename[0] != '/') ++ data->filename = grub_xasprintf ("%s/%s", http_path, filename); ++ else ++ data->filename = grub_strdup (filename); ++ + if (!data->filename) + { + grub_free (data); diff --git a/0132-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch b/0132-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch deleted file mode 100644 index 7c41e87..0000000 --- a/0132-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 26 May 2020 16:59:28 +0200 -Subject: [PATCH] x86-efi: Reduce maximum bounce buffer size to 16 MiB - -The EFI linux loader allocates a bounce buffer to copy the initrd since in -some machines doing DMA on addresses above 4GB is not possible during EFI. - -But the verifiers framework also allocates a buffer to copy the initrd in -its grub_file_open() handler. It does this since the data to verify has to -be passed as a single chunk to modules that use the verifiers framework. - -If the initrd image size is big there may not be enough memory in the heap -to allocate two buffers of that size. This causes an allocation failure in -the verifiers framework and leads to the initrd not being read. - -To prevent these allocation failures, let's reduce the maximum size of the -bounce buffer used in the EFI loader. Since the data read can be copied to -the actual initrd address in multilple chunks. - -Resolves: rhbz#1838633 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/loader/i386/efi/linux.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 6bc18d5aef..15d40d6e35 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -144,7 +144,7 @@ grub_linuxefi_unload (void) - return GRUB_ERR_NONE; - } - --#define BOUNCE_BUFFER_MAX 0x10000000ull -+#define BOUNCE_BUFFER_MAX 0x1000000ull - - static grub_ssize_t - read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) diff --git a/0133-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch b/0133-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch new file mode 100644 index 0000000..f3b10c1 --- /dev/null +++ b/0133-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 16 Jan 2019 13:21:46 -0500 +Subject: [PATCH] Fix a missing return in efi-export-env and efi-load-env + commands + +Somewhere along the way this got mis-merged to include a return without +a value. Fix it up. + +Signed-off-by: Peter Jones +--- + grub-core/commands/efi/env.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c +index cbd13e03e8..977edb6b06 100644 +--- a/grub-core/commands/efi/env.c ++++ b/grub-core/commands/efi/env.c +@@ -149,6 +149,8 @@ grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)), + + grub_envblk_iterate (envblk, NULL, set_var); + grub_free (envblk_s.buf); ++ ++ return GRUB_ERR_NONE; + } + + static grub_command_t export_cmd, loadenv_cmd; diff --git a/0133-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch b/0133-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch deleted file mode 100644 index 7fef93e..0000000 --- a/0133-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 2 Jun 2020 13:25:01 +0200 -Subject: [PATCH] http: Prepend prefix when the HTTP path is relative as done - in efi/http - -There are two different HTTP drivers that can be used when requesting an -HTTP resource: the efi/http that uses the EFI_HTTP_PROTOCOL and the http -that uses GRUB's HTTP and TCP/IP implementation. - -The efi/http driver appends a prefix that is defined in the variable -http_path, but the http driver doesn't. - -So using this driver and attempting to fetch a resource using a relative -path fails. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/net/http.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/grub-core/net/http.c b/grub-core/net/http.c -index b52b558d63..7f878b5615 100644 ---- a/grub-core/net/http.c -+++ b/grub-core/net/http.c -@@ -501,13 +501,20 @@ http_open (struct grub_file *file, const char *filename) - { - grub_err_t err; - struct http_data *data; -+ const char *http_path; - - data = grub_zalloc (sizeof (*data)); - if (!data) - return grub_errno; - file->size = GRUB_FILE_SIZE_UNKNOWN; - -- data->filename = grub_strdup (filename); -+ /* If path is relative, prepend http_path */ -+ http_path = grub_env_get ("http_path"); -+ if (http_path && filename[0] != '/') -+ data->filename = grub_xasprintf ("%s/%s", http_path, filename); -+ else -+ data->filename = grub_strdup (filename); -+ - if (!data->filename) - { - grub_free (data); diff --git a/0134-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch b/0134-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch deleted file mode 100644 index f3b10c1..0000000 --- a/0134-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 16 Jan 2019 13:21:46 -0500 -Subject: [PATCH] Fix a missing return in efi-export-env and efi-load-env - commands - -Somewhere along the way this got mis-merged to include a return without -a value. Fix it up. - -Signed-off-by: Peter Jones ---- - grub-core/commands/efi/env.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c -index cbd13e03e8..977edb6b06 100644 ---- a/grub-core/commands/efi/env.c -+++ b/grub-core/commands/efi/env.c -@@ -149,6 +149,8 @@ grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)), - - grub_envblk_iterate (envblk, NULL, set_var); - grub_free (envblk_s.buf); -+ -+ return GRUB_ERR_NONE; - } - - static grub_command_t export_cmd, loadenv_cmd; diff --git a/0134-efi-dhcp-fix-some-allocation-error-checking.patch b/0134-efi-dhcp-fix-some-allocation-error-checking.patch new file mode 100644 index 0000000..90e7a34 --- /dev/null +++ b/0134-efi-dhcp-fix-some-allocation-error-checking.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 19 Jul 2020 17:11:06 -0400 +Subject: [PATCH] efi+dhcp: fix some allocation error checking. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/dhcp.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c +index dbef63d8c0..e5c79b748b 100644 +--- a/grub-core/net/efi/dhcp.c ++++ b/grub-core/net/efi/dhcp.c +@@ -80,7 +80,7 @@ grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packe + if (status != GRUB_EFI_BUFFER_TOO_SMALL) + return NULL; + +- option_list = grub_malloc (option_count * sizeof(*option_list)); ++ option_list = grub_calloc (option_count, sizeof(*option_list)); + if (!option_list) + return NULL; + +@@ -360,8 +360,11 @@ grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), + + if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) + { +- options = grub_malloc (count * sizeof(*options)); +- status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); ++ options = grub_calloc (count, sizeof(*options)); ++ if (options) ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); ++ else ++ status = GRUB_EFI_OUT_OF_RESOURCES; + } + + if (status != GRUB_EFI_SUCCESS) diff --git a/0135-efi-dhcp-fix-some-allocation-error-checking.patch b/0135-efi-dhcp-fix-some-allocation-error-checking.patch deleted file mode 100644 index 90e7a34..0000000 --- a/0135-efi-dhcp-fix-some-allocation-error-checking.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Sun, 19 Jul 2020 17:11:06 -0400 -Subject: [PATCH] efi+dhcp: fix some allocation error checking. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/dhcp.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c -index dbef63d8c0..e5c79b748b 100644 ---- a/grub-core/net/efi/dhcp.c -+++ b/grub-core/net/efi/dhcp.c -@@ -80,7 +80,7 @@ grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packe - if (status != GRUB_EFI_BUFFER_TOO_SMALL) - return NULL; - -- option_list = grub_malloc (option_count * sizeof(*option_list)); -+ option_list = grub_calloc (option_count, sizeof(*option_list)); - if (!option_list) - return NULL; - -@@ -360,8 +360,11 @@ grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), - - if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) - { -- options = grub_malloc (count * sizeof(*options)); -- status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); -+ options = grub_calloc (count, sizeof(*options)); -+ if (options) -+ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); -+ else -+ status = GRUB_EFI_OUT_OF_RESOURCES; - } - - if (status != GRUB_EFI_SUCCESS) diff --git a/0135-efi-http-fix-some-allocation-error-checking.patch b/0135-efi-http-fix-some-allocation-error-checking.patch new file mode 100644 index 0000000..149ada8 --- /dev/null +++ b/0135-efi-http-fix-some-allocation-error-checking.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 19 Jul 2020 17:14:15 -0400 +Subject: [PATCH] efi+http: fix some allocation error checking. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/http.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index fc8cb25ae0..26647a50fa 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -412,8 +412,8 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + int type) + { + grub_err_t err; +- grub_off_t size; +- char *buf; ++ grub_off_t size = 0; ++ char *buf = NULL; + char *file_name = NULL; + const char *http_path; + +@@ -441,8 +441,11 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + return err; + } + +- buf = grub_malloc (size); +- efihttp_read (dev, buf, size); ++ if (size) ++ { ++ buf = grub_malloc (size); ++ efihttp_read (dev, buf, size); ++ } + + file->size = size; + file->data = buf; diff --git a/0136-efi-http-fix-some-allocation-error-checking.patch b/0136-efi-http-fix-some-allocation-error-checking.patch deleted file mode 100644 index 149ada8..0000000 --- a/0136-efi-http-fix-some-allocation-error-checking.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Sun, 19 Jul 2020 17:14:15 -0400 -Subject: [PATCH] efi+http: fix some allocation error checking. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/http.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c -index fc8cb25ae0..26647a50fa 100644 ---- a/grub-core/net/efi/http.c -+++ b/grub-core/net/efi/http.c -@@ -412,8 +412,8 @@ grub_efihttp_open (struct grub_efi_net_device *dev, - int type) - { - grub_err_t err; -- grub_off_t size; -- char *buf; -+ grub_off_t size = 0; -+ char *buf = NULL; - char *file_name = NULL; - const char *http_path; - -@@ -441,8 +441,11 @@ grub_efihttp_open (struct grub_efi_net_device *dev, - return err; - } - -- buf = grub_malloc (size); -- efihttp_read (dev, buf, size); -+ if (size) -+ { -+ buf = grub_malloc (size); -+ efihttp_read (dev, buf, size); -+ } - - file->size = size; - file->data = buf; diff --git a/0136-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch b/0136-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch new file mode 100644 index 0000000..6413eb6 --- /dev/null +++ b/0136-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 19 Jul 2020 17:27:00 -0400 +Subject: [PATCH] efi/ip[46]_config.c: fix some potential allocation overflows + +In theory all of this data comes from the firmware stack and it should +be safe, but it's better to be paranoid. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/ip4_config.c | 25 ++++++++++++++++++------- + grub-core/net/efi/ip6_config.c | 13 ++++++++++--- + 2 files changed, 28 insertions(+), 10 deletions(-) + +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +index 313c818b18..9725e928f7 100644 +--- a/grub-core/net/efi/ip4_config.c ++++ b/grub-core/net/efi/ip4_config.c +@@ -4,15 +4,20 @@ + #include + #include + #include ++#include + + char * + grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) + { + char *hw_addr, *p; +- int sz, s; +- int i; ++ grub_size_t sz, s, i; + +- sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1; ++ if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) || ++ grub_add (sz, 1, &sz)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } + + hw_addr = grub_malloc (sz); + if (!hw_addr) +@@ -20,7 +25,7 @@ grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_a + + p = hw_addr; + s = sz; +- for (i = 0; i < (int)hw_address_size; i++) ++ for (i = 0; i < hw_address_size; i++) + { + grub_snprintf (p, sz, "%02x:", hw_address[i]); + p += sizeof ("XX:") - 1; +@@ -238,14 +243,20 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) + { + grub_efi_ip4_config2_interface_info_t *interface_info; + char **ret; +- int i, id; ++ int id; ++ grub_size_t i, nmemb; + + interface_info = efi_ip4_config_interface_info (dev->ip4_config); + if (!interface_info) + return NULL; + +- ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1)); ++ if (grub_add (interface_info->route_table_size, 1, &nmemb)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } + ++ ret = grub_calloc (nmemb, sizeof (*ret)); + if (!ret) + { + grub_free (interface_info); +@@ -253,7 +264,7 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) + } + + id = 0; +- for (i = 0; i < (int)interface_info->route_table_size; i++) ++ for (i = 0; i < interface_info->route_table_size; i++) + { + char *subnet, *gateway, *mask; + grub_uint32_t u32_subnet, u32_gateway; +diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c +index 017c4d05bc..a46f6f9b68 100644 +--- a/grub-core/net/efi/ip6_config.c ++++ b/grub-core/net/efi/ip6_config.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + char * + grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) +@@ -228,14 +229,20 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) + { + grub_efi_ip6_config_interface_info_t *interface_info; + char **ret; +- int i, id; ++ int id; ++ grub_size_t i, nmemb; + + interface_info = efi_ip6_config_interface_info (dev->ip6_config); + if (!interface_info) + return NULL; + +- ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1)); ++ if (grub_add (interface_info->route_count, 1, &nmemb)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } + ++ ret = grub_calloc (nmemb, sizeof (*ret)); + if (!ret) + { + grub_free (interface_info); +@@ -243,7 +250,7 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) + } + + id = 0; +- for (i = 0; i < (int)interface_info->route_count ; i++) ++ for (i = 0; i < interface_info->route_count ; i++) + { + char *gateway, *destination; + grub_uint64_t u64_gateway[2]; diff --git a/0137-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch b/0137-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch deleted file mode 100644 index 6413eb6..0000000 --- a/0137-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Sun, 19 Jul 2020 17:27:00 -0400 -Subject: [PATCH] efi/ip[46]_config.c: fix some potential allocation overflows - -In theory all of this data comes from the firmware stack and it should -be safe, but it's better to be paranoid. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/ip4_config.c | 25 ++++++++++++++++++------- - grub-core/net/efi/ip6_config.c | 13 ++++++++++--- - 2 files changed, 28 insertions(+), 10 deletions(-) - -diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c -index 313c818b18..9725e928f7 100644 ---- a/grub-core/net/efi/ip4_config.c -+++ b/grub-core/net/efi/ip4_config.c -@@ -4,15 +4,20 @@ - #include - #include - #include -+#include - - char * - grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) - { - char *hw_addr, *p; -- int sz, s; -- int i; -+ grub_size_t sz, s, i; - -- sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1; -+ if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) || -+ grub_add (sz, 1, &sz)) -+ { -+ grub_errno = GRUB_ERR_OUT_OF_RANGE; -+ return NULL; -+ } - - hw_addr = grub_malloc (sz); - if (!hw_addr) -@@ -20,7 +25,7 @@ grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_a - - p = hw_addr; - s = sz; -- for (i = 0; i < (int)hw_address_size; i++) -+ for (i = 0; i < hw_address_size; i++) - { - grub_snprintf (p, sz, "%02x:", hw_address[i]); - p += sizeof ("XX:") - 1; -@@ -238,14 +243,20 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) - { - grub_efi_ip4_config2_interface_info_t *interface_info; - char **ret; -- int i, id; -+ int id; -+ grub_size_t i, nmemb; - - interface_info = efi_ip4_config_interface_info (dev->ip4_config); - if (!interface_info) - return NULL; - -- ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1)); -+ if (grub_add (interface_info->route_table_size, 1, &nmemb)) -+ { -+ grub_errno = GRUB_ERR_OUT_OF_RANGE; -+ return NULL; -+ } - -+ ret = grub_calloc (nmemb, sizeof (*ret)); - if (!ret) - { - grub_free (interface_info); -@@ -253,7 +264,7 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) - } - - id = 0; -- for (i = 0; i < (int)interface_info->route_table_size; i++) -+ for (i = 0; i < interface_info->route_table_size; i++) - { - char *subnet, *gateway, *mask; - grub_uint32_t u32_subnet, u32_gateway; -diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c -index 017c4d05bc..a46f6f9b68 100644 ---- a/grub-core/net/efi/ip6_config.c -+++ b/grub-core/net/efi/ip6_config.c -@@ -3,6 +3,7 @@ - #include - #include - #include -+#include - - char * - grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) -@@ -228,14 +229,20 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) - { - grub_efi_ip6_config_interface_info_t *interface_info; - char **ret; -- int i, id; -+ int id; -+ grub_size_t i, nmemb; - - interface_info = efi_ip6_config_interface_info (dev->ip6_config); - if (!interface_info) - return NULL; - -- ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1)); -+ if (grub_add (interface_info->route_count, 1, &nmemb)) -+ { -+ grub_errno = GRUB_ERR_OUT_OF_RANGE; -+ return NULL; -+ } - -+ ret = grub_calloc (nmemb, sizeof (*ret)); - if (!ret) - { - grub_free (interface_info); -@@ -243,7 +250,7 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) - } - - id = 0; -- for (i = 0; i < (int)interface_info->route_count ; i++) -+ for (i = 0; i < interface_info->route_count ; i++) - { - char *gateway, *destination; - grub_uint64_t u64_gateway[2]; diff --git a/0137-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch b/0137-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch new file mode 100644 index 0000000..8e63d1d --- /dev/null +++ b/0137-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Colin Watson +Date: Fri, 24 Jul 2020 17:18:09 +0100 +Subject: [PATCH] efilinux: Fix integer overflows in grub_cmd_initrd + +These could be triggered by an extremely large number of arguments to +the initrd command on 32-bit architectures, or a crafted filesystem with +very large files on any architecture. + +Signed-off-by: Colin Watson +--- + grub-core/loader/i386/efi/linux.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 15d40d6e35..f992ceeef2 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -28,6 +28,8 @@ + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -206,7 +208,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- files = grub_zalloc (argc * sizeof (files[0])); ++ files = grub_calloc (argc, sizeof (files[0])); + if (!files) + goto fail; + +@@ -216,7 +218,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + if (! files[i]) + goto fail; + nfiles++; +- size += ALIGN_UP (grub_file_size (files[i]), 4); ++ if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ goto fail; ++ } + } + + initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); diff --git a/0138-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch b/0138-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch deleted file mode 100644 index 8e63d1d..0000000 --- a/0138-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Fri, 24 Jul 2020 17:18:09 +0100 -Subject: [PATCH] efilinux: Fix integer overflows in grub_cmd_initrd - -These could be triggered by an extremely large number of arguments to -the initrd command on 32-bit architectures, or a crafted filesystem with -very large files on any architecture. - -Signed-off-by: Colin Watson ---- - grub-core/loader/i386/efi/linux.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 15d40d6e35..f992ceeef2 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -28,6 +28,8 @@ - #include - #include - #include -+#include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -206,7 +208,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -- files = grub_zalloc (argc * sizeof (files[0])); -+ files = grub_calloc (argc, sizeof (files[0])); - if (!files) - goto fail; - -@@ -216,7 +218,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - if (! files[i]) - goto fail; - nfiles++; -- size += ALIGN_UP (grub_file_size (files[i]), 4); -+ if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size)) -+ { -+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); -+ goto fail; -+ } - } - - initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); diff --git a/0138-linuxefi-fail-kernel-validation-without-shim-protoco.patch b/0138-linuxefi-fail-kernel-validation-without-shim-protoco.patch new file mode 100644 index 0000000..828fe16 --- /dev/null +++ b/0138-linuxefi-fail-kernel-validation-without-shim-protoco.patch @@ -0,0 +1,130 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Wed, 22 Jul 2020 11:31:43 +0100 +Subject: [PATCH] linuxefi: fail kernel validation without shim protocol. + +If certificates that signed grub are installed into db, grub can be +booted directly. It will then boot any kernel without signature +validation. The booted kernel will think it was booted in secureboot +mode and will implement lockdown, yet it could have been tampered. + +This version of the patch skips calling verification, when booted +without secureboot. And is indented with gnu ident. + +CVE-2020-15705 + +Reported-by: Mathieu Trudel-Lapierre +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/arm64/linux.c | 13 +++++++++---- + grub-core/loader/efi/chainloader.c | 1 + + grub-core/loader/efi/linux.c | 1 + + grub-core/loader/i386/efi/linux.c | 17 +++++++++++------ + 4 files changed, 22 insertions(+), 10 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 70a0075ec5..47f8cf0d84 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -363,11 +364,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); + +- rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); +- if (rc < 0) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { +- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); +- goto fail; ++ rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); ++ if (rc <= 0) ++ { ++ grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("%s has invalid signature"), argv[0]); ++ goto fail; ++ } + } + + pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index ac8dfd40c6..d41e8ea14a 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -1084,6 +1084,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + return 0; + } ++ // -1 fall-through to fail + + fail: + if (dev) +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index e8b9ecb17f..9260731c10 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -33,6 +33,7 @@ struct grub_efi_shim_lock + }; + typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; + ++// Returns 1 on success, -1 on error, 0 when not available + int + grub_linuxefi_secure_validate (void *data, grub_uint32_t size) + { +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index f992ceeef2..3cf0f9b330 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -101,7 +102,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + + pages = BYTES_TO_PAGES(size); + grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", +- pages, (void *)max); ++ (unsigned long)pages, (void *)(unsigned long)max); + + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, +@@ -307,12 +308,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- rc = grub_linuxefi_secure_validate (kernel, filelen); +- if (rc < 0) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { +- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), +- argv[0]); +- goto fail; ++ rc = grub_linuxefi_secure_validate (kernel, filelen); ++ if (rc <= 0) ++ { ++ grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("%s has invalid signature"), argv[0]); ++ goto fail; ++ } + } + + lh = (struct linux_i386_kernel_header *)kernel; +@@ -386,6 +390,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); + grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ (unsigned long) + MIN((grub_size_t)0x202+setup_header_end_offset, + sizeof (*params)) - 0x1f1, + (grub_uint8_t *)kernel + 0x1f1, diff --git a/0139-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch b/0139-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch new file mode 100644 index 0000000..f20f5c7 --- /dev/null +++ b/0139-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/bootp.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/bootp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 8fb8918ae7..7baf3540c8 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -329,7 +329,7 @@ grub_net_configure_by_dhcp_ack (const char *name, + struct grub_net_network_level_interface *inter; + int mask = -1; + char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; +- const grub_uint8_t *opt; ++ const char *opt; + grub_uint8_t opt_len, overload = 0; + const char *boot_file = 0, *server_name = 0; + grub_size_t boot_file_len, server_name_len; +@@ -505,7 +505,7 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (opt && opt_len) + { + grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); +- if (opt && grub_strcmp (opt, "HTTPClient") == 0) ++ if (opt && grub_strcmp ((char *)opt, "HTTPClient") == 0) + { + char *proto, *ip, *pa; + diff --git a/0139-linuxefi-fail-kernel-validation-without-shim-protoco.patch b/0139-linuxefi-fail-kernel-validation-without-shim-protoco.patch deleted file mode 100644 index 828fe16..0000000 --- a/0139-linuxefi-fail-kernel-validation-without-shim-protoco.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dimitri John Ledkov -Date: Wed, 22 Jul 2020 11:31:43 +0100 -Subject: [PATCH] linuxefi: fail kernel validation without shim protocol. - -If certificates that signed grub are installed into db, grub can be -booted directly. It will then boot any kernel without signature -validation. The booted kernel will think it was booted in secureboot -mode and will implement lockdown, yet it could have been tampered. - -This version of the patch skips calling verification, when booted -without secureboot. And is indented with gnu ident. - -CVE-2020-15705 - -Reported-by: Mathieu Trudel-Lapierre -Signed-off-by: Dimitri John Ledkov ---- - grub-core/loader/arm64/linux.c | 13 +++++++++---- - grub-core/loader/efi/chainloader.c | 1 + - grub-core/loader/efi/linux.c | 1 + - grub-core/loader/i386/efi/linux.c | 17 +++++++++++------ - 4 files changed, 22 insertions(+), 10 deletions(-) - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index 70a0075ec5..47f8cf0d84 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -34,6 +34,7 @@ - #include - #include - #include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -363,11 +364,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); - -- rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); -- if (rc < 0) -+ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) - { -- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); -- goto fail; -+ rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); -+ if (rc <= 0) -+ { -+ grub_error (GRUB_ERR_INVALID_COMMAND, -+ N_("%s has invalid signature"), argv[0]); -+ goto fail; -+ } - } - - pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index ac8dfd40c6..d41e8ea14a 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -1084,6 +1084,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - - return 0; - } -+ // -1 fall-through to fail - - fail: - if (dev) -diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c -index e8b9ecb17f..9260731c10 100644 ---- a/grub-core/loader/efi/linux.c -+++ b/grub-core/loader/efi/linux.c -@@ -33,6 +33,7 @@ struct grub_efi_shim_lock - }; - typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; - -+// Returns 1 on success, -1 on error, 0 when not available - int - grub_linuxefi_secure_validate (void *data, grub_uint32_t size) - { -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index f992ceeef2..3cf0f9b330 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -101,7 +102,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) - - pages = BYTES_TO_PAGES(size); - grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", -- pages, (void *)max); -+ (unsigned long)pages, (void *)(unsigned long)max); - - prev_max = max; - addr = grub_efi_allocate_pages_real (max, pages, -@@ -307,12 +308,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -- rc = grub_linuxefi_secure_validate (kernel, filelen); -- if (rc < 0) -+ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) - { -- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), -- argv[0]); -- goto fail; -+ rc = grub_linuxefi_secure_validate (kernel, filelen); -+ if (rc <= 0) -+ { -+ grub_error (GRUB_ERR_INVALID_COMMAND, -+ N_("%s has invalid signature"), argv[0]); -+ goto fail; -+ } - } - - lh = (struct linux_i386_kernel_header *)kernel; -@@ -386,6 +390,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); - grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", -+ (unsigned long) - MIN((grub_size_t)0x202+setup_header_end_offset, - sizeof (*params)) - 0x1f1, - (grub_uint8_t *)kernel + 0x1f1, diff --git a/0140-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch b/0140-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch deleted file mode 100644 index f20f5c7..0000000 --- a/0140-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 20 Jul 2020 12:24:02 -0400 -Subject: [PATCH] Fix const char ** pointers in grub-core/net/bootp.c - -This will need to get folded back in the right place on the next rebase, -but it's before "Make grub_strtol() "end" pointers have safer const -qualifiers" currently, so for now I'm leaving it here instead of merging -it back with the original patch. - -Signed-off-by: Peter Jones ---- - grub-core/net/bootp.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c -index 8fb8918ae7..7baf3540c8 100644 ---- a/grub-core/net/bootp.c -+++ b/grub-core/net/bootp.c -@@ -329,7 +329,7 @@ grub_net_configure_by_dhcp_ack (const char *name, - struct grub_net_network_level_interface *inter; - int mask = -1; - char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; -- const grub_uint8_t *opt; -+ const char *opt; - grub_uint8_t opt_len, overload = 0; - const char *boot_file = 0, *server_name = 0; - grub_size_t boot_file_len, server_name_len; -@@ -505,7 +505,7 @@ grub_net_configure_by_dhcp_ack (const char *name, - if (opt && opt_len) - { - grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); -- if (opt && grub_strcmp (opt, "HTTPClient") == 0) -+ if (opt && grub_strcmp ((char *)opt, "HTTPClient") == 0) - { - char *proto, *ip, *pa; - diff --git a/0140-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch b/0140-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch new file mode 100644 index 0000000..ea92110 --- /dev/null +++ b/0140-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip4_config.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/ip4_config.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +index 9725e928f7..cb880fc3e8 100644 +--- a/grub-core/net/efi/ip4_config.c ++++ b/grub-core/net/efi/ip4_config.c +@@ -61,7 +61,8 @@ int + grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) + { + grub_uint32_t newip = 0; +- int i, ncolon = 0; ++ grub_size_t i; ++ int ncolon = 0; + const char *ptr = val; + + /* Check that is not an IPv6 address */ +@@ -78,7 +79,7 @@ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *addres + for (i = 0; i < 4; i++) + { + unsigned long t; +- t = grub_strtoul (ptr, (char **) &ptr, 0); ++ t = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; diff --git a/0141-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch b/0141-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch deleted file mode 100644 index ea92110..0000000 --- a/0141-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 20 Jul 2020 12:24:02 -0400 -Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip4_config.c - -This will need to get folded back in the right place on the next rebase, -but it's before "Make grub_strtol() "end" pointers have safer const -qualifiers" currently, so for now I'm leaving it here instead of merging -it back with the original patch. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/ip4_config.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c -index 9725e928f7..cb880fc3e8 100644 ---- a/grub-core/net/efi/ip4_config.c -+++ b/grub-core/net/efi/ip4_config.c -@@ -61,7 +61,8 @@ int - grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) - { - grub_uint32_t newip = 0; -- int i, ncolon = 0; -+ grub_size_t i; -+ int ncolon = 0; - const char *ptr = val; - - /* Check that is not an IPv6 address */ -@@ -78,7 +79,7 @@ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *addres - for (i = 0; i < 4; i++) - { - unsigned long t; -- t = grub_strtoul (ptr, (char **) &ptr, 0); -+ t = grub_strtoul (ptr, &ptr, 0); - if (grub_errno) - { - grub_errno = GRUB_ERR_NONE; diff --git a/0141-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch b/0141-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch new file mode 100644 index 0000000..915e6d7 --- /dev/null +++ b/0141-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip6_config.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/ip6_config.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c +index a46f6f9b68..1c5415d718 100644 +--- a/grub-core/net/efi/ip6_config.c ++++ b/grub-core/net/efi/ip6_config.c +@@ -85,7 +85,7 @@ grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *addres + ptr++; + continue; + } +- t = grub_strtoul (ptr, (char **) &ptr, 16); ++ t = grub_strtoul (ptr, &ptr, 16); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; diff --git a/0142-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch b/0142-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch deleted file mode 100644 index 915e6d7..0000000 --- a/0142-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 20 Jul 2020 12:24:02 -0400 -Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip6_config.c - -This will need to get folded back in the right place on the next rebase, -but it's before "Make grub_strtol() "end" pointers have safer const -qualifiers" currently, so for now I'm leaving it here instead of merging -it back with the original patch. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/ip6_config.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c -index a46f6f9b68..1c5415d718 100644 ---- a/grub-core/net/efi/ip6_config.c -+++ b/grub-core/net/efi/ip6_config.c -@@ -85,7 +85,7 @@ grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *addres - ptr++; - continue; - } -- t = grub_strtoul (ptr, (char **) &ptr, 16); -+ t = grub_strtoul (ptr, &ptr, 16); - if (grub_errno) - { - grub_errno = GRUB_ERR_NONE; diff --git a/0142-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch b/0142-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch new file mode 100644 index 0000000..fbba65a --- /dev/null +++ b/0142-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/net.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index a3f0535d43..78e5442fc5 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -729,7 +729,7 @@ grub_efi_net_parse_address (const char *address, + { + grub_uint32_t subnet_mask_size; + +- subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0); ++ subnet_mask_size = grub_strtoul (rest + 1, &rest, 0); + + if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) + { +@@ -758,7 +758,7 @@ grub_efi_net_parse_address (const char *address, + { + grub_efi_uint8_t prefix_length; + +- prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0); ++ prefix_length = grub_strtoul (rest + 1, &rest, 0); + if (!grub_errno && prefix_length <= 128 && *rest == 0) + { + ip6->prefix_length = prefix_length; diff --git a/0143-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch b/0143-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch deleted file mode 100644 index fbba65a..0000000 --- a/0143-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 20 Jul 2020 12:24:02 -0400 -Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/net.c - -This will need to get folded back in the right place on the next rebase, -but it's before "Make grub_strtol() "end" pointers have safer const -qualifiers" currently, so for now I'm leaving it here instead of merging -it back with the original patch. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/net.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c -index a3f0535d43..78e5442fc5 100644 ---- a/grub-core/net/efi/net.c -+++ b/grub-core/net/efi/net.c -@@ -729,7 +729,7 @@ grub_efi_net_parse_address (const char *address, - { - grub_uint32_t subnet_mask_size; - -- subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0); -+ subnet_mask_size = grub_strtoul (rest + 1, &rest, 0); - - if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) - { -@@ -758,7 +758,7 @@ grub_efi_net_parse_address (const char *address, - { - grub_efi_uint8_t prefix_length; - -- prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0); -+ prefix_length = grub_strtoul (rest + 1, &rest, 0); - if (!grub_errno && prefix_length <= 128 && *rest == 0) - { - ip6->prefix_length = prefix_length; diff --git a/0143-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch b/0143-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch new file mode 100644 index 0000000..9b9acfe --- /dev/null +++ b/0143-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/pxe.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/pxe.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c +index 531949cba5..73e2bb01c1 100644 +--- a/grub-core/net/efi/pxe.c ++++ b/grub-core/net/efi/pxe.c +@@ -187,7 +187,7 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + ptr++; + continue; + } +- t = grub_strtoul (ptr, (char **) &ptr, 16); ++ t = grub_strtoul (ptr, &ptr, 16); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; +@@ -225,7 +225,7 @@ pxe_open (struct grub_efi_net_device *dev, + int type __attribute__((unused))) + { + int i; +- char *p; ++ const char *p; + grub_efi_status_t status; + grub_efi_pxe_ip_address_t server_ip; + grub_efi_uint64_t file_size = 0; +@@ -313,7 +313,7 @@ pxe_read (struct grub_efi_net_device *dev, + grub_size_t len) + { + int i; +- char *p; ++ const char *p; + grub_efi_status_t status; + grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; + grub_efi_uint64_t bufsz = len; diff --git a/0144-Add-systemd-integration-scripts-to-make-systemctl-re.patch b/0144-Add-systemd-integration-scripts-to-make-systemctl-re.patch new file mode 100644 index 0000000..8cf45c3 --- /dev/null +++ b/0144-Add-systemd-integration-scripts-to-make-systemctl-re.patch @@ -0,0 +1,190 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 22 Jul 2020 14:03:42 +0200 +Subject: [PATCH] Add systemd integration scripts to make "systemctl reboot + --boot-loader-menu=xxx" work with grub + +This commit adds a number of scripts / config files to make +"systemctl reboot --boot-loader-menu=xxx" work with grub: + +1. /lib/systemd/system/systemd-logind.service.d/10-grub.conf +This sets SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU in the env. for logind, +indicating that the boot-loader which is used supports this feature, see: +https://github.com/systemd/systemd/blob/master/docs/ENVIRONMENT.md + +2. /lib/systemd/system/grub-systemd-integration.service + /lib/systemd/system/reboot.target.wants/grub-systemd-integration.service -> + ../grub-systemd-integration.service + /usr/libexec/grub/grub-systemd-integration.sh + +The symlink in the .wants dir causes the added service file to be started +by systemd just before rebooting the system. +If /run/systemd/reboot-to-boot-loader-menu exist then the service will run +the grub-systemd-integration.sh script. +This script sets the new menu_show_once_timeout grubenv variable to the +requested timeout in seconds. + +3. /etc/grub.d/14_menu_show_once + +This new grub-mkconfig snippet adds the necessary code to the generated +grub.conf to honor the new menu_show_once_timeout variable, and to +automatically clear it after consuming it. + +Note the service and libexec script use grub-systemd-integration as name +because in the future they may be used to add further integration with +systemctl reboot --foo options, e.g. support for --boot-loader-entry=NAME. + +A few notes about upstreaming this patch from the rhboot grub2 fork: +1. I have deliberately put the grub.conf bits for this in a new / separate + grub-mkconfig snippet generator for easy upstreaming +2. Even though the commit message mentions the .wants symlink for the .service + I have been unable to come up with a clean way to do this at "make install" + time, this should be fixed before upstreaming. + +Downstream notes: +1. Since make install does not add the .wants symlink, this needs to be done + in grub2.spec %install +2. This is keeping support for the "old" Fedora specific menu_show_once env + variable, which has a hardcoded timeout of 60 sec in 12_menu_auto_hide in + place for now. This can be dropped (eventually) in a follow-up patch once + GNOME has been converted to use the systemd dbus API equivalent of + "systemctl reboot --boot-loader-menu=xxx". + +Signed-off-by: Hans de Goede +--- + Makefile.util.def | 27 ++++++++++++++++++++++++ + conf/Makefile.common | 6 ++++++ + util/grub.d/14_menu_show_once.in | 13 ++++++++++++ + util/systemd/10-grub-logind-service.conf.in | 2 ++ + util/systemd/grub-systemd-integration.service.in | 8 +++++++ + util/systemd/systemd-integration.sh.in | 6 ++++++ + 6 files changed, 62 insertions(+) + create mode 100755 util/grub.d/14_menu_show_once.in + create mode 100644 util/systemd/10-grub-logind-service.conf.in + create mode 100644 util/systemd/grub-systemd-integration.service.in + create mode 100644 util/systemd/systemd-integration.sh.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index b4ce5383b7..6366442129 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -470,6 +470,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '14_menu_show_once'; ++ common = util/grub.d/14_menu_show_once.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '01_users'; + common = util/grub.d/01_users.in; +@@ -569,6 +575,27 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = 'grub-systemd-integration.service'; ++ common = util/systemd/grub-systemd-integration.service.in; ++ installdir = systemdunit; ++ condition = COND_HOST_LINUX; ++}; ++ ++script = { ++ name = 'systemd-integration.sh'; ++ common = util/systemd/systemd-integration.sh.in; ++ installdir = grublibexec; ++ condition = COND_HOST_LINUX; ++}; ++ ++script = { ++ name = '10-grub-logind-service.conf'; ++ common = util/systemd/10-grub-logind-service.conf.in; ++ installdir = systemd_logind_service_d; ++ condition = COND_HOST_LINUX; ++}; ++ + program = { + mansection = 1; + name = grub-mkrescue; +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 0647c53b91..9fe5863b2d 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -63,8 +63,11 @@ CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS) + # Other variables + + grubconfdir = $(sysconfdir)/grub.d ++grublibexecdir = $(libexecdir)/$(grubdirname) + platformdir = $(pkglibdir)/$(target_cpu)-$(platform) + starfielddir = $(pkgdatadir)/themes/starfield ++systemdunitdir = ${prefix}/lib/systemd/system ++systemd_logind_service_ddir = $(systemdunitdir)/systemd-logind.service.d + + CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines + CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib +@@ -121,6 +124,9 @@ noinst_LIBRARIES = + dist_noinst_DATA = + platform_SCRIPTS = + platform_PROGRAMS = ++grublibexec_SCRIPTS = ++systemdunit_SCRIPTS = ++systemd_logind_service_d_SCRIPTS = + + TESTS = + EXTRA_DIST = +diff --git a/util/grub.d/14_menu_show_once.in b/util/grub.d/14_menu_show_once.in +new file mode 100755 +index 0000000000..1cd7f36142 +--- /dev/null ++++ b/util/grub.d/14_menu_show_once.in +@@ -0,0 +1,13 @@ ++#! /bin/sh ++# Force the menu to be shown once, with a timeout of ${menu_show_once_timeout} ++# if requested by ${menu_show_once_timeout} being set in the env. ++cat << EOF ++if [ x\$feature_timeout_style = xy ]; then ++ if [ "\${menu_show_once_timeout}" ]; then ++ set timeout_style=menu ++ set timeout="\${menu_show_once_timeout}" ++ unset menu_show_once_timeout ++ save_env menu_show_once_timeout ++ fi ++fi ++EOF +diff --git a/util/systemd/10-grub-logind-service.conf.in b/util/systemd/10-grub-logind-service.conf.in +new file mode 100644 +index 0000000000..f2d4ac0073 +--- /dev/null ++++ b/util/systemd/10-grub-logind-service.conf.in +@@ -0,0 +1,2 @@ ++[Service] ++Environment=SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU=true +diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in +new file mode 100644 +index 0000000000..c81fb594ce +--- /dev/null ++++ b/util/systemd/grub-systemd-integration.service.in +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Grub2 systemctl reboot --boot-loader-menu=... support ++Before=umount.target systemd-reboot.service ++DefaultDependencies=no ++ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu ++ ++[Service] ++ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh +diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in +new file mode 100644 +index 0000000000..dc1218597b +--- /dev/null ++++ b/util/systemd/systemd-integration.sh.in +@@ -0,0 +1,6 @@ ++#!/bin/sh ++ ++TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu) ++TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000)) ++ ++@grub_editenv@ - set menu_show_once_timeout=$TIMEOUT diff --git a/0144-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch b/0144-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch deleted file mode 100644 index 9b9acfe..0000000 --- a/0144-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 20 Jul 2020 12:24:02 -0400 -Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/pxe.c - -This will need to get folded back in the right place on the next rebase, -but it's before "Make grub_strtol() "end" pointers have safer const -qualifiers" currently, so for now I'm leaving it here instead of merging -it back with the original patch. - -Signed-off-by: Peter Jones ---- - grub-core/net/efi/pxe.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c -index 531949cba5..73e2bb01c1 100644 ---- a/grub-core/net/efi/pxe.c -+++ b/grub-core/net/efi/pxe.c -@@ -187,7 +187,7 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) - ptr++; - continue; - } -- t = grub_strtoul (ptr, (char **) &ptr, 16); -+ t = grub_strtoul (ptr, &ptr, 16); - if (grub_errno) - { - grub_errno = GRUB_ERR_NONE; -@@ -225,7 +225,7 @@ pxe_open (struct grub_efi_net_device *dev, - int type __attribute__((unused))) - { - int i; -- char *p; -+ const char *p; - grub_efi_status_t status; - grub_efi_pxe_ip_address_t server_ip; - grub_efi_uint64_t file_size = 0; -@@ -313,7 +313,7 @@ pxe_read (struct grub_efi_net_device *dev, - grub_size_t len) - { - int i; -- char *p; -+ const char *p; - grub_efi_status_t status; - grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; - grub_efi_uint64_t bufsz = len; diff --git a/0145-Add-systemd-integration-scripts-to-make-systemctl-re.patch b/0145-Add-systemd-integration-scripts-to-make-systemctl-re.patch deleted file mode 100644 index 9e0fc88..0000000 --- a/0145-Add-systemd-integration-scripts-to-make-systemctl-re.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 22 Jul 2020 14:03:42 +0200 -Subject: [PATCH] Add systemd integration scripts to make "systemctl reboot - --boot-loader-menu=xxx" work with grub - -This commit adds a number of scripts / config files to make -"systemctl reboot --boot-loader-menu=xxx" work with grub: - -1. /lib/systemd/system/systemd-logind.service.d/10-grub.conf -This sets SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU in the env. for logind, -indicating that the boot-loader which is used supports this feature, see: -https://github.com/systemd/systemd/blob/master/docs/ENVIRONMENT.md - -2. /lib/systemd/system/grub-systemd-integration.service - /lib/systemd/system/reboot.target.wants/grub-systemd-integration.service -> - ../grub-systemd-integration.service - /usr/libexec/grub/grub-systemd-integration.sh - -The symlink in the .wants dir causes the added service file to be started -by systemd just before rebooting the system. -If /run/systemd/reboot-to-boot-loader-menu exist then the service will run -the grub-systemd-integration.sh script. -This script sets the new menu_show_once_timeout grubenv variable to the -requested timeout in seconds. - -3. /etc/grub.d/14_menu_show_once - -This new grub-mkconfig snippet adds the necessary code to the generated -grub.conf to honor the new menu_show_once_timeout variable, and to -automatically clear it after consuming it. - -Note the service and libexec script use grub-systemd-integration as name -because in the future they may be used to add further integration with -systemctl reboot --foo options, e.g. support for --boot-loader-entry=NAME. - -A few notes about upstreaming this patch from the rhboot grub2 fork: -1. I have deliberately put the grub.conf bits for this in a new / separate - grub-mkconfig snippet generator for easy upstreaming -2. Even though the commit message mentions the .wants symlink for the .service - I have been unable to come up with a clean way to do this at "make install" - time, this should be fixed before upstreaming. - -Downstream notes: -1. Since make install does not add the .wants symlink, this needs to be done - in grub2.spec %install -2. This is keeping support for the "old" Fedora specific menu_show_once env - variable, which has a hardcoded timeout of 60 sec in 12_menu_auto_hide in - place for now. This can be dropped (eventually) in a follow-up patch once - GNOME has been converted to use the systemd dbus API equivalent of - "systemctl reboot --boot-loader-menu=xxx". - -Signed-off-by: Hans de Goede ---- - Makefile.util.def | 27 ++++++++++++++++++++++++ - conf/Makefile.common | 6 ++++++ - util/grub.d/14_menu_show_once.in | 13 ++++++++++++ - util/systemd/10-grub-logind-service.conf.in | 2 ++ - util/systemd/grub-systemd-integration.service.in | 8 +++++++ - util/systemd/systemd-integration.sh.in | 6 ++++++ - 6 files changed, 62 insertions(+) - create mode 100755 util/grub.d/14_menu_show_once.in - create mode 100644 util/systemd/10-grub-logind-service.conf.in - create mode 100644 util/systemd/grub-systemd-integration.service.in - create mode 100644 util/systemd/systemd-integration.sh.in - -diff --git a/Makefile.util.def b/Makefile.util.def -index 2e6ad979c3..9927c2cfd6 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -470,6 +470,12 @@ script = { - installdir = grubconf; - }; - -+script = { -+ name = '14_menu_show_once'; -+ common = util/grub.d/14_menu_show_once.in; -+ installdir = grubconf; -+}; -+ - script = { - name = '01_users'; - common = util/grub.d/01_users.in; -@@ -569,6 +575,27 @@ script = { - installdir = grubconf; - }; - -+script = { -+ name = 'grub-systemd-integration.service'; -+ common = util/systemd/grub-systemd-integration.service.in; -+ installdir = systemdunit; -+ condition = COND_HOST_LINUX; -+}; -+ -+script = { -+ name = 'systemd-integration.sh'; -+ common = util/systemd/systemd-integration.sh.in; -+ installdir = grublibexec; -+ condition = COND_HOST_LINUX; -+}; -+ -+script = { -+ name = '10-grub-logind-service.conf'; -+ common = util/systemd/10-grub-logind-service.conf.in; -+ installdir = systemd_logind_service_d; -+ condition = COND_HOST_LINUX; -+}; -+ - program = { - mansection = 1; - name = grub-mkrescue; -diff --git a/conf/Makefile.common b/conf/Makefile.common -index 0647c53b91..9fe5863b2d 100644 ---- a/conf/Makefile.common -+++ b/conf/Makefile.common -@@ -63,8 +63,11 @@ CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS) - # Other variables - - grubconfdir = $(sysconfdir)/grub.d -+grublibexecdir = $(libexecdir)/$(grubdirname) - platformdir = $(pkglibdir)/$(target_cpu)-$(platform) - starfielddir = $(pkgdatadir)/themes/starfield -+systemdunitdir = ${prefix}/lib/systemd/system -+systemd_logind_service_ddir = $(systemdunitdir)/systemd-logind.service.d - - CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines - CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib -@@ -121,6 +124,9 @@ noinst_LIBRARIES = - dist_noinst_DATA = - platform_SCRIPTS = - platform_PROGRAMS = -+grublibexec_SCRIPTS = -+systemdunit_SCRIPTS = -+systemd_logind_service_d_SCRIPTS = - - TESTS = - EXTRA_DIST = -diff --git a/util/grub.d/14_menu_show_once.in b/util/grub.d/14_menu_show_once.in -new file mode 100755 -index 0000000000..1cd7f36142 ---- /dev/null -+++ b/util/grub.d/14_menu_show_once.in -@@ -0,0 +1,13 @@ -+#! /bin/sh -+# Force the menu to be shown once, with a timeout of ${menu_show_once_timeout} -+# if requested by ${menu_show_once_timeout} being set in the env. -+cat << EOF -+if [ x\$feature_timeout_style = xy ]; then -+ if [ "\${menu_show_once_timeout}" ]; then -+ set timeout_style=menu -+ set timeout="\${menu_show_once_timeout}" -+ unset menu_show_once_timeout -+ save_env menu_show_once_timeout -+ fi -+fi -+EOF -diff --git a/util/systemd/10-grub-logind-service.conf.in b/util/systemd/10-grub-logind-service.conf.in -new file mode 100644 -index 0000000000..f2d4ac0073 ---- /dev/null -+++ b/util/systemd/10-grub-logind-service.conf.in -@@ -0,0 +1,2 @@ -+[Service] -+Environment=SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU=true -diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in -new file mode 100644 -index 0000000000..c81fb594ce ---- /dev/null -+++ b/util/systemd/grub-systemd-integration.service.in -@@ -0,0 +1,8 @@ -+[Unit] -+Description=Grub2 systemctl reboot --boot-loader-menu=... support -+Before=umount.target systemd-reboot.service -+DefaultDependencies=no -+ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu -+ -+[Service] -+ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh -diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in -new file mode 100644 -index 0000000000..dc1218597b ---- /dev/null -+++ b/util/systemd/systemd-integration.sh.in -@@ -0,0 +1,6 @@ -+#!/bin/sh -+ -+TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu) -+TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000)) -+ -+@grub_editenv@ - set menu_show_once_timeout=$TIMEOUT diff --git a/0145-systemd-integration.sh-Also-set-old-menu_show_once-g.patch b/0145-systemd-integration.sh-Also-set-old-menu_show_once-g.patch new file mode 100644 index 0000000..a16ed68 --- /dev/null +++ b/0145-systemd-integration.sh-Also-set-old-menu_show_once-g.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 23 Jul 2020 09:27:36 +0200 +Subject: [PATCH] systemd-integration.sh: Also set old menu_show_once grubenv + var + +Downstream RH / Fedora patch for compatibility with old, not (yet) +regenerated grub.cfg files which miss the menu_show_once_timeout check. +This older grubenv variable leads to a fixed timeout of 60 seconds. + +Note that the new menu_show_once_timeout will overrule these 60 seconds +if both are set and the grub.cfg does have the menu_show_once_timeout +check. + +Signed-off-by: Hans de Goede +--- + util/systemd/systemd-integration.sh.in | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in +index dc1218597b..a4c071c5b0 100644 +--- a/util/systemd/systemd-integration.sh.in ++++ b/util/systemd/systemd-integration.sh.in +@@ -4,3 +4,8 @@ TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu) + TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000)) + + @grub_editenv@ - set menu_show_once_timeout=$TIMEOUT ++ ++# Downstream RH / Fedora patch for compatibility with old, not (yet) ++# regenerated grub.cfg files which miss the menu_show_once_timeout check ++# this older grubenv variable leads to a fixed timeout of 60 seconds ++@grub_editenv@ - set menu_show_once=1 diff --git a/0146-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch b/0146-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch new file mode 100644 index 0000000..f891a69 --- /dev/null +++ b/0146-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 597111077b..2601438260 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 bcb4d9ba78..9414dc1b99 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/0146-systemd-integration.sh-Also-set-old-menu_show_once-g.patch b/0146-systemd-integration.sh-Also-set-old-menu_show_once-g.patch deleted file mode 100644 index a16ed68..0000000 --- a/0146-systemd-integration.sh-Also-set-old-menu_show_once-g.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 23 Jul 2020 09:27:36 +0200 -Subject: [PATCH] systemd-integration.sh: Also set old menu_show_once grubenv - var - -Downstream RH / Fedora patch for compatibility with old, not (yet) -regenerated grub.cfg files which miss the menu_show_once_timeout check. -This older grubenv variable leads to a fixed timeout of 60 seconds. - -Note that the new menu_show_once_timeout will overrule these 60 seconds -if both are set and the grub.cfg does have the menu_show_once_timeout -check. - -Signed-off-by: Hans de Goede ---- - util/systemd/systemd-integration.sh.in | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in -index dc1218597b..a4c071c5b0 100644 ---- a/util/systemd/systemd-integration.sh.in -+++ b/util/systemd/systemd-integration.sh.in -@@ -4,3 +4,8 @@ TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu) - TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000)) - - @grub_editenv@ - set menu_show_once_timeout=$TIMEOUT -+ -+# Downstream RH / Fedora patch for compatibility with old, not (yet) -+# regenerated grub.cfg files which miss the menu_show_once_timeout check -+# this older grubenv variable leads to a fixed timeout of 60 seconds -+@grub_editenv@ - set menu_show_once=1 diff --git a/0147-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch b/0147-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch deleted file mode 100644 index f891a69..0000000 --- a/0147-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch +++ /dev/null @@ -1,121 +0,0 @@ -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 597111077b..2601438260 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 bcb4d9ba78..9414dc1b99 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/0147-grub-install-disable-support-for-EFI-platforms.patch b/0147-grub-install-disable-support-for-EFI-platforms.patch new file mode 100644 index 0000000..f6a7530 --- /dev/null +++ b/0147-grub-install-disable-support-for-EFI-platforms.patch @@ -0,0 +1,101 @@ +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 +[rharwood: drop man page] +--- + util/grub-install.c | 37 ++++++++++++++++--------------------- + docs/grub.texi | 7 +++++++ + 2 files changed, 23 insertions(+), 21 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index a2bec7446c..5babc7af55 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -899,6 +899,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); +@@ -1011,28 +1027,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_RISCV32_EFI: +- case GRUB_INSTALL_PLATFORM_RISCV64_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 04ed6ac1f0..4870faaa00 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6509,6 +6509,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/0148-New-with-debug-timestamps-configure-flag-to-prepend-.patch b/0148-New-with-debug-timestamps-configure-flag-to-prepend-.patch new file mode 100644 index 0000000..ec5b30b --- /dev/null +++ b/0148-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 a02d40a05b..ab0d326f00 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1585,6 +1585,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)])]) +@@ -2136,6 +2147,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]) + +@@ -2231,6 +2243,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 578bf51a5f..9f54b6b7d2 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 + { +@@ -192,9 +195,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 c7e316f0f1..c80e3e0aba 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/0148-grub-install-disable-support-for-EFI-platforms.patch b/0148-grub-install-disable-support-for-EFI-platforms.patch deleted file mode 100644 index f6a7530..0000000 --- a/0148-grub-install-disable-support-for-EFI-platforms.patch +++ /dev/null @@ -1,101 +0,0 @@ -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 -[rharwood: drop man page] ---- - util/grub-install.c | 37 ++++++++++++++++--------------------- - docs/grub.texi | 7 +++++++ - 2 files changed, 23 insertions(+), 21 deletions(-) - -diff --git a/util/grub-install.c b/util/grub-install.c -index a2bec7446c..5babc7af55 100644 ---- a/util/grub-install.c -+++ b/util/grub-install.c -@@ -899,6 +899,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); -@@ -1011,28 +1027,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_RISCV32_EFI: -- case GRUB_INSTALL_PLATFORM_RISCV64_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 04ed6ac1f0..4870faaa00 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -6509,6 +6509,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/0149-Added-debug-statements-to-grub_disk_open-and-grub_di.patch b/0149-Added-debug-statements-to-grub_disk_open-and-grub_di.patch new file mode 100644 index 0000000..d26027c --- /dev/null +++ b/0149-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 e1b0e073e0..05a28ab142 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->disk_close) + (disk->dev->disk_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/0149-New-with-debug-timestamps-configure-flag-to-prepend-.patch b/0149-New-with-debug-timestamps-configure-flag-to-prepend-.patch deleted file mode 100644 index c32be3c..0000000 --- a/0149-New-with-debug-timestamps-configure-flag-to-prepend-.patch +++ /dev/null @@ -1,112 +0,0 @@ -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 de707f7e0b..f069d84039 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1586,6 +1586,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)])]) -@@ -2167,6 +2178,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]) - -@@ -2262,6 +2274,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 578bf51a5f..9f54b6b7d2 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 - { -@@ -192,9 +195,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 c7e316f0f1..c80e3e0aba 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/0150-Added-debug-statements-to-grub_disk_open-and-grub_di.patch b/0150-Added-debug-statements-to-grub_disk_open-and-grub_di.patch deleted file mode 100644 index d26027c..0000000 --- a/0150-Added-debug-statements-to-grub_disk_open-and-grub_di.patch +++ /dev/null @@ -1,47 +0,0 @@ -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 e1b0e073e0..05a28ab142 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->disk_close) - (disk->dev->disk_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/0150-Introduce-function-grub_debug_is_enabled-void-return.patch b/0150-Introduce-function-grub_debug_is_enabled-void-return.patch new file mode 100644 index 0000000..9ce5d9d --- /dev/null +++ b/0150-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 9f54b6b7d2..a186ad3dd4 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -163,6 +163,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 3adc4036e3..6c4aa85ac5 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -340,6 +340,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/0151-Don-t-clear-screen-when-debugging-is-enabled.patch b/0151-Don-t-clear-screen-when-debugging-is-enabled.patch new file mode 100644 index 0000000..c35d8a3 --- /dev/null +++ b/0151-Don-t-clear-screen-when-debugging-is-enabled.patch @@ -0,0 +1,31 @@ +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 +[rharwood@redhat.com: rebase fuzz] +Signed-off-by: Robbie Harwood +--- + grub-core/normal/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index af9792c963..7de9e4c36d 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -215,8 +215,9 @@ grub_normal_init_page (struct grub_term_output *term, + char *msg_formatted; + grub_uint32_t *unicode_msg; + grub_uint32_t *last_position; +- +- grub_term_cls (term); ++ ++ if (! grub_debug_is_enabled ()) ++ grub_term_cls (term); + + msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION); + if (!msg_formatted) diff --git a/0151-Introduce-function-grub_debug_is_enabled-void-return.patch b/0151-Introduce-function-grub_debug_is_enabled-void-return.patch deleted file mode 100644 index 9ce5d9d..0000000 --- a/0151-Introduce-function-grub_debug_is_enabled-void-return.patch +++ /dev/null @@ -1,51 +0,0 @@ -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 9f54b6b7d2..a186ad3dd4 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -163,6 +163,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 3adc4036e3..6c4aa85ac5 100644 ---- a/include/grub/misc.h -+++ b/include/grub/misc.h -@@ -340,6 +340,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/0152-Don-t-clear-screen-when-debugging-is-enabled.patch b/0152-Don-t-clear-screen-when-debugging-is-enabled.patch deleted file mode 100644 index c35d8a3..0000000 --- a/0152-Don-t-clear-screen-when-debugging-is-enabled.patch +++ /dev/null @@ -1,31 +0,0 @@ -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 -[rharwood@redhat.com: rebase fuzz] -Signed-off-by: Robbie Harwood ---- - grub-core/normal/main.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c -index af9792c963..7de9e4c36d 100644 ---- a/grub-core/normal/main.c -+++ b/grub-core/normal/main.c -@@ -215,8 +215,9 @@ grub_normal_init_page (struct grub_term_output *term, - char *msg_formatted; - grub_uint32_t *unicode_msg; - grub_uint32_t *last_position; -- -- grub_term_cls (term); -+ -+ if (! grub_debug_is_enabled ()) -+ grub_term_cls (term); - - msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION); - if (!msg_formatted) diff --git a/0152-grub_file_-instrumentation-new-file-debug-tag.patch b/0152-grub_file_-instrumentation-new-file-debug-tag.patch new file mode 100644 index 0000000..908e1ff --- /dev/null +++ b/0152-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 58454458c4..e19aea3e51 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -66,6 +66,8 @@ grub_file_open (const char *name, enum grub_file_type type) + 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; +@@ -128,6 +130,8 @@ grub_file_open (const char *name, enum grub_file_type type) + if (!file) + grub_file_close (last_file); + ++ grub_dprintf ("file", "Opening `%s' succeeded.\n", name); ++ + return file; + + fail: +@@ -138,6 +142,8 @@ grub_file_open (const char *name, enum grub_file_type type) + + grub_free (file); + ++ grub_dprintf ("file", "Opening `%s' failed.\n", name); ++ + return 0; + } + +@@ -169,6 +175,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) +@@ -189,11 +196,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->fs_close) + (file->fs->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/0153-grub_file_-instrumentation-new-file-debug-tag.patch b/0153-grub_file_-instrumentation-new-file-debug-tag.patch deleted file mode 100644 index 908e1ff..0000000 --- a/0153-grub_file_-instrumentation-new-file-debug-tag.patch +++ /dev/null @@ -1,71 +0,0 @@ -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 58454458c4..e19aea3e51 100644 ---- a/grub-core/kern/file.c -+++ b/grub-core/kern/file.c -@@ -66,6 +66,8 @@ grub_file_open (const char *name, enum grub_file_type type) - 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; -@@ -128,6 +130,8 @@ grub_file_open (const char *name, enum grub_file_type type) - if (!file) - grub_file_close (last_file); - -+ grub_dprintf ("file", "Opening `%s' succeeded.\n", name); -+ - return file; - - fail: -@@ -138,6 +142,8 @@ grub_file_open (const char *name, enum grub_file_type type) - - grub_free (file); - -+ grub_dprintf ("file", "Opening `%s' failed.\n", name); -+ - return 0; - } - -@@ -169,6 +175,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) -@@ -189,11 +196,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->fs_close) - (file->fs->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/0153-ieee1275-Avoiding-many-unecessary-open-close.patch b/0153-ieee1275-Avoiding-many-unecessary-open-close.patch new file mode 100644 index 0000000..f6c5244 --- /dev/null +++ b/0153-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 03674cb477..ea7f78ac7d 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/0154-ieee1275-Avoiding-many-unecessary-open-close.patch b/0154-ieee1275-Avoiding-many-unecessary-open-close.patch deleted file mode 100644 index f6c5244..0000000 --- a/0154-ieee1275-Avoiding-many-unecessary-open-close.patch +++ /dev/null @@ -1,136 +0,0 @@ -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 03674cb477..ea7f78ac7d 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/0154-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/0154-ieee1275-powerpc-implements-fibre-channel-discovery-.patch new file mode 100644 index 0000000..04c5c32 --- /dev/null +++ b/0154-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 a6153d3595..0f5d54e9f2 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/0155-ieee1275-powerpc-enables-device-mapper-discovery.patch b/0155-ieee1275-powerpc-enables-device-mapper-discovery.patch new file mode 100644 index 0000000..85dbde7 --- /dev/null +++ b/0155-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 0f5d54e9f2..cc849d9c94 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/0155-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/0155-ieee1275-powerpc-implements-fibre-channel-discovery-.patch deleted file mode 100644 index 04c5c32..0000000 --- a/0155-ieee1275-powerpc-implements-fibre-channel-discovery-.patch +++ /dev/null @@ -1,90 +0,0 @@ -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 a6153d3595..0f5d54e9f2 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/0156-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch b/0156-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch new file mode 100644 index 0000000..f938fd1 --- /dev/null +++ b/0156-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch @@ -0,0 +1,245 @@ +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 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +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 + +Signed-off-by: Renaud Métrich +Signed-off-by: Robbie Harwood +--- + 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 2601438260..dac0f946fe 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/0156-ieee1275-powerpc-enables-device-mapper-discovery.patch b/0156-ieee1275-powerpc-enables-device-mapper-discovery.patch deleted file mode 100644 index 85dbde7..0000000 --- a/0156-ieee1275-powerpc-enables-device-mapper-discovery.patch +++ /dev/null @@ -1,106 +0,0 @@ -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 0f5d54e9f2..cc849d9c94 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/0157-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch b/0157-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch deleted file mode 100644 index f938fd1..0000000 --- a/0157-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch +++ /dev/null @@ -1,245 +0,0 @@ -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 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -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 - -Signed-off-by: Renaud Métrich -Signed-off-by: Robbie Harwood ---- - 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 2601438260..dac0f946fe 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/0157-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/0157-Add-suport-for-signing-grub-with-an-appended-signatu.patch new file mode 100644 index 0000000..81660d4 --- /dev/null +++ b/0157-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 +--- + util/grub-install-common.c | 18 ++++++++++++++---- + util/grub-mkimage.c | 15 +++++++++++++-- + util/grub-mkimagexx.c | 39 ++++++++++++++++++++++++++++++++++++++- + util/mkimage.c | 13 +++++++------ + include/grub/util/install.h | 8 ++++++-- + include/grub/util/mkimage.h | 4 ++-- + 6 files changed, 80 insertions(+), 17 deletions(-) + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index 4e212e690c..a74fee16e2 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -461,10 +461,12 @@ static size_t npubkeys; + static char *sbat; + static int disable_shim_lock; + static grub_compression_t compression; ++static size_t appsig_size; + + int + grub_install_parse (int key, char *arg) + { ++ const char *end; + switch (key) + { + case 'C': +@@ -562,6 +564,12 @@ grub_install_parse (int key, char *arg) + grub_util_error (_("Unrecognized compression `%s'"), arg); + case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: + return 1; ++ case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE: ++ grub_errno = 0; ++ appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ return 1; + default: + return 0; + } +@@ -661,11 +669,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + " --output '%s' " + " --dtb '%s' " + "--sbat '%s' " +- "--format '%s' --compression '%s' %s %s %s\n", ++ "--format '%s' --compression '%s' " ++ "--appended-signature-size %zu %s %s %s\n", + dir, prefix, + outname, dtb ? : "", sbat ? : "", mkimage_target, +- compnames[compression], note ? "--note" : "", +- disable_shim_lock ? "--disable-shim-lock" : "", s); ++ compnames[compression], appsig_size, ++ disable_shim_lock ? "--disable-shim-lock" : "", ++ note ? "--note" : "", s); + free (s); + + tgt = grub_install_get_image_target (mkimage_target); +@@ -675,7 +685,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, + pubkeys, npubkeys, config_path, tgt, +- note, compression, dtb, sbat, ++ note, appsig_size, compression, dtb, sbat, + disable_shim_lock); + while (dc--) + grub_install_pop_module (); +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index c0d5599370..8a53310548 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -84,6 +84,7 @@ static struct argp_option options[] = { + {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, + {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, ++ {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -128,6 +129,7 @@ struct arguments + char *sbat; + int note; + int disable_shim_lock; ++ size_t appsig_size; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; + }; +@@ -138,6 +140,7 @@ argp_parser (int key, char *arg, struct argp_state *state) + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = state->input; ++ const char* end; + + switch (key) + { +@@ -170,6 +173,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->note = 1; + break; + ++ case 'S': ++ grub_errno = 0; ++ arguments->appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ break; ++ + case 'm': + if (arguments->memdisk) + free (arguments->memdisk); +@@ -324,8 +334,9 @@ main (int argc, char *argv[]) + arguments.memdisk, arguments.pubkeys, + arguments.npubkeys, arguments.config, + arguments.image_target, arguments.note, +- arguments.comp, arguments.dtb, +- arguments.sbat, arguments.disable_shim_lock); ++ arguments.appsig_size, arguments.comp, ++ arguments.dtb, arguments.sbat, ++ arguments.disable_shim_lock); + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index d78fa3e533..393119486d 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -84,6 +84,15 @@ struct grub_ieee1275_note + struct grub_ieee1275_note_desc descriptor; + }; + ++#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature" ++#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */ ++ ++struct grub_appended_signature_note ++{ ++ Elf32_Nhdr header; ++ char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)]; ++}; ++ + #define GRUB_XEN_NOTE_NAME "Xen" + + struct fixup_block_list +@@ -207,7 +216,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) + + void + SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf_Addr target_addr, + struct grub_mkimage_layout *layout) + { +@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + int shnum = 4; + int string_size = sizeof (".text") + sizeof ("mods") + 1; + ++ if (appsig_size) ++ { ++ phnum++; ++ footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ } ++ + if (image_target->id != IMAGE_LOONGSON_ELF) + phnum += 2; + +@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + ++ if (appsig_size) { ++ int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) ++ (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ ++ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME)); ++ /* needs to sit at the end, so we round this up and sign some zero padding */ ++ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4)); ++ note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE); ++ strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME); ++ ++ phdr++; ++ phdr->p_type = grub_host_to_target32 (PT_NOTE); ++ phdr->p_flags = grub_host_to_target32 (PF_R); ++ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); ++ phdr->p_vaddr = 0; ++ phdr->p_paddr = 0; ++ phdr->p_filesz = grub_host_to_target32 (note_size); ++ phdr->p_memsz = 0; ++ phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ } ++ + { + char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr)); +diff --git a/util/mkimage.c b/util/mkimage.c +index a26cf76f72..bab1227601 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -869,8 +869,9 @@ grub_install_generate_image (const char *dir, const char *prefix, + char *memdisk_path, char **pubkey_paths, + size_t npubkeys, char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, grub_compression_t comp, const char *dtb_path, +- const char *sbat_path, int disable_shim_lock) ++ int note, size_t appsig_size, grub_compression_t comp, ++ const char *dtb_path, const char *sbat_path, ++ int disable_shim_lock) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; +@@ -1773,11 +1774,11 @@ grub_install_generate_image (const char *dir, const char *prefix, + else + target_addr = image_target->link_addr; + if (image_target->voidp_sizeof == 4) +- grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + else +- grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + } + break; + } +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 7df3191f47..cf4531e02b 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -67,6 +67,9 @@ + N_("SBAT metadata"), 0 }, \ + { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ + N_("disable shim_lock verifier"), 0 }, \ ++ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ ++ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ ++ 1}, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -128,7 +131,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, + GRUB_INSTALL_OPTIONS_DTB, + GRUB_INSTALL_OPTIONS_SBAT, +- GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK ++ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, ++ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE + }; + + extern char *grub_install_source_directory; +@@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + size_t npubkeys, + char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, ++ int note, size_t appsig_size, + grub_compression_t comp, const char *dtb_file, + const char *sbat_path, const int disable_shim_lock); + +diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h +index 3819a67441..6f1da89b9b 100644 +--- a/include/grub/util/mkimage.h ++++ b/include/grub/util/mkimage.h +@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, + const struct grub_install_image_target_desc *image_target); + void + grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf32_Addr target_addr, + struct grub_mkimage_layout *layout); + void + grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf64_Addr target_addr, + struct grub_mkimage_layout *layout); + diff --git a/0158-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/0158-Add-suport-for-signing-grub-with-an-appended-signatu.patch deleted file mode 100644 index 81660d4..0000000 --- a/0158-Add-suport-for-signing-grub-with-an-appended-signatu.patch +++ /dev/null @@ -1,309 +0,0 @@ -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 ---- - util/grub-install-common.c | 18 ++++++++++++++---- - util/grub-mkimage.c | 15 +++++++++++++-- - util/grub-mkimagexx.c | 39 ++++++++++++++++++++++++++++++++++++++- - util/mkimage.c | 13 +++++++------ - include/grub/util/install.h | 8 ++++++-- - include/grub/util/mkimage.h | 4 ++-- - 6 files changed, 80 insertions(+), 17 deletions(-) - -diff --git a/util/grub-install-common.c b/util/grub-install-common.c -index 4e212e690c..a74fee16e2 100644 ---- a/util/grub-install-common.c -+++ b/util/grub-install-common.c -@@ -461,10 +461,12 @@ static size_t npubkeys; - static char *sbat; - static int disable_shim_lock; - static grub_compression_t compression; -+static size_t appsig_size; - - int - grub_install_parse (int key, char *arg) - { -+ const char *end; - switch (key) - { - case 'C': -@@ -562,6 +564,12 @@ grub_install_parse (int key, char *arg) - grub_util_error (_("Unrecognized compression `%s'"), arg); - case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: - return 1; -+ case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE: -+ grub_errno = 0; -+ appsig_size = grub_strtol(arg, &end, 10); -+ if (grub_errno) -+ return 0; -+ return 1; - default: - return 0; - } -@@ -661,11 +669,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, - " --output '%s' " - " --dtb '%s' " - "--sbat '%s' " -- "--format '%s' --compression '%s' %s %s %s\n", -+ "--format '%s' --compression '%s' " -+ "--appended-signature-size %zu %s %s %s\n", - dir, prefix, - outname, dtb ? : "", sbat ? : "", mkimage_target, -- compnames[compression], note ? "--note" : "", -- disable_shim_lock ? "--disable-shim-lock" : "", s); -+ compnames[compression], appsig_size, -+ disable_shim_lock ? "--disable-shim-lock" : "", -+ note ? "--note" : "", s); - free (s); - - tgt = grub_install_get_image_target (mkimage_target); -@@ -675,7 +685,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, - grub_install_generate_image (dir, prefix, fp, outname, - modules.entries, memdisk_path, - pubkeys, npubkeys, config_path, tgt, -- note, compression, dtb, sbat, -+ note, appsig_size, compression, dtb, sbat, - disable_shim_lock); - while (dc--) - grub_install_pop_module (); -diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c -index c0d5599370..8a53310548 100644 ---- a/util/grub-mkimage.c -+++ b/util/grub-mkimage.c -@@ -84,6 +84,7 @@ static struct argp_option options[] = { - {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, - {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, - {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, -+ {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0}, - { 0, 0, 0, 0, 0, 0 } - }; - -@@ -128,6 +129,7 @@ struct arguments - char *sbat; - int note; - int disable_shim_lock; -+ size_t appsig_size; - const struct grub_install_image_target_desc *image_target; - grub_compression_t comp; - }; -@@ -138,6 +140,7 @@ argp_parser (int key, char *arg, struct argp_state *state) - /* Get the input argument from argp_parse, which we - know is a pointer to our arguments structure. */ - struct arguments *arguments = state->input; -+ const char* end; - - switch (key) - { -@@ -170,6 +173,13 @@ argp_parser (int key, char *arg, struct argp_state *state) - arguments->note = 1; - break; - -+ case 'S': -+ grub_errno = 0; -+ arguments->appsig_size = grub_strtol(arg, &end, 10); -+ if (grub_errno) -+ return 0; -+ break; -+ - case 'm': - if (arguments->memdisk) - free (arguments->memdisk); -@@ -324,8 +334,9 @@ main (int argc, char *argv[]) - arguments.memdisk, arguments.pubkeys, - arguments.npubkeys, arguments.config, - arguments.image_target, arguments.note, -- arguments.comp, arguments.dtb, -- arguments.sbat, arguments.disable_shim_lock); -+ arguments.appsig_size, arguments.comp, -+ arguments.dtb, arguments.sbat, -+ arguments.disable_shim_lock); - - if (grub_util_file_sync (fp) < 0) - grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", -diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c -index d78fa3e533..393119486d 100644 ---- a/util/grub-mkimagexx.c -+++ b/util/grub-mkimagexx.c -@@ -84,6 +84,15 @@ struct grub_ieee1275_note - struct grub_ieee1275_note_desc descriptor; - }; - -+#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature" -+#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */ -+ -+struct grub_appended_signature_note -+{ -+ Elf32_Nhdr header; -+ char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)]; -+}; -+ - #define GRUB_XEN_NOTE_NAME "Xen" - - struct fixup_block_list -@@ -207,7 +216,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) - - void - SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, -- int note, char **core_img, size_t *core_size, -+ int note, size_t appsig_size, char **core_img, size_t *core_size, - Elf_Addr target_addr, - struct grub_mkimage_layout *layout) - { -@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc - int shnum = 4; - int string_size = sizeof (".text") + sizeof ("mods") + 1; - -+ if (appsig_size) -+ { -+ phnum++; -+ footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); -+ } -+ - if (image_target->id != IMAGE_LOONGSON_ELF) - phnum += 2; - -@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc - phdr->p_offset = grub_host_to_target32 (header_size + program_size); - } - -+ if (appsig_size) { -+ int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); -+ struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) -+ (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); -+ -+ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME)); -+ /* needs to sit at the end, so we round this up and sign some zero padding */ -+ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4)); -+ note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE); -+ strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME); -+ -+ phdr++; -+ phdr->p_type = grub_host_to_target32 (PT_NOTE); -+ phdr->p_flags = grub_host_to_target32 (PF_R); -+ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); -+ phdr->p_vaddr = 0; -+ phdr->p_paddr = 0; -+ phdr->p_filesz = grub_host_to_target32 (note_size); -+ phdr->p_memsz = 0; -+ phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); -+ } -+ - { - char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) - + shnum * sizeof (*shdr)); -diff --git a/util/mkimage.c b/util/mkimage.c -index a26cf76f72..bab1227601 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -869,8 +869,9 @@ grub_install_generate_image (const char *dir, const char *prefix, - char *memdisk_path, char **pubkey_paths, - size_t npubkeys, char *config_path, - const struct grub_install_image_target_desc *image_target, -- int note, grub_compression_t comp, const char *dtb_path, -- const char *sbat_path, int disable_shim_lock) -+ int note, size_t appsig_size, grub_compression_t comp, -+ const char *dtb_path, const char *sbat_path, -+ int disable_shim_lock) - { - char *kernel_img, *core_img; - size_t total_module_size, core_size; -@@ -1773,11 +1774,11 @@ grub_install_generate_image (const char *dir, const char *prefix, - else - target_addr = image_target->link_addr; - if (image_target->voidp_sizeof == 4) -- grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, -- target_addr, &layout); -+ grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img, -+ &core_size, target_addr, &layout); - else -- grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, -- target_addr, &layout); -+ grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img, -+ &core_size, target_addr, &layout); - } - break; - } -diff --git a/include/grub/util/install.h b/include/grub/util/install.h -index 7df3191f47..cf4531e02b 100644 ---- a/include/grub/util/install.h -+++ b/include/grub/util/install.h -@@ -67,6 +67,9 @@ - N_("SBAT metadata"), 0 }, \ - { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ - N_("disable shim_lock verifier"), 0 }, \ -+ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ -+ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ -+ 1}, \ - { "verbose", 'v', 0, 0, \ - N_("print verbose messages."), 1 } - -@@ -128,7 +131,8 @@ enum grub_install_options { - GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, - GRUB_INSTALL_OPTIONS_DTB, - GRUB_INSTALL_OPTIONS_SBAT, -- GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK -+ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, -+ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE - }; - - extern char *grub_install_source_directory; -@@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char *prefix, - size_t npubkeys, - char *config_path, - const struct grub_install_image_target_desc *image_target, -- int note, -+ int note, size_t appsig_size, - grub_compression_t comp, const char *dtb_file, - const char *sbat_path, const int disable_shim_lock); - -diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h -index 3819a67441..6f1da89b9b 100644 ---- a/include/grub/util/mkimage.h -+++ b/include/grub/util/mkimage.h -@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, - const struct grub_install_image_target_desc *image_target); - void - grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, -- int note, char **core_img, size_t *core_size, -+ int note, size_t appsig_size, char **core_img, size_t *core_size, - Elf32_Addr target_addr, - struct grub_mkimage_layout *layout); - void - grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, -- int note, char **core_img, size_t *core_size, -+ int note, size_t appsig_size, char **core_img, size_t *core_size, - Elf64_Addr target_addr, - struct grub_mkimage_layout *layout); - diff --git a/0158-docs-grub-Document-signing-grub-under-UEFI.patch b/0158-docs-grub-Document-signing-grub-under-UEFI.patch new file mode 100644 index 0000000..f2b5c17 --- /dev/null +++ b/0158-docs-grub-Document-signing-grub-under-UEFI.patch @@ -0,0 +1,61 @@ +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. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 4870faaa00..365d1d6931 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5817,6 +5817,7 @@ environment variables and commands are listed in the same order. + * Secure Boot Advanced Targeting:: Embedded information for generation number based revocation + * Measured Boot:: Measuring boot components + * Lockdown:: Lockdown when booting on a secure setup ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5895,7 +5896,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} +@@ -6067,6 +6068,25 @@ be restricted and some operations/commands cannot be executed. + The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. + Otherwise it does not exit. + ++@node Signing GRUB itself ++@section Signing GRUB itself ++ ++To ensure a complete secure-boot chain, there must be a way for the code that ++loads GRUB to verify the integrity of the core image. ++ ++This is ultimately platform-specific and individual platforms can define their ++own mechanisms. However, there are general-purpose mechanisms that can be used ++with GRUB. ++ ++@section Signing GRUB for UEFI secure boot ++ ++On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed ++with a tool such as @command{pesign} or @command{sbsign}. Refer to the ++suggestions in @pxref{UEFI secure boot and shim} to ensure that the final ++image works under UEFI secure boot and can maintain the secure-boot chain. It ++will also be necessary to enrol the public key used into a relevant firmware ++key database. ++ + @node Platform limitations + @chapter Platform limitations + diff --git a/0159-docs-grub-Document-signing-grub-under-UEFI.patch b/0159-docs-grub-Document-signing-grub-under-UEFI.patch deleted file mode 100644 index f2b5c17..0000000 --- a/0159-docs-grub-Document-signing-grub-under-UEFI.patch +++ /dev/null @@ -1,61 +0,0 @@ -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. - -Signed-off-by: Daniel Axtens ---- - docs/grub.texi | 22 +++++++++++++++++++++- - 1 file changed, 21 insertions(+), 1 deletion(-) - -diff --git a/docs/grub.texi b/docs/grub.texi -index 4870faaa00..365d1d6931 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -5817,6 +5817,7 @@ environment variables and commands are listed in the same order. - * Secure Boot Advanced Targeting:: Embedded information for generation number based revocation - * Measured Boot:: Measuring boot components - * Lockdown:: Lockdown when booting on a secure setup -+* Signing GRUB itself:: Ensuring the integrity of the GRUB core image - @end menu - - @node Authentication and authorisation -@@ -5895,7 +5896,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} -@@ -6067,6 +6068,25 @@ be restricted and some operations/commands cannot be executed. - The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. - Otherwise it does not exit. - -+@node Signing GRUB itself -+@section Signing GRUB itself -+ -+To ensure a complete secure-boot chain, there must be a way for the code that -+loads GRUB to verify the integrity of the core image. -+ -+This is ultimately platform-specific and individual platforms can define their -+own mechanisms. However, there are general-purpose mechanisms that can be used -+with GRUB. -+ -+@section Signing GRUB for UEFI secure boot -+ -+On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed -+with a tool such as @command{pesign} or @command{sbsign}. Refer to the -+suggestions in @pxref{UEFI secure boot and shim} to ensure that the final -+image works under UEFI secure boot and can maintain the secure-boot chain. It -+will also be necessary to enrol the public key used into a relevant firmware -+key database. -+ - @node Platform limitations - @chapter Platform limitations - diff --git a/0159-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/0159-docs-grub-Document-signing-grub-with-an-appended-sig.patch new file mode 100644 index 0000000..ee3d659 --- /dev/null +++ b/0159-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 365d1d6931..afbde7c1f7 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6087,6 +6087,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It + will also be necessary to enrol the public key used into a relevant firmware + key database. + ++@section Signing GRUB with an appended signature ++ ++The @file{core.elf} 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.elf} ++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/0160-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/0160-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch new file mode 100644 index 0000000..b23ce49 --- /dev/null +++ b/0160-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 2f76e6b043..20d870f2a4 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -245,11 +245,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/0160-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/0160-docs-grub-Document-signing-grub-with-an-appended-sig.patch deleted file mode 100644 index ee3d659..0000000 --- a/0160-docs-grub-Document-signing-grub-with-an-appended-sig.patch +++ /dev/null @@ -1,67 +0,0 @@ -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 365d1d6931..afbde7c1f7 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -6087,6 +6087,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It - will also be necessary to enrol the public key used into a relevant firmware - key database. - -+@section Signing GRUB with an appended signature -+ -+The @file{core.elf} 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.elf} -+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/0161-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/0161-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch deleted file mode 100644 index b23ce49..0000000 --- a/0161-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch +++ /dev/null @@ -1,44 +0,0 @@ -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 2f76e6b043..20d870f2a4 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -245,11 +245,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/0161-pgp-factor-out-rsa_pad.patch b/0161-pgp-factor-out-rsa_pad.patch new file mode 100644 index 0000000..f1e721d --- /dev/null +++ b/0161-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 81fc274148..97347ae76f 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2510,6 +2510,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 5daa1e9d00..2408db4994 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 0000000000..dbacd563d0 +--- /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 0000000000..5c338c84a1 +--- /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/0162-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/0162-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch new file mode 100644 index 0000000..541474e --- /dev/null +++ b/0162-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 2408db4994..355a43844a 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 ca334d5a40..c578128a59 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/0162-pgp-factor-out-rsa_pad.patch b/0162-pgp-factor-out-rsa_pad.patch deleted file mode 100644 index f1e721d..0000000 --- a/0162-pgp-factor-out-rsa_pad.patch +++ /dev/null @@ -1,191 +0,0 @@ -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 81fc274148..97347ae76f 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -2510,6 +2510,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 5daa1e9d00..2408db4994 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 0000000000..dbacd563d0 ---- /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 0000000000..5c338c84a1 ---- /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/0163-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/0163-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch deleted file mode 100644 index 541474e..0000000 --- a/0163-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch +++ /dev/null @@ -1,71 +0,0 @@ -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 2408db4994..355a43844a 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 ca334d5a40..c578128a59 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/0163-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/0163-posix_wrap-tweaks-in-preparation-for-libtasn1.patch new file mode 100644 index 0000000..3176f1b --- /dev/null +++ b/0163-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 7217138ffd..591dbf3289 100644 +--- a/grub-core/lib/posix_wrap/limits.h ++++ b/grub-core/lib/posix_wrap/limits.h +@@ -37,5 +37,6 @@ + #define LONG_MAX GRUB_LONG_MAX + + #define CHAR_BIT 8 ++#define WORD_BIT 32 + + #endif +diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h +index 7a8d385e97..4634db09f2 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 854eb0122e..f63412c8da 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/0164-libtasn1-import-libtasn1-4.16.0.patch b/0164-libtasn1-import-libtasn1-4.16.0.patch new file mode 100644 index 0000000..9587661 --- /dev/null +++ b/0164-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 0000000000..245ea64cf0 +--- /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 0000000000..ff04eb778c +--- /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 0000000000..997eb2725d +--- /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 0000000000..cee74daf79 +--- /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 0000000000..e91a3a151c +--- /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 0000000000..d5dbbf8765 +--- /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 0000000000..8189c56a4c +--- /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 0000000000..440a33f4bb +--- /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 0000000000..48229844ff +--- /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 0000000000..ea1625786c +--- /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 0000000000..598e684b35 +--- /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 0000000000..99e685da07 +--- /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 0000000000..6fd7a30dc3 +--- /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 0000000000..e8b3628db9 +--- /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 0000000000..50a8642296 +--- /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/0164-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/0164-posix_wrap-tweaks-in-preparation-for-libtasn1.patch deleted file mode 100644 index 3176f1b..0000000 --- a/0164-posix_wrap-tweaks-in-preparation-for-libtasn1.patch +++ /dev/null @@ -1,64 +0,0 @@ -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 7217138ffd..591dbf3289 100644 ---- a/grub-core/lib/posix_wrap/limits.h -+++ b/grub-core/lib/posix_wrap/limits.h -@@ -37,5 +37,6 @@ - #define LONG_MAX GRUB_LONG_MAX - - #define CHAR_BIT 8 -+#define WORD_BIT 32 - - #endif -diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h -index 7a8d385e97..4634db09f2 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 854eb0122e..f63412c8da 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/0165-libtasn1-disable-code-not-needed-in-grub.patch b/0165-libtasn1-disable-code-not-needed-in-grub.patch new file mode 100644 index 0000000..84dcbf0 --- /dev/null +++ b/0165-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 245ea64cf0..52def59836 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 ff04eb778c..42f9a92b5d 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 997eb2725d..539008d8e9 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 cee74daf79..42785e8622 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 8189c56a4c..fcfde01a39 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 6fd7a30dc3..785eda2ae3 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/0165-libtasn1-import-libtasn1-4.16.0.patch b/0165-libtasn1-import-libtasn1-4.16.0.patch deleted file mode 100644 index 9587661..0000000 --- a/0165-libtasn1-import-libtasn1-4.16.0.patch +++ /dev/null @@ -1,8934 +0,0 @@ -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 0000000000..245ea64cf0 ---- /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 0000000000..ff04eb778c ---- /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 0000000000..997eb2725d ---- /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 0000000000..cee74daf79 ---- /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 0000000000..e91a3a151c ---- /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 0000000000..d5dbbf8765 ---- /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 0000000000..8189c56a4c ---- /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 0000000000..440a33f4bb ---- /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 0000000000..48229844ff ---- /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 0000000000..ea1625786c ---- /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 0000000000..598e684b35 ---- /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 0000000000..99e685da07 ---- /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 0000000000..6fd7a30dc3 ---- /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 0000000000..e8b3628db9 ---- /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 0000000000..50a8642296 ---- /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/0166-libtasn1-changes-for-grub-compatibility.patch b/0166-libtasn1-changes-for-grub-compatibility.patch new file mode 100644 index 0000000..7c756bd --- /dev/null +++ b/0166-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 42f9a92b5d..7856858b27 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 539008d8e9..ed761ff56b 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 e91a3a151c..e33875c2c7 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 d5dbbf8765..89c9be69dc 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 ea1625786c..4a568efee9 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 785eda2ae3..28dbf16c4e 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/0166-libtasn1-disable-code-not-needed-in-grub.patch b/0166-libtasn1-disable-code-not-needed-in-grub.patch deleted file mode 100644 index 84dcbf0..0000000 --- a/0166-libtasn1-disable-code-not-needed-in-grub.patch +++ /dev/null @@ -1,307 +0,0 @@ -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 245ea64cf0..52def59836 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 ff04eb778c..42f9a92b5d 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 997eb2725d..539008d8e9 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 cee74daf79..42785e8622 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 8189c56a4c..fcfde01a39 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 6fd7a30dc3..785eda2ae3 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/0167-libtasn1-changes-for-grub-compatibility.patch b/0167-libtasn1-changes-for-grub-compatibility.patch deleted file mode 100644 index 7c756bd..0000000 --- a/0167-libtasn1-changes-for-grub-compatibility.patch +++ /dev/null @@ -1,202 +0,0 @@ -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 42f9a92b5d..7856858b27 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 539008d8e9..ed761ff56b 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 e91a3a151c..e33875c2c7 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 d5dbbf8765..89c9be69dc 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 ea1625786c..4a568efee9 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 785eda2ae3..28dbf16c4e 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/0167-libtasn1-compile-into-asn1-module.patch b/0167-libtasn1-compile-into-asn1-module.patch new file mode 100644 index 0000000..b557403 --- /dev/null +++ b/0167-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 97347ae76f..21d2c54185 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2576,3 +2576,18 @@ module = { + common = commands/i386/wrmsr.c; + enable = x86; + }; ++ ++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 0000000000..622ba942e3 +--- /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/0168-libtasn1-compile-into-asn1-module.patch b/0168-libtasn1-compile-into-asn1-module.patch deleted file mode 100644 index b557403..0000000 --- a/0168-libtasn1-compile-into-asn1-module.patch +++ /dev/null @@ -1,70 +0,0 @@ -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 97347ae76f..21d2c54185 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -2576,3 +2576,18 @@ module = { - common = commands/i386/wrmsr.c; - enable = x86; - }; -+ -+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 0000000000..622ba942e3 ---- /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/0168-test_asn1-test-module-for-libtasn1.patch b/0168-test_asn1-test-module-for-libtasn1.patch new file mode 100644 index 0000000..c95a00b --- /dev/null +++ b/0168-test_asn1-test-module-for-libtasn1.patch @@ -0,0 +1,1457 @@ +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 6366442129..d04b3fe68a 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1289,6 +1289,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 21d2c54185..b4aaccf7b5 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2591,3 +2591,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 0000000000..534e304521 +--- /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 0000000000..f48aea0ef8 +--- /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 0000000000..9f01006ddf +--- /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 0000000000..dbe1474b20 +--- /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 0000000000..d367bbfb5a +--- /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 0000000000..3a83b58c59 +--- /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 0000000000..d8a049e8df +--- /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 0000000000..dc7268d4c6 +--- /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 0000000000..75fcd21f0d +--- /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 0000000000..1e7d3d64f5 +--- /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 0000000000..e2561e5ec6 +--- /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 0000000000..555e56dd20 +--- /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 208d1d2325..1d005887e7 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -264,6 +264,7 @@ widthspec.bin + /stamp-h1 + /syslinux_test + /tar_test ++/test_asn1 + /test_sha512sum + /test_unset + /tests/syslinux/ubuntu10.04_grub.cfg +diff --git a/tests/test_asn1.in b/tests/test_asn1.in +new file mode 100644 +index 0000000000..8173c5c270 +--- /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/0169-grub-install-support-embedding-x509-certificates.patch b/0169-grub-install-support-embedding-x509-certificates.patch new file mode 100644 index 0000000..c4c35f4 --- /dev/null +++ b/0169-grub-install-support-embedding-x509-certificates.patch @@ -0,0 +1,253 @@ +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 | 38 ++++++++++++++++++++++++++++++++++++-- + include/grub/kernel.h | 4 +++- + include/grub/util/install.h | 7 +++++-- + 6 files changed, 80 insertions(+), 9 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 355a43844a..b81ac0ae46 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 a74fee16e2..c603f5b308 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -460,6 +460,8 @@ static char **pubkeys; + static size_t npubkeys; + static char *sbat; + static int disable_shim_lock; ++static char **x509keys; ++static size_t nx509keys; + static grub_compression_t compression; + static size_t appsig_size; + +@@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg) + case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: + disable_shim_lock = 1; + return 1; ++ case 'x': ++ x509keys = xrealloc (x509keys, ++ sizeof (x509keys[0]) ++ * (nx509keys + 1)); ++ x509keys[nx509keys++] = xstrdup (arg); ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -627,6 +635,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + slen += 20 + grub_strlen (*pk); + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ slen += 10 + grub_strlen (*pk); ++ + for (md = modules.entries; *md; md++) + { + slen += 10 + grub_strlen (*md); +@@ -655,6 +666,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + *p++ = ' '; + } + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ { ++ p = grub_stpcpy (p, "--x509 '"); ++ p = grub_stpcpy (p, *pk); ++ *p++ = '\''; ++ *p++ = ' '; ++ } ++ + for (md = modules.entries; *md; md++) + { + *p++ = '\''; +@@ -684,7 +703,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, sbat, + disable_shim_lock); + while (dc--) +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index 8a53310548..e1f1112784 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -75,7 +75,8 @@ static struct argp_option options[] = { + /* TRANSLATORS: "embed" is a verb (command description). "*/ + {"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0}, + /* TRANSLATORS: "embed" is a verb (command description). "*/ +- {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0}, ++ {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0}, ++ {"x509", 'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0}, + /* TRANSLATORS: NOTE is a name of segment. */ + {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, + {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, +@@ -124,6 +125,8 @@ struct arguments + char *dtb; + char **pubkeys; + size_t npubkeys; ++ char **x509keys; ++ size_t nx509keys; + char *font; + char *config; + char *sbat; +@@ -206,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); + break; + ++ case 'x': ++ arguments->x509keys = xrealloc (arguments->x509keys, ++ sizeof (arguments->x509keys[0]) ++ * (arguments->nx509keys + 1)); ++ arguments->x509keys[arguments->nx509keys++] = xstrdup (arg); ++ break; ++ + case 'c': + if (arguments->config) + free (arguments->config); +@@ -332,7 +342,8 @@ main (int argc, char *argv[]) + grub_install_generate_image (arguments.dir, arguments.prefix, fp, + arguments.output, arguments.modules, + arguments.memdisk, arguments.pubkeys, +- arguments.npubkeys, arguments.config, ++ arguments.npubkeys, arguments.x509keys, ++ arguments.nx509keys, arguments.config, + arguments.image_target, arguments.note, + arguments.appsig_size, arguments.comp, + arguments.dtb, arguments.sbat, +diff --git a/util/mkimage.c b/util/mkimage.c +index bab1227601..8319e8dfbd 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -867,7 +867,8 @@ 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, ++ size_t npubkeys, char **x509key_paths, ++ size_t nx509keys, char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, size_t appsig_size, grub_compression_t comp, + const char *dtb_path, const char *sbat_path, +@@ -913,6 +914,19 @@ grub_install_generate_image (const char *dir, const char *prefix, + } + } + ++ { ++ size_t i; ++ for (i = 0; i < nx509keys; i++) ++ { ++ size_t curs; ++ curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i])); ++ grub_util_info ("the size of x509 public key %u is 0x%" ++ GRUB_HOST_PRIxLONG_LONG, ++ (unsigned) i, (unsigned long long) curs); ++ total_module_size += curs + sizeof (struct grub_module_header); ++ } ++ } ++ + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); +@@ -1034,7 +1048,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + curs = grub_util_get_image_size (pubkey_paths[i]); + + header = (struct grub_module_header *) (kernel_img + offset); +- header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY); ++ header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY); + header->size = grub_host_to_target32 (curs + sizeof (*header)); + offset += sizeof (*header); + +@@ -1043,6 +1057,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 55849777ea..98edc0863f 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -30,7 +30,9 @@ enum + OBJ_TYPE_PREFIX, + OBJ_TYPE_PUBKEY, + OBJ_TYPE_DTB, +- OBJ_TYPE_DISABLE_SHIM_LOCK ++ OBJ_TYPE_DISABLE_SHIM_LOCK, ++ OBJ_TYPE_GPG_PUBKEY, ++ OBJ_TYPE_X509_PUBKEY, + }; + + /* The module header. */ +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index cf4531e02b..51f3b13ac1 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -67,6 +67,8 @@ + N_("SBAT metadata"), 0 }, \ + { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ + N_("disable shim_lock verifier"), 0 }, \ ++ { "x509key", 'x', N_("FILE"), 0, \ ++ N_("embed FILE as an x509 certificate for signature checking"), 0}, \ + { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ + "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ + 1}, \ +@@ -188,8 +190,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/0169-test_asn1-test-module-for-libtasn1.patch b/0169-test_asn1-test-module-for-libtasn1.patch deleted file mode 100644 index 1588c51..0000000 --- a/0169-test_asn1-test-module-for-libtasn1.patch +++ /dev/null @@ -1,1457 +0,0 @@ -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 9927c2cfd6..3f191aa809 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -1306,6 +1306,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 21d2c54185..b4aaccf7b5 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -2591,3 +2591,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 0000000000..534e304521 ---- /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 0000000000..f48aea0ef8 ---- /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 0000000000..9f01006ddf ---- /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 0000000000..dbe1474b20 ---- /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 0000000000..d367bbfb5a ---- /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 0000000000..3a83b58c59 ---- /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 0000000000..d8a049e8df ---- /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 0000000000..dc7268d4c6 ---- /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 0000000000..75fcd21f0d ---- /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 0000000000..1e7d3d64f5 ---- /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 0000000000..e2561e5ec6 ---- /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 0000000000..555e56dd20 ---- /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 594d0134d3..856e69bc5c 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -264,6 +264,7 @@ widthspec.bin - /stamp-h1 - /syslinux_test - /tar_test -+/test_asn1 - /test_sha512sum - /test_unset - /tests/syslinux/ubuntu10.04_grub.cfg -diff --git a/tests/test_asn1.in b/tests/test_asn1.in -new file mode 100644 -index 0000000000..8173c5c270 ---- /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/0170-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/0170-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch new file mode 100644 index 0000000..0ebc6c7 --- /dev/null +++ b/0170-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 0000000000..ddd1314e63 +--- /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 0000000000..adef69d95c +--- /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/0170-grub-install-support-embedding-x509-certificates.patch b/0170-grub-install-support-embedding-x509-certificates.patch deleted file mode 100644 index c4c35f4..0000000 --- a/0170-grub-install-support-embedding-x509-certificates.patch +++ /dev/null @@ -1,253 +0,0 @@ -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 | 38 ++++++++++++++++++++++++++++++++++++-- - include/grub/kernel.h | 4 +++- - include/grub/util/install.h | 7 +++++-- - 6 files changed, 80 insertions(+), 9 deletions(-) - -diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c -index 355a43844a..b81ac0ae46 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 a74fee16e2..c603f5b308 100644 ---- a/util/grub-install-common.c -+++ b/util/grub-install-common.c -@@ -460,6 +460,8 @@ static char **pubkeys; - static size_t npubkeys; - static char *sbat; - static int disable_shim_lock; -+static char **x509keys; -+static size_t nx509keys; - static grub_compression_t compression; - static size_t appsig_size; - -@@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg) - case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: - disable_shim_lock = 1; - return 1; -+ case 'x': -+ x509keys = xrealloc (x509keys, -+ sizeof (x509keys[0]) -+ * (nx509keys + 1)); -+ x509keys[nx509keys++] = xstrdup (arg); -+ return 1; - - case GRUB_INSTALL_OPTIONS_VERBOSITY: - verbosity++; -@@ -627,6 +635,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, - for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) - slen += 20 + grub_strlen (*pk); - -+ for (pk = x509keys; pk < x509keys + nx509keys; pk++) -+ slen += 10 + grub_strlen (*pk); -+ - for (md = modules.entries; *md; md++) - { - slen += 10 + grub_strlen (*md); -@@ -655,6 +666,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, - *p++ = ' '; - } - -+ for (pk = x509keys; pk < x509keys + nx509keys; pk++) -+ { -+ p = grub_stpcpy (p, "--x509 '"); -+ p = grub_stpcpy (p, *pk); -+ *p++ = '\''; -+ *p++ = ' '; -+ } -+ - for (md = modules.entries; *md; md++) - { - *p++ = '\''; -@@ -684,7 +703,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, sbat, - disable_shim_lock); - while (dc--) -diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c -index 8a53310548..e1f1112784 100644 ---- a/util/grub-mkimage.c -+++ b/util/grub-mkimage.c -@@ -75,7 +75,8 @@ static struct argp_option options[] = { - /* TRANSLATORS: "embed" is a verb (command description). "*/ - {"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0}, - /* TRANSLATORS: "embed" is a verb (command description). "*/ -- {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0}, -+ {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0}, -+ {"x509", 'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0}, - /* TRANSLATORS: NOTE is a name of segment. */ - {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, - {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, -@@ -124,6 +125,8 @@ struct arguments - char *dtb; - char **pubkeys; - size_t npubkeys; -+ char **x509keys; -+ size_t nx509keys; - char *font; - char *config; - char *sbat; -@@ -206,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state) - arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); - break; - -+ case 'x': -+ arguments->x509keys = xrealloc (arguments->x509keys, -+ sizeof (arguments->x509keys[0]) -+ * (arguments->nx509keys + 1)); -+ arguments->x509keys[arguments->nx509keys++] = xstrdup (arg); -+ break; -+ - case 'c': - if (arguments->config) - free (arguments->config); -@@ -332,7 +342,8 @@ main (int argc, char *argv[]) - grub_install_generate_image (arguments.dir, arguments.prefix, fp, - arguments.output, arguments.modules, - arguments.memdisk, arguments.pubkeys, -- arguments.npubkeys, arguments.config, -+ arguments.npubkeys, arguments.x509keys, -+ arguments.nx509keys, arguments.config, - arguments.image_target, arguments.note, - arguments.appsig_size, arguments.comp, - arguments.dtb, arguments.sbat, -diff --git a/util/mkimage.c b/util/mkimage.c -index bab1227601..8319e8dfbd 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -867,7 +867,8 @@ 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, -+ size_t npubkeys, char **x509key_paths, -+ size_t nx509keys, char *config_path, - const struct grub_install_image_target_desc *image_target, - int note, size_t appsig_size, grub_compression_t comp, - const char *dtb_path, const char *sbat_path, -@@ -913,6 +914,19 @@ grub_install_generate_image (const char *dir, const char *prefix, - } - } - -+ { -+ size_t i; -+ for (i = 0; i < nx509keys; i++) -+ { -+ size_t curs; -+ curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i])); -+ grub_util_info ("the size of x509 public key %u is 0x%" -+ GRUB_HOST_PRIxLONG_LONG, -+ (unsigned) i, (unsigned long long) curs); -+ total_module_size += curs + sizeof (struct grub_module_header); -+ } -+ } -+ - if (memdisk_path) - { - memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); -@@ -1034,7 +1048,7 @@ grub_install_generate_image (const char *dir, const char *prefix, - curs = grub_util_get_image_size (pubkey_paths[i]); - - header = (struct grub_module_header *) (kernel_img + offset); -- header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY); -+ header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY); - header->size = grub_host_to_target32 (curs + sizeof (*header)); - offset += sizeof (*header); - -@@ -1043,6 +1057,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 55849777ea..98edc0863f 100644 ---- a/include/grub/kernel.h -+++ b/include/grub/kernel.h -@@ -30,7 +30,9 @@ enum - OBJ_TYPE_PREFIX, - OBJ_TYPE_PUBKEY, - OBJ_TYPE_DTB, -- OBJ_TYPE_DISABLE_SHIM_LOCK -+ OBJ_TYPE_DISABLE_SHIM_LOCK, -+ OBJ_TYPE_GPG_PUBKEY, -+ OBJ_TYPE_X509_PUBKEY, - }; - - /* The module header. */ -diff --git a/include/grub/util/install.h b/include/grub/util/install.h -index cf4531e02b..51f3b13ac1 100644 ---- a/include/grub/util/install.h -+++ b/include/grub/util/install.h -@@ -67,6 +67,8 @@ - N_("SBAT metadata"), 0 }, \ - { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ - N_("disable shim_lock verifier"), 0 }, \ -+ { "x509key", 'x', N_("FILE"), 0, \ -+ N_("embed FILE as an x509 certificate for signature checking"), 0}, \ - { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ - "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ - 1}, \ -@@ -188,8 +190,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/0171-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/0171-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch deleted file mode 100644 index 0ebc6c7..0000000 --- a/0171-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch +++ /dev/null @@ -1,639 +0,0 @@ -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 0000000000..ddd1314e63 ---- /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 0000000000..adef69d95c ---- /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/0171-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/0171-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch new file mode 100644 index 0000000..5a13d5b --- /dev/null +++ b/0171-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch @@ -0,0 +1,1528 @@ +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 | 958 +++++++++++++++++++++++++++ + grub-core/commands/appendedsig/appendedsig.h | 110 +++ + 4 files changed, 1475 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 0000000000..eff095a9df +--- /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 0000000000..dc6afe203f +--- /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 0000000000..2b38b3670a +--- /dev/null ++++ b/grub-core/commands/appendedsig/x509.c +@@ -0,0 +1,958 @@ ++/* ++ * 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)) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only UTF-8 DirectoryStrings are supported, got %s", ++ choice); ++ goto cleanup_choice; ++ } ++ ++ 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; ++ } ++ ++ /* 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, "utf8String", *string, &tmp_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading out UTF-8 string in DirectoryString: %s", ++ 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 0000000000..9792ef3901 +--- /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/0172-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/0172-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch deleted file mode 100644 index 5a13d5b..0000000 --- a/0172-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch +++ /dev/null @@ -1,1528 +0,0 @@ -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 | 958 +++++++++++++++++++++++++++ - grub-core/commands/appendedsig/appendedsig.h | 110 +++ - 4 files changed, 1475 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 0000000000..eff095a9df ---- /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 0000000000..dc6afe203f ---- /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 0000000000..2b38b3670a ---- /dev/null -+++ b/grub-core/commands/appendedsig/x509.c -@@ -0,0 +1,958 @@ -+/* -+ * 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)) -+ { -+ err = -+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, -+ "Only UTF-8 DirectoryStrings are supported, got %s", -+ choice); -+ goto cleanup_choice; -+ } -+ -+ 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; -+ } -+ -+ /* 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, "utf8String", *string, &tmp_size); -+ if (result != ASN1_SUCCESS) -+ { -+ err = -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "Error reading out UTF-8 string in DirectoryString: %s", -+ 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 0000000000..9792ef3901 ---- /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/0172-appended-signatures-support-verifying-appended-signa.patch b/0172-appended-signatures-support-verifying-appended-signa.patch new file mode 100644 index 0000000..969293a --- /dev/null +++ b/0172-appended-signatures-support-verifying-appended-signa.patch @@ -0,0 +1,718 @@ +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 Linux kernels and grub modules +have appended signatures, and commands to manage the list of trusted +certificates for verification. + +Verification must be enabled by setting check_appended_signatures. If +GRUB is locked down when the module is loaded, verification will be +enabled and locked automatically. + +As with the PGP verifier, it is not a complete secure-boot solution: +other mechanisms, such as a password or lockdown, must be used to ensure +that a user cannot drop to the grub shell and disable verification. + +Signed-off-by: Daniel Axtens +[pjones: fix missing format specifier] +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 12 + + grub-core/commands/appendedsig/appendedsig.c | 645 +++++++++++++++++++++++++++ + include/grub/file.h | 2 + + 3 files changed, 659 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 b4aaccf7b5..77321d218c 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -980,6 +980,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 = hdparm; + common = commands/hdparm.c; +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +new file mode 100644 +index 0000000000..bf8b18b620 +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -0,0 +1,645 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020-2021 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++const char magic[] = "~Module signature appended~\n"; ++ ++/* ++ * This structure is extracted from scripts/sign-file.c in the linux kernel ++ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible. ++ */ ++struct module_signature ++{ ++ grub_uint8_t algo; /* Public-key crypto algorithm [0] */ ++ grub_uint8_t hash; /* Digest algorithm [0] */ ++ grub_uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ ++ grub_uint8_t signer_len; /* Length of signer's name [0] */ ++ grub_uint8_t key_id_len; /* Length of key identifier [0] */ ++ grub_uint8_t __pad[3]; ++ grub_uint32_t sig_len; /* Length of signature data */ ++} GRUB_PACKED; ++ ++ ++/* This represents an entire, parsed, appended signature */ ++struct grub_appended_signature ++{ ++ grub_size_t signature_len; /* Length of PKCS#7 data + ++ * metadata + magic */ ++ ++ struct module_signature sig_metadata; /* Module signature metadata */ ++ struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ ++}; ++ ++/* Trusted certificates for verifying appended signatures */ ++struct x509_certificate *grub_trusted_key; ++ ++/* ++ * Force gcry_rsa to be a module dependency. ++ * ++ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built ++ * in if you add 'appendedsig' to grub-install --modules. You would need to ++ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when ++ * we only support RSA. ++ * ++ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the ++ * the filesystem after we install the verifier - we won't be able to verify ++ * it without having it already present. We also shouldn't load it before we ++ * install the verifier, because that would mean it wouldn't be verified - an ++ * attacker could insert any code they wanted into the module. ++ * ++ * So instead, reference the internal symbol from gcry_rsa. That creates a ++ * direct dependency on gcry_rsa, so it will be built in when this module ++ * is built in. Being built in (assuming the core image is itself signed!) ++ * also resolves our concerns about loading from the filesystem. ++ */ ++extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; ++ ++static int check_sigs = 0; ++ ++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 char * ++grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), ++ const char *val) ++{ ++ /* Do not allow the value to be changed if set to forced */ ++ if (check_sigs == 2) ++ return grub_strdup ("forced"); ++ ++ if ((*val == '2') || (*val == 'f')) ++ check_sigs = 2; ++ else if ((*val == '1') || (*val == 'e')) ++ check_sigs = 1; ++ else if ((*val == '0') || (*val == 'n')) ++ check_sigs = 0; ++ ++ return grub_strdup (grub_env_read_sec (NULL, NULL)); ++} ++ ++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 __attribute__((unused)), ++ enum grub_file_type type, ++ void **context __attribute__((unused)), ++ enum grub_verify_flags *flags) ++{ ++ if (!check_sigs) ++ { ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_CERTIFICATE_TRUST: ++ /* ++ * This is a certificate to add to trusted keychain. ++ * ++ * This needs to be verified or blocked. Ideally we'd write an x509 ++ * verifier, but we lack the hubris required to take this on. Instead, ++ * require that it have an appended signature. ++ */ ++ ++ /* Fall through */ ++ ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ /* ++ * Appended signatures are only defined for ELF binaries. ++ * Out of an abundance of caution, we only verify Linux kernels and ++ * GRUB modules at this point. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; ++ ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ /* ++ * It is possible to use appended signature verification without ++ * lockdown - like the PGP verifier. When combined with an embedded ++ * config file in a signed grub binary, this could still be a meaningful ++ * secure-boot chain - so long as it isn't subverted by something like a ++ * rouge ACPI table or DT image. Defer them explicitly. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ return GRUB_ERR_NONE; ++ ++ default: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++} ++ ++static grub_err_t ++appendedsig_write (void *ctxt __attribute__((unused)), ++ void *buf, grub_size_t size) ++{ ++ return grub_verify_appended_signature (buf, size); ++} ++ ++struct grub_file_verifier grub_appendedsig_verifier = { ++ .name = "appendedsig", ++ .init = appendedsig_init, ++ .write = appendedsig_write, ++}; ++ ++static grub_ssize_t ++pseudo_read (struct grub_file *file, char *buf, grub_size_t len) ++{ ++ grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len); ++ return len; ++} ++ ++/* Filesystem descriptor. */ ++static struct grub_fs pseudo_fs = { ++ .name = "pseudo", ++ .fs_read = pseudo_read ++}; ++ ++static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; ++ ++GRUB_MOD_INIT (appendedsig) ++{ ++ int rc; ++ struct grub_module_header *header; ++ ++ /* If in lockdown, immediately enter forced mode */ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ check_sigs = 2; ++ ++ grub_trusted_key = NULL; ++ ++ grub_register_variable_hook ("check_appended_signatures", ++ grub_env_read_sec, ++ grub_env_write_sec); ++ grub_env_export ("check_appended_signatures"); ++ ++ rc = asn1_init (); ++ if (rc) ++ grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, ++ asn1_strerror (rc)); ++ ++ FOR_MODULES (header) ++ { ++ struct grub_file pseudo_file; ++ struct x509_certificate *pk = NULL; ++ grub_err_t err; ++ ++ /* Not an ELF module, skip. */ ++ if (header->type != OBJ_TYPE_X509_PUBKEY) ++ continue; ++ ++ grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); ++ pseudo_file.fs = &pseudo_fs; ++ pseudo_file.size = header->size - sizeof (struct grub_module_header); ++ pseudo_file.data = (char *) header + sizeof (struct grub_module_header); ++ ++ grub_dprintf ("appendedsig", ++ "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", ++ pseudo_file.size); ++ ++ pk = grub_zalloc (sizeof (struct x509_certificate)); ++ if (!pk) ++ { ++ grub_fatal ("Out of memory loading initial certificates"); ++ } ++ ++ err = read_cert_from_file (&pseudo_file, pk); ++ if (err != GRUB_ERR_NONE) ++ grub_fatal ("Error loading initial key: %s", grub_errmsg); ++ ++ grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject); ++ ++ pk->next = grub_trusted_key; ++ grub_trusted_key = pk; ++ } ++ ++ cmd_trust = ++ grub_register_command ("trust_certificate", grub_cmd_trust, ++ N_("X509_CERTIFICATE"), ++ N_("Add X509_CERTIFICATE to trusted certificates.")); ++ cmd_list = ++ grub_register_command ("list_certificates", grub_cmd_list, 0, ++ N_("Show the list of trusted x509 certificates.")); ++ cmd_verify = ++ grub_register_command ("verify_appended", grub_cmd_verify_signature, ++ N_("FILE"), ++ N_("Verify FILE against the trusted x509 certificates.")); ++ cmd_distrust = ++ grub_register_command ("distrust_certificate", grub_cmd_distrust, ++ N_("CERT_NUMBER"), ++ N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates.")); ++ ++ grub_verifier_register (&grub_appendedsig_verifier); ++ grub_dl_set_persistent (mod); ++} ++ ++GRUB_MOD_FINI (appendedsig) ++{ ++ /* ++ * grub_dl_set_persistent should prevent this from actually running, but ++ * it does still run under emu. ++ */ ++ ++ grub_verifier_unregister (&grub_appendedsig_verifier); ++ grub_unregister_command (cmd_verify); ++ grub_unregister_command (cmd_list); ++ grub_unregister_command (cmd_trust); ++ grub_unregister_command (cmd_distrust); ++} +diff --git a/include/grub/file.h b/include/grub/file.h +index 31567483cc..96827a4f89 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -80,6 +80,8 @@ enum grub_file_type + GRUB_FILE_TYPE_PUBLIC_KEY, + /* File holding public key to add to trused keys. */ + GRUB_FILE_TYPE_PUBLIC_KEY_TRUST, ++ /* File holding x509 certificiate to add to trusted keys. */ ++ GRUB_FILE_TYPE_CERTIFICATE_TRUST, + /* File of which we intend to print a blocklist to the user. */ + GRUB_FILE_TYPE_PRINT_BLOCKLIST, + /* File we intend to use for test loading or testing speed. */ diff --git a/0173-appended-signatures-support-verifying-appended-signa.patch b/0173-appended-signatures-support-verifying-appended-signa.patch deleted file mode 100644 index 969293a..0000000 --- a/0173-appended-signatures-support-verifying-appended-signa.patch +++ /dev/null @@ -1,718 +0,0 @@ -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 Linux kernels and grub modules -have appended signatures, and commands to manage the list of trusted -certificates for verification. - -Verification must be enabled by setting check_appended_signatures. If -GRUB is locked down when the module is loaded, verification will be -enabled and locked automatically. - -As with the PGP verifier, it is not a complete secure-boot solution: -other mechanisms, such as a password or lockdown, must be used to ensure -that a user cannot drop to the grub shell and disable verification. - -Signed-off-by: Daniel Axtens -[pjones: fix missing format specifier] -Signed-off-by: Robbie Harwood ---- - grub-core/Makefile.core.def | 12 + - grub-core/commands/appendedsig/appendedsig.c | 645 +++++++++++++++++++++++++++ - include/grub/file.h | 2 + - 3 files changed, 659 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 b4aaccf7b5..77321d218c 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -980,6 +980,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 = hdparm; - common = commands/hdparm.c; -diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c -new file mode 100644 -index 0000000000..bf8b18b620 ---- /dev/null -+++ b/grub-core/commands/appendedsig/appendedsig.c -@@ -0,0 +1,645 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2020-2021 IBM Corporation. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "appendedsig.h" -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+const char magic[] = "~Module signature appended~\n"; -+ -+/* -+ * This structure is extracted from scripts/sign-file.c in the linux kernel -+ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible. -+ */ -+struct module_signature -+{ -+ grub_uint8_t algo; /* Public-key crypto algorithm [0] */ -+ grub_uint8_t hash; /* Digest algorithm [0] */ -+ grub_uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ -+ grub_uint8_t signer_len; /* Length of signer's name [0] */ -+ grub_uint8_t key_id_len; /* Length of key identifier [0] */ -+ grub_uint8_t __pad[3]; -+ grub_uint32_t sig_len; /* Length of signature data */ -+} GRUB_PACKED; -+ -+ -+/* This represents an entire, parsed, appended signature */ -+struct grub_appended_signature -+{ -+ grub_size_t signature_len; /* Length of PKCS#7 data + -+ * metadata + magic */ -+ -+ struct module_signature sig_metadata; /* Module signature metadata */ -+ struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ -+}; -+ -+/* Trusted certificates for verifying appended signatures */ -+struct x509_certificate *grub_trusted_key; -+ -+/* -+ * Force gcry_rsa to be a module dependency. -+ * -+ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built -+ * in if you add 'appendedsig' to grub-install --modules. You would need to -+ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when -+ * we only support RSA. -+ * -+ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the -+ * the filesystem after we install the verifier - we won't be able to verify -+ * it without having it already present. We also shouldn't load it before we -+ * install the verifier, because that would mean it wouldn't be verified - an -+ * attacker could insert any code they wanted into the module. -+ * -+ * So instead, reference the internal symbol from gcry_rsa. That creates a -+ * direct dependency on gcry_rsa, so it will be built in when this module -+ * is built in. Being built in (assuming the core image is itself signed!) -+ * also resolves our concerns about loading from the filesystem. -+ */ -+extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; -+ -+static int check_sigs = 0; -+ -+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 char * -+grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), -+ const char *val) -+{ -+ /* Do not allow the value to be changed if set to forced */ -+ if (check_sigs == 2) -+ return grub_strdup ("forced"); -+ -+ if ((*val == '2') || (*val == 'f')) -+ check_sigs = 2; -+ else if ((*val == '1') || (*val == 'e')) -+ check_sigs = 1; -+ else if ((*val == '0') || (*val == 'n')) -+ check_sigs = 0; -+ -+ return grub_strdup (grub_env_read_sec (NULL, NULL)); -+} -+ -+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 __attribute__((unused)), -+ enum grub_file_type type, -+ void **context __attribute__((unused)), -+ enum grub_verify_flags *flags) -+{ -+ if (!check_sigs) -+ { -+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; -+ return GRUB_ERR_NONE; -+ } -+ -+ switch (type & GRUB_FILE_TYPE_MASK) -+ { -+ case GRUB_FILE_TYPE_CERTIFICATE_TRUST: -+ /* -+ * This is a certificate to add to trusted keychain. -+ * -+ * This needs to be verified or blocked. Ideally we'd write an x509 -+ * verifier, but we lack the hubris required to take this on. Instead, -+ * require that it have an appended signature. -+ */ -+ -+ /* Fall through */ -+ -+ case GRUB_FILE_TYPE_LINUX_KERNEL: -+ case GRUB_FILE_TYPE_GRUB_MODULE: -+ /* -+ * Appended signatures are only defined for ELF binaries. -+ * Out of an abundance of caution, we only verify Linux kernels and -+ * GRUB modules at this point. -+ */ -+ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; -+ return GRUB_ERR_NONE; -+ -+ case GRUB_FILE_TYPE_ACPI_TABLE: -+ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: -+ /* -+ * It is possible to use appended signature verification without -+ * lockdown - like the PGP verifier. When combined with an embedded -+ * config file in a signed grub binary, this could still be a meaningful -+ * secure-boot chain - so long as it isn't subverted by something like a -+ * rouge ACPI table or DT image. Defer them explicitly. -+ */ -+ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; -+ return GRUB_ERR_NONE; -+ -+ default: -+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; -+ return GRUB_ERR_NONE; -+ } -+} -+ -+static grub_err_t -+appendedsig_write (void *ctxt __attribute__((unused)), -+ void *buf, grub_size_t size) -+{ -+ return grub_verify_appended_signature (buf, size); -+} -+ -+struct grub_file_verifier grub_appendedsig_verifier = { -+ .name = "appendedsig", -+ .init = appendedsig_init, -+ .write = appendedsig_write, -+}; -+ -+static grub_ssize_t -+pseudo_read (struct grub_file *file, char *buf, grub_size_t len) -+{ -+ grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len); -+ return len; -+} -+ -+/* Filesystem descriptor. */ -+static struct grub_fs pseudo_fs = { -+ .name = "pseudo", -+ .fs_read = pseudo_read -+}; -+ -+static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; -+ -+GRUB_MOD_INIT (appendedsig) -+{ -+ int rc; -+ struct grub_module_header *header; -+ -+ /* If in lockdown, immediately enter forced mode */ -+ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) -+ check_sigs = 2; -+ -+ grub_trusted_key = NULL; -+ -+ grub_register_variable_hook ("check_appended_signatures", -+ grub_env_read_sec, -+ grub_env_write_sec); -+ grub_env_export ("check_appended_signatures"); -+ -+ rc = asn1_init (); -+ if (rc) -+ grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, -+ asn1_strerror (rc)); -+ -+ FOR_MODULES (header) -+ { -+ struct grub_file pseudo_file; -+ struct x509_certificate *pk = NULL; -+ grub_err_t err; -+ -+ /* Not an ELF module, skip. */ -+ if (header->type != OBJ_TYPE_X509_PUBKEY) -+ continue; -+ -+ grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); -+ pseudo_file.fs = &pseudo_fs; -+ pseudo_file.size = header->size - sizeof (struct grub_module_header); -+ pseudo_file.data = (char *) header + sizeof (struct grub_module_header); -+ -+ grub_dprintf ("appendedsig", -+ "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", -+ pseudo_file.size); -+ -+ pk = grub_zalloc (sizeof (struct x509_certificate)); -+ if (!pk) -+ { -+ grub_fatal ("Out of memory loading initial certificates"); -+ } -+ -+ err = read_cert_from_file (&pseudo_file, pk); -+ if (err != GRUB_ERR_NONE) -+ grub_fatal ("Error loading initial key: %s", grub_errmsg); -+ -+ grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject); -+ -+ pk->next = grub_trusted_key; -+ grub_trusted_key = pk; -+ } -+ -+ cmd_trust = -+ grub_register_command ("trust_certificate", grub_cmd_trust, -+ N_("X509_CERTIFICATE"), -+ N_("Add X509_CERTIFICATE to trusted certificates.")); -+ cmd_list = -+ grub_register_command ("list_certificates", grub_cmd_list, 0, -+ N_("Show the list of trusted x509 certificates.")); -+ cmd_verify = -+ grub_register_command ("verify_appended", grub_cmd_verify_signature, -+ N_("FILE"), -+ N_("Verify FILE against the trusted x509 certificates.")); -+ cmd_distrust = -+ grub_register_command ("distrust_certificate", grub_cmd_distrust, -+ N_("CERT_NUMBER"), -+ N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates.")); -+ -+ grub_verifier_register (&grub_appendedsig_verifier); -+ grub_dl_set_persistent (mod); -+} -+ -+GRUB_MOD_FINI (appendedsig) -+{ -+ /* -+ * grub_dl_set_persistent should prevent this from actually running, but -+ * it does still run under emu. -+ */ -+ -+ grub_verifier_unregister (&grub_appendedsig_verifier); -+ grub_unregister_command (cmd_verify); -+ grub_unregister_command (cmd_list); -+ grub_unregister_command (cmd_trust); -+ grub_unregister_command (cmd_distrust); -+} -diff --git a/include/grub/file.h b/include/grub/file.h -index 31567483cc..96827a4f89 100644 ---- a/include/grub/file.h -+++ b/include/grub/file.h -@@ -80,6 +80,8 @@ enum grub_file_type - GRUB_FILE_TYPE_PUBLIC_KEY, - /* File holding public key to add to trused keys. */ - GRUB_FILE_TYPE_PUBLIC_KEY_TRUST, -+ /* File holding x509 certificiate to add to trusted keys. */ -+ GRUB_FILE_TYPE_CERTIFICATE_TRUST, - /* File of which we intend to print a blocklist to the user. */ - GRUB_FILE_TYPE_PRINT_BLOCKLIST, - /* File we intend to use for test loading or testing speed. */ diff --git a/0173-appended-signatures-verification-tests.patch b/0173-appended-signatures-verification-tests.patch new file mode 100644 index 0000000..982b3c8 --- /dev/null +++ b/0173-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 77321d218c..6bddc841b8 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2161,6 +2161,12 @@ module = { + common = tests/setjmp_test.c; + }; + ++module = { ++ name = appended_signature_test; ++ common = tests/appended_signature_test.c; ++ common = tests/appended_signatures.h; ++}; ++ + module = { + name = signature_test; + common = tests/signature_test.c; +diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c +new file mode 100644 +index 0000000000..88a485200d +--- /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 96781fb39b..403fa5c789 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 0000000000..aa3dc6278e +--- /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/0174-appended-signatures-documentation.patch b/0174-appended-signatures-documentation.patch new file mode 100644 index 0000000..eb58046 --- /dev/null +++ b/0174-appended-signatures-documentation.patch @@ -0,0 +1,341 @@ +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. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 182 insertions(+), 17 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index afbde7c1f7..4816be8561 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -3214,6 +3214,7 @@ These variables have special meaning to GRUB. + + @menu + * biosnum:: ++* check_appended_signatures:: + * check_signatures:: + * chosen:: + * cmdpath:: +@@ -3273,11 +3274,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 +@@ -3994,6 +4002,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 +@@ -4010,6 +4019,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 +@@ -4047,8 +4057,10 @@ you forget a command, you can run the command @command{help} + * test:: Check file types and compare values + * true:: Do nothing, successfully + * trust:: Add public key to list of trusted keys ++* trust_certificate:: Add an x509 certificate to the list of trusted certificates + * unset:: Unset an environment variable + @comment * vbeinfo:: List available video modes ++* verify_appended:: Verify appended digital signature + * verify_detached:: Verify detached digital signature + * videoinfo:: List available video modes + @comment * xen_*:: Xen boot commands for AArch64 +@@ -4376,9 +4388,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} or ++@code{forced} (@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 + +@@ -4636,6 +4667,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 + +@@ -4655,7 +4701,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 + +@@ -4690,8 +4736,13 @@ 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} if GRUB is ++not in @pxref{Lockdown} mode. + @end deffn + + +@@ -4987,7 +5038,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 + + +@@ -5387,11 +5438,32 @@ 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} or ++@code{forced}. ++ ++Note that if @code{check_appended_signatures} is set to @code{enforce} or ++@code{forced} 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 + +@@ -5410,6 +5482,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 +@@ -5428,7 +5512,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 +@@ -5811,13 +5895,14 @@ environment variables and commands are listed in the same order. + @chapter Security + + @menu +-* Authentication and authorisation:: Users and access control +-* Using digital signatures:: Booting digitally signed code +-* UEFI secure boot and shim:: Booting digitally signed PE files +-* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation +-* Measured Boot:: Measuring boot components +-* Lockdown:: Lockdown when booting on a secure setup +-* Signing GRUB itself:: Ensuring the integrity of the GRUB core image ++* Authentication and authorisation:: Users and access control ++* Using GPG-style digital signatures:: Booting digitally signed code ++* Using appended signatures:: An alternative approach to booting digitally signed code ++* UEFI secure boot and shim:: Booting digitally signed PE files ++* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation ++* Measured Boot:: Measuring boot components ++* Lockdown:: Lockdown when booting on a secure setup ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5891,8 +5976,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. +@@ -5985,6 +6070,86 @@ 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 line-feed character, @code{0x0a}. ++ ++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. ++ ++@itemize ++@item @samp{no}: no verification is performed. This is the default when GRUB ++ is not in @pxref{Lockdown} mode. ++@item @samp{enforce}: verification is performed. Verification can be disabled ++ by setting the variable back to @samp{no}. ++@item @samp{forced}: verification is performed and cannot be disabled. This is ++ set when GRUB is in Lockdown when the appendedsig module is loaded. ++@end itemize ++ ++Unlike GPG-style signatures, not all files loaded by GRUB are required to be ++signed. Once verification is turned on, the following file types will have ++appended signatures verified: ++ ++@itemize ++@item Linux kernels ++@item GRUB modules, except those built into the core image ++@item Any new certificate files to be trusted ++@end itemize ++ ++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. ++ ++Unless lockdown mode is enabled, 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, unless lockdown mode is enabled: ++ ++@itemize ++@item Special care must be taken around the @command{loadenv} command, which ++ can be used to turn off @code{check_appended_signature}. ++ ++@item If the grub configuration file is loaded from the disk, anyone who can ++ modify the file on disk can turn off @code{check_appended_signature}. ++ Consider embedding the configuration into the core grub image. ++@end itemize ++ + @node UEFI secure boot and shim + @section UEFI secure boot and shim support + diff --git a/0174-appended-signatures-verification-tests.patch b/0174-appended-signatures-verification-tests.patch deleted file mode 100644 index 982b3c8..0000000 --- a/0174-appended-signatures-verification-tests.patch +++ /dev/null @@ -1,897 +0,0 @@ -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 77321d218c..6bddc841b8 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -2161,6 +2161,12 @@ module = { - common = tests/setjmp_test.c; - }; - -+module = { -+ name = appended_signature_test; -+ common = tests/appended_signature_test.c; -+ common = tests/appended_signatures.h; -+}; -+ - module = { - name = signature_test; - common = tests/signature_test.c; -diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c -new file mode 100644 -index 0000000000..88a485200d ---- /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 96781fb39b..403fa5c789 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 0000000000..aa3dc6278e ---- /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/0175-appended-signatures-documentation.patch b/0175-appended-signatures-documentation.patch deleted file mode 100644 index eb58046..0000000 --- a/0175-appended-signatures-documentation.patch +++ /dev/null @@ -1,341 +0,0 @@ -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. - -Signed-off-by: Daniel Axtens ---- - docs/grub.texi | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 182 insertions(+), 17 deletions(-) - -diff --git a/docs/grub.texi b/docs/grub.texi -index afbde7c1f7..4816be8561 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -3214,6 +3214,7 @@ These variables have special meaning to GRUB. - - @menu - * biosnum:: -+* check_appended_signatures:: - * check_signatures:: - * chosen:: - * cmdpath:: -@@ -3273,11 +3274,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 -@@ -3994,6 +4002,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 -@@ -4010,6 +4019,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 -@@ -4047,8 +4057,10 @@ you forget a command, you can run the command @command{help} - * test:: Check file types and compare values - * true:: Do nothing, successfully - * trust:: Add public key to list of trusted keys -+* trust_certificate:: Add an x509 certificate to the list of trusted certificates - * unset:: Unset an environment variable - @comment * vbeinfo:: List available video modes -+* verify_appended:: Verify appended digital signature - * verify_detached:: Verify detached digital signature - * videoinfo:: List available video modes - @comment * xen_*:: Xen boot commands for AArch64 -@@ -4376,9 +4388,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} or -+@code{forced} (@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 - -@@ -4636,6 +4667,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 - -@@ -4655,7 +4701,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 - -@@ -4690,8 +4736,13 @@ 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} if GRUB is -+not in @pxref{Lockdown} mode. - @end deffn - - -@@ -4987,7 +5038,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 - - -@@ -5387,11 +5438,32 @@ 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} or -+@code{forced}. -+ -+Note that if @code{check_appended_signatures} is set to @code{enforce} or -+@code{forced} 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 - -@@ -5410,6 +5482,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 -@@ -5428,7 +5512,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 -@@ -5811,13 +5895,14 @@ environment variables and commands are listed in the same order. - @chapter Security - - @menu --* Authentication and authorisation:: Users and access control --* Using digital signatures:: Booting digitally signed code --* UEFI secure boot and shim:: Booting digitally signed PE files --* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation --* Measured Boot:: Measuring boot components --* Lockdown:: Lockdown when booting on a secure setup --* Signing GRUB itself:: Ensuring the integrity of the GRUB core image -+* Authentication and authorisation:: Users and access control -+* Using GPG-style digital signatures:: Booting digitally signed code -+* Using appended signatures:: An alternative approach to booting digitally signed code -+* UEFI secure boot and shim:: Booting digitally signed PE files -+* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation -+* Measured Boot:: Measuring boot components -+* Lockdown:: Lockdown when booting on a secure setup -+* Signing GRUB itself:: Ensuring the integrity of the GRUB core image - @end menu - - @node Authentication and authorisation -@@ -5891,8 +5976,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. -@@ -5985,6 +6070,86 @@ 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 line-feed character, @code{0x0a}. -+ -+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. -+ -+@itemize -+@item @samp{no}: no verification is performed. This is the default when GRUB -+ is not in @pxref{Lockdown} mode. -+@item @samp{enforce}: verification is performed. Verification can be disabled -+ by setting the variable back to @samp{no}. -+@item @samp{forced}: verification is performed and cannot be disabled. This is -+ set when GRUB is in Lockdown when the appendedsig module is loaded. -+@end itemize -+ -+Unlike GPG-style signatures, not all files loaded by GRUB are required to be -+signed. Once verification is turned on, the following file types will have -+appended signatures verified: -+ -+@itemize -+@item Linux kernels -+@item GRUB modules, except those built into the core image -+@item Any new certificate files to be trusted -+@end itemize -+ -+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. -+ -+Unless lockdown mode is enabled, 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, unless lockdown mode is enabled: -+ -+@itemize -+@item Special care must be taken around the @command{loadenv} command, which -+ can be used to turn off @code{check_appended_signature}. -+ -+@item If the grub configuration file is loaded from the disk, anyone who can -+ modify the file on disk can turn off @code{check_appended_signature}. -+ Consider embedding the configuration into the core grub image. -+@end itemize -+ - @node UEFI secure boot and shim - @section UEFI secure boot and shim support - diff --git a/0175-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch b/0175-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch new file mode 100644 index 0000000..ed4c684 --- /dev/null +++ b/0175-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Sep 2020 11:11:17 +1000 +Subject: [PATCH] ieee1275: enter lockdown based on /ibm,secure-boot + +If the 'ibm,secure-boot' property of the root node is 2 or greater, +enter lockdown. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/ieee1275/init.c | 27 +++++++++++++++++++++++++++ + include/grub/lockdown.h | 3 ++- + docs/grub.texi | 4 ++-- + 4 files changed, 32 insertions(+), 3 deletions(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 6bddc841b8..3f3459b2c7 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -323,6 +323,7 @@ kernel = { + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; ++ powerpc_ieee1275 = kern/lockdown.c; + + sparc64_ieee1275 = kern/sparc64/cache.S; + sparc64_ieee1275 = kern/sparc64/dl.c; +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 937c1bc44c..fc7d971272 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -44,6 +44,7 @@ + #ifdef __sparc__ + #include + #endif ++#include + + /* The minimal heap size we can live with. */ + #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) +@@ -271,6 +272,30 @@ grub_parse_cmdline (void) + } + } + ++static void ++grub_get_ieee1275_secure_boot (void) ++{ ++ grub_ieee1275_phandle_t root; ++ int rc; ++ grub_uint32_t is_sb; ++ ++ grub_ieee1275_finddevice ("/", &root); ++ ++ rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb, ++ sizeof (is_sb), 0); ++ ++ /* ibm,secure-boot: ++ * 0 - disabled ++ * 1 - audit ++ * 2 - enforce ++ * 3 - enforce + OS-specific behaviour ++ * ++ * We only support enforce. ++ */ ++ if (rc >= 0 && is_sb >= 2) ++ grub_lockdown (); ++} ++ + grub_addr_t grub_modbase; + + void +@@ -296,6 +321,8 @@ grub_machine_init (void) + #else + grub_install_get_time_ms (grub_rtc_get_time_ms); + #endif ++ ++ grub_get_ieee1275_secure_boot (); + } + + void +diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h +index 40531fa823..ebfee4bf06 100644 +--- a/include/grub/lockdown.h ++++ b/include/grub/lockdown.h +@@ -24,7 +24,8 @@ + #define GRUB_LOCKDOWN_DISABLED 0 + #define GRUB_LOCKDOWN_ENABLED 1 + +-#ifdef GRUB_MACHINE_EFI ++#if defined(GRUB_MACHINE_EFI) || \ ++ (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)) + extern void + EXPORT_FUNC (grub_lockdown) (void); + extern int +diff --git a/docs/grub.texi b/docs/grub.texi +index 4816be8561..a4da9c2a1b 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6227,8 +6227,8 @@ Measured boot is currently only supported on EFI platforms. + @section Lockdown when booting on a secure setup + + The GRUB can be locked down when booted on a secure boot environment, for example +-if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will +-be restricted and some operations/commands cannot be executed. ++if UEFI or Power secure boot is enabled. On a locked down configuration, the ++GRUB will be restricted and some operations/commands cannot be executed. + + The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. + Otherwise it does not exit. diff --git a/0176-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch b/0176-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch new file mode 100644 index 0000000..a40caea --- /dev/null +++ b/0176-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 14 Apr 2021 20:10:23 +1000 +Subject: [PATCH] ieee1275: drop HEAP_MAX_ADDR, HEAP_MIN_SIZE + +HEAP_MAX_ADDR is confusing. Currently it is set to 32MB, except +on ieee1275 on x86, where it is 64MB. + +There is a comment which purports to explain it: + +/* If possible, we will avoid claiming heap above this address, because it + seems to cause relocation problems with OSes that link at 4 MiB */ + +This doesn't make a lot of sense when the constants are well above 4MB +already. It was not always this way. Prior to +commit 7b5d0fe4440c ("Increase heap limit") in 2010, HEAP_MAX_SIZE and +HEAP_MAX_ADDR were indeed 4MB. However, when the constants were increased +the comment was left unchanged. + +It's been over a decade. It doesn't seem like we have problems with +claims over 4MB on powerpc or x86 ieee1275. (sparc does things completely +differently and never used the constant.) + +Drop the constant and the check. + +The only use of HEAP_MIN_SIZE was to potentially override the +HEAP_MAX_ADDR check. It is now unused. Remove it. + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/ieee1275/init.c | 17 ----------------- + 1 file changed, 17 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index fc7d971272..0dcd114ce5 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -46,9 +46,6 @@ + #endif + #include + +-/* The minimal heap size we can live with. */ +-#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) +- + /* The maximum heap size we're going to claim */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) +@@ -56,14 +53,6 @@ + #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) + #endif + +-/* If possible, we will avoid claiming heap above this address, because it +- seems to cause relocation problems with OSes that link at 4 MiB */ +-#ifdef __i386__ +-#define HEAP_MAX_ADDR (unsigned long) (64 * 1024 * 1024) +-#else +-#define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) +-#endif +- + extern char _end[]; + + #ifdef __sparc__ +@@ -185,12 +174,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + if (*total + len > HEAP_MAX_SIZE) + len = HEAP_MAX_SIZE - *total; + +- /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */ +- if ((addr < HEAP_MAX_ADDR) && /* if it's too late, don't bother */ +- (addr + len > HEAP_MAX_ADDR) && /* if it wasn't available anyway, don't bother */ +- (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE)) /* only limit ourselves when we can afford to */ +- len = HEAP_MAX_ADDR - addr; +- + /* In theory, firmware should already prevent this from happening by not + listing our own image in /memory/available. The check below is intended + as a safeguard in case that doesn't happen. However, it doesn't protect diff --git a/0176-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch b/0176-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch deleted file mode 100644 index ed4c684..0000000 --- a/0176-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 28 Sep 2020 11:11:17 +1000 -Subject: [PATCH] ieee1275: enter lockdown based on /ibm,secure-boot - -If the 'ibm,secure-boot' property of the root node is 2 or greater, -enter lockdown. - -Signed-off-by: Daniel Axtens ---- - grub-core/Makefile.core.def | 1 + - grub-core/kern/ieee1275/init.c | 27 +++++++++++++++++++++++++++ - include/grub/lockdown.h | 3 ++- - docs/grub.texi | 4 ++-- - 4 files changed, 32 insertions(+), 3 deletions(-) - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 6bddc841b8..3f3459b2c7 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -323,6 +323,7 @@ kernel = { - powerpc_ieee1275 = kern/powerpc/cache.S; - powerpc_ieee1275 = kern/powerpc/dl.c; - powerpc_ieee1275 = kern/powerpc/compiler-rt.S; -+ powerpc_ieee1275 = kern/lockdown.c; - - sparc64_ieee1275 = kern/sparc64/cache.S; - sparc64_ieee1275 = kern/sparc64/dl.c; -diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index 937c1bc44c..fc7d971272 100644 ---- a/grub-core/kern/ieee1275/init.c -+++ b/grub-core/kern/ieee1275/init.c -@@ -44,6 +44,7 @@ - #ifdef __sparc__ - #include - #endif -+#include - - /* The minimal heap size we can live with. */ - #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) -@@ -271,6 +272,30 @@ grub_parse_cmdline (void) - } - } - -+static void -+grub_get_ieee1275_secure_boot (void) -+{ -+ grub_ieee1275_phandle_t root; -+ int rc; -+ grub_uint32_t is_sb; -+ -+ grub_ieee1275_finddevice ("/", &root); -+ -+ rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb, -+ sizeof (is_sb), 0); -+ -+ /* ibm,secure-boot: -+ * 0 - disabled -+ * 1 - audit -+ * 2 - enforce -+ * 3 - enforce + OS-specific behaviour -+ * -+ * We only support enforce. -+ */ -+ if (rc >= 0 && is_sb >= 2) -+ grub_lockdown (); -+} -+ - grub_addr_t grub_modbase; - - void -@@ -296,6 +321,8 @@ grub_machine_init (void) - #else - grub_install_get_time_ms (grub_rtc_get_time_ms); - #endif -+ -+ grub_get_ieee1275_secure_boot (); - } - - void -diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h -index 40531fa823..ebfee4bf06 100644 ---- a/include/grub/lockdown.h -+++ b/include/grub/lockdown.h -@@ -24,7 +24,8 @@ - #define GRUB_LOCKDOWN_DISABLED 0 - #define GRUB_LOCKDOWN_ENABLED 1 - --#ifdef GRUB_MACHINE_EFI -+#if defined(GRUB_MACHINE_EFI) || \ -+ (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)) - extern void - EXPORT_FUNC (grub_lockdown) (void); - extern int -diff --git a/docs/grub.texi b/docs/grub.texi -index 4816be8561..a4da9c2a1b 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -6227,8 +6227,8 @@ Measured boot is currently only supported on EFI platforms. - @section Lockdown when booting on a secure setup - - The GRUB can be locked down when booted on a secure boot environment, for example --if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will --be restricted and some operations/commands cannot be executed. -+if UEFI or Power secure boot is enabled. On a locked down configuration, the -+GRUB will be restricted and some operations/commands cannot be executed. - - The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. - Otherwise it does not exit. diff --git a/0177-ieee1275-claim-more-memory.patch b/0177-ieee1275-claim-more-memory.patch new file mode 100644 index 0000000..6ec319b --- /dev/null +++ b/0177-ieee1275-claim-more-memory.patch @@ -0,0 +1,252 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 15 Apr 2020 23:28:29 +1000 +Subject: [PATCH] ieee1275: claim more memory + +On powerpc-ieee1275, we are running out of memory trying to verify +anything. This is because: + + - we have to load an entire file into memory to verify it. This is + extremely difficult to change with appended signatures. + - We only have 32MB of heap. + - Distro kernels are now often around 30MB. + +So we want to claim more memory from OpenFirmware for our heap. + +There are some complications: + + - The grub mm code isn't the only thing that will make claims on + memory from OpenFirmware: + + * PFW/SLOF will have claimed some for their own use. + + * The ieee1275 loader will try to find other bits of memory that we + haven't claimed to place the kernel and initrd when we go to boot. + + * Once we load Linux, it will also try to claim memory. It claims + memory without any reference to /memory/available, it just starts + at min(top of RMO, 768MB) and works down. So we need to avoid this + area. See arch/powerpc/kernel/prom_init.c as of v5.11. + + - The smallest amount of memory a ppc64 KVM guest can have is 256MB. + It doesn't work with distro kernels but can work with custom kernels. + We should maintain support for that. (ppc32 can boot with even less, + and we shouldn't break that either.) + + - Even if a VM has more memory, the memory OpenFirmware makes available + as Real Memory Area can be restricted. A freshly created LPAR on a + PowerVM machine is likely to have only 256MB available to OpenFirmware + even if it has many gigabytes of memory allocated. + +EFI systems will attempt to allocate 1/4th of the available memory, +clamped to between 1M and 1600M. That seems like a good sort of +approach, we just need to figure out if 1/4 is the right fraction +for us. + +We don't know in advance how big the kernel and initrd are going to be, +which makes figuring out how much memory we can take a bit tricky. + +To figure out how much memory we should leave unused, I looked at: + + - an Ubuntu 20.04.1 ppc64le pseries KVM guest: + vmlinux: ~30MB + initrd: ~50MB + + - a RHEL8.2 ppc64le pseries KVM guest: + vmlinux: ~30MB + initrd: ~30MB + +Ubuntu VMs struggle to boot with just 256MB under SLOF. +RHEL likewise has a higher minimum supported memory figure. +So lets first consider a distro kernel and 512MB of addressible memory. +(This is the default case for anything booting under PFW.) Say we lose +131MB to PFW (based on some tests). This leaves us 381MB. 1/4 of 381MB +is ~95MB. That should be enough to verify a 30MB vmlinux and should +leave plenty of space to load Linux and the initrd. + +If we consider 256MB of RMA under PFW, we have just 125MB remaining. 1/4 +of that is a smidge under 32MB, which gives us very poor odds of verifying +a distro-sized kernel. However, if we need 80MB just to put the kernel +and initrd in memory, we can't claim any more than 45MB anyway. So 1/4 +will do. We'll come back to this later. + +grub is always built as a 32-bit binary, even if it's loading a ppc64 +kernel. So we can't address memory beyond 4GB. This gives a natural cap +of 1GB for powerpc-ieee1275. + +Also apply this 1/4 approach to i386-ieee1275, but keep the 32MB cap. + +make check still works for both i386 and powerpc and I've booted +powerpc grub with this change under SLOF and PFW. + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/ieee1275/init.c | 81 +++++++++++++++++++++++++++++++++--------- + docs/grub-dev.texi | 6 ++-- + 2 files changed, 69 insertions(+), 18 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 0dcd114ce5..c61d91a028 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -46,11 +46,12 @@ + #endif + #include + +-/* The maximum heap size we're going to claim */ ++/* The maximum heap size we're going to claim. Not used by sparc. ++ We allocate 1/4 of the available memory under 4G, up to this limit. */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) +-#else +-#define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) ++#else // __powerpc__ ++#define HEAP_MAX_SIZE (unsigned long) (1 * 1024 * 1024 * 1024) + #endif + + extern char _end[]; +@@ -147,16 +148,45 @@ grub_claim_heap (void) + + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); + } + #else +-/* Helper for grub_claim_heap. */ ++/* Helper for grub_claim_heap on powerpc. */ ++static int ++heap_size (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, ++ void *data) ++{ ++ grub_uint32_t total = *(grub_uint32_t *)data; ++ ++ if (type != GRUB_MEMORY_AVAILABLE) ++ return 0; ++ ++ /* Do not consider memory beyond 4GB */ ++ if (addr > 0xffffffffUL) ++ return 0; ++ ++ if (addr + len > 0xffffffffUL) ++ len = 0xffffffffUL - addr; ++ ++ total += len; ++ *(grub_uint32_t *)data = total; ++ ++ return 0; ++} ++ + static int + heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + void *data) + { +- unsigned long *total = data; ++ grub_uint32_t total = *(grub_uint32_t *)data; + + if (type != GRUB_MEMORY_AVAILABLE) + return 0; + ++ /* Do not consider memory beyond 4GB */ ++ if (addr > 0xffffffffUL) ++ return 0; ++ ++ if (addr + len > 0xffffffffUL) ++ len = 0xffffffffUL - addr; ++ + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) + { + if (addr + len <= 0x180000) +@@ -170,10 +200,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + } + len -= 1; /* Required for some firmware. */ + +- /* Never exceed HEAP_MAX_SIZE */ +- if (*total + len > HEAP_MAX_SIZE) +- len = HEAP_MAX_SIZE - *total; +- + /* In theory, firmware should already prevent this from happening by not + listing our own image in /memory/available. The check below is intended + as a safeguard in case that doesn't happen. However, it doesn't protect +@@ -185,6 +211,18 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + len = 0; + } + ++ /* If this block contains 0x30000000 (768MB), do not claim below that. ++ Linux likes to claim memory at min(RMO top, 768MB) and works down ++ without reference to /memory/available. */ ++ if ((addr < 0x30000000) && ((addr + len) > 0x30000000)) ++ { ++ len = len - (0x30000000 - addr); ++ addr = 0x30000000; ++ } ++ ++ if (len > total) ++ len = total; ++ + if (len) + { + grub_err_t err; +@@ -193,10 +231,12 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + if (err) + return err; + grub_mm_init_region ((void *) (grub_addr_t) addr, len); ++ total -= len; + } + +- *total += len; +- if (*total >= HEAP_MAX_SIZE) ++ *(grub_uint32_t *)data = total; ++ ++ if (total == 0) + return 1; + + return 0; +@@ -205,13 +245,22 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + static void + grub_claim_heap (void) + { +- unsigned long total = 0; ++ grub_uint32_t total = 0; + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) +- heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, +- 1, &total); +- else +- grub_machine_mmap_iterate (heap_init, &total); ++ { ++ heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, ++ 1, &total); ++ return; ++ } ++ ++ grub_machine_mmap_iterate (heap_size, &total); ++ ++ total = total / 4; ++ if (total > HEAP_MAX_SIZE) ++ total = HEAP_MAX_SIZE; ++ ++ grub_machine_mmap_iterate (heap_init, &total); + } + #endif + +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 19f708ee66..90083772c8 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -1047,7 +1047,9 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most + 1.6 GiB. + + On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275. +-It allocates at most 32MiB for its heap. ++ ++On i386-ieee1275, GRUB allocates at most 32MiB for its heap. On ++powerpc-ieee1275, GRUB allocates up to 1GiB. + + On sparc64-ieee1275 stack is 256KiB and heap is 2MiB. + +@@ -1075,7 +1077,7 @@ In short: + @item i386-qemu @tab 60 KiB @tab < 4 GiB + @item *-efi @tab ? @tab < 1.6 GiB + @item i386-ieee1275 @tab ? @tab < 32 MiB +-@item powerpc-ieee1275 @tab ? @tab < 32 MiB ++@item powerpc-ieee1275 @tab ? @tab < 1 GiB + @item sparc64-ieee1275 @tab 256KiB @tab 2 MiB + @item arm-uboot @tab 256KiB @tab 2 MiB + @item mips(el)-qemu_mips @tab 2MiB @tab 253 MiB diff --git a/0177-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch b/0177-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch deleted file mode 100644 index a40caea..0000000 --- a/0177-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Wed, 14 Apr 2021 20:10:23 +1000 -Subject: [PATCH] ieee1275: drop HEAP_MAX_ADDR, HEAP_MIN_SIZE - -HEAP_MAX_ADDR is confusing. Currently it is set to 32MB, except -on ieee1275 on x86, where it is 64MB. - -There is a comment which purports to explain it: - -/* If possible, we will avoid claiming heap above this address, because it - seems to cause relocation problems with OSes that link at 4 MiB */ - -This doesn't make a lot of sense when the constants are well above 4MB -already. It was not always this way. Prior to -commit 7b5d0fe4440c ("Increase heap limit") in 2010, HEAP_MAX_SIZE and -HEAP_MAX_ADDR were indeed 4MB. However, when the constants were increased -the comment was left unchanged. - -It's been over a decade. It doesn't seem like we have problems with -claims over 4MB on powerpc or x86 ieee1275. (sparc does things completely -differently and never used the constant.) - -Drop the constant and the check. - -The only use of HEAP_MIN_SIZE was to potentially override the -HEAP_MAX_ADDR check. It is now unused. Remove it. - -Signed-off-by: Daniel Axtens ---- - grub-core/kern/ieee1275/init.c | 17 ----------------- - 1 file changed, 17 deletions(-) - -diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index fc7d971272..0dcd114ce5 100644 ---- a/grub-core/kern/ieee1275/init.c -+++ b/grub-core/kern/ieee1275/init.c -@@ -46,9 +46,6 @@ - #endif - #include - --/* The minimal heap size we can live with. */ --#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) -- - /* The maximum heap size we're going to claim */ - #ifdef __i386__ - #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) -@@ -56,14 +53,6 @@ - #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) - #endif - --/* If possible, we will avoid claiming heap above this address, because it -- seems to cause relocation problems with OSes that link at 4 MiB */ --#ifdef __i386__ --#define HEAP_MAX_ADDR (unsigned long) (64 * 1024 * 1024) --#else --#define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) --#endif -- - extern char _end[]; - - #ifdef __sparc__ -@@ -185,12 +174,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, - if (*total + len > HEAP_MAX_SIZE) - len = HEAP_MAX_SIZE - *total; - -- /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */ -- if ((addr < HEAP_MAX_ADDR) && /* if it's too late, don't bother */ -- (addr + len > HEAP_MAX_ADDR) && /* if it wasn't available anyway, don't bother */ -- (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE)) /* only limit ourselves when we can afford to */ -- len = HEAP_MAX_ADDR - addr; -- - /* In theory, firmware should already prevent this from happening by not - listing our own image in /memory/available. The check below is intended - as a safeguard in case that doesn't happen. However, it doesn't protect diff --git a/0178-ieee1275-claim-more-memory.patch b/0178-ieee1275-claim-more-memory.patch deleted file mode 100644 index 6ec319b..0000000 --- a/0178-ieee1275-claim-more-memory.patch +++ /dev/null @@ -1,252 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Wed, 15 Apr 2020 23:28:29 +1000 -Subject: [PATCH] ieee1275: claim more memory - -On powerpc-ieee1275, we are running out of memory trying to verify -anything. This is because: - - - we have to load an entire file into memory to verify it. This is - extremely difficult to change with appended signatures. - - We only have 32MB of heap. - - Distro kernels are now often around 30MB. - -So we want to claim more memory from OpenFirmware for our heap. - -There are some complications: - - - The grub mm code isn't the only thing that will make claims on - memory from OpenFirmware: - - * PFW/SLOF will have claimed some for their own use. - - * The ieee1275 loader will try to find other bits of memory that we - haven't claimed to place the kernel and initrd when we go to boot. - - * Once we load Linux, it will also try to claim memory. It claims - memory without any reference to /memory/available, it just starts - at min(top of RMO, 768MB) and works down. So we need to avoid this - area. See arch/powerpc/kernel/prom_init.c as of v5.11. - - - The smallest amount of memory a ppc64 KVM guest can have is 256MB. - It doesn't work with distro kernels but can work with custom kernels. - We should maintain support for that. (ppc32 can boot with even less, - and we shouldn't break that either.) - - - Even if a VM has more memory, the memory OpenFirmware makes available - as Real Memory Area can be restricted. A freshly created LPAR on a - PowerVM machine is likely to have only 256MB available to OpenFirmware - even if it has many gigabytes of memory allocated. - -EFI systems will attempt to allocate 1/4th of the available memory, -clamped to between 1M and 1600M. That seems like a good sort of -approach, we just need to figure out if 1/4 is the right fraction -for us. - -We don't know in advance how big the kernel and initrd are going to be, -which makes figuring out how much memory we can take a bit tricky. - -To figure out how much memory we should leave unused, I looked at: - - - an Ubuntu 20.04.1 ppc64le pseries KVM guest: - vmlinux: ~30MB - initrd: ~50MB - - - a RHEL8.2 ppc64le pseries KVM guest: - vmlinux: ~30MB - initrd: ~30MB - -Ubuntu VMs struggle to boot with just 256MB under SLOF. -RHEL likewise has a higher minimum supported memory figure. -So lets first consider a distro kernel and 512MB of addressible memory. -(This is the default case for anything booting under PFW.) Say we lose -131MB to PFW (based on some tests). This leaves us 381MB. 1/4 of 381MB -is ~95MB. That should be enough to verify a 30MB vmlinux and should -leave plenty of space to load Linux and the initrd. - -If we consider 256MB of RMA under PFW, we have just 125MB remaining. 1/4 -of that is a smidge under 32MB, which gives us very poor odds of verifying -a distro-sized kernel. However, if we need 80MB just to put the kernel -and initrd in memory, we can't claim any more than 45MB anyway. So 1/4 -will do. We'll come back to this later. - -grub is always built as a 32-bit binary, even if it's loading a ppc64 -kernel. So we can't address memory beyond 4GB. This gives a natural cap -of 1GB for powerpc-ieee1275. - -Also apply this 1/4 approach to i386-ieee1275, but keep the 32MB cap. - -make check still works for both i386 and powerpc and I've booted -powerpc grub with this change under SLOF and PFW. - -Signed-off-by: Daniel Axtens ---- - grub-core/kern/ieee1275/init.c | 81 +++++++++++++++++++++++++++++++++--------- - docs/grub-dev.texi | 6 ++-- - 2 files changed, 69 insertions(+), 18 deletions(-) - -diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index 0dcd114ce5..c61d91a028 100644 ---- a/grub-core/kern/ieee1275/init.c -+++ b/grub-core/kern/ieee1275/init.c -@@ -46,11 +46,12 @@ - #endif - #include - --/* The maximum heap size we're going to claim */ -+/* The maximum heap size we're going to claim. Not used by sparc. -+ We allocate 1/4 of the available memory under 4G, up to this limit. */ - #ifdef __i386__ - #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) --#else --#define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) -+#else // __powerpc__ -+#define HEAP_MAX_SIZE (unsigned long) (1 * 1024 * 1024 * 1024) - #endif - - extern char _end[]; -@@ -147,16 +148,45 @@ grub_claim_heap (void) - + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); - } - #else --/* Helper for grub_claim_heap. */ -+/* Helper for grub_claim_heap on powerpc. */ -+static int -+heap_size (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, -+ void *data) -+{ -+ grub_uint32_t total = *(grub_uint32_t *)data; -+ -+ if (type != GRUB_MEMORY_AVAILABLE) -+ return 0; -+ -+ /* Do not consider memory beyond 4GB */ -+ if (addr > 0xffffffffUL) -+ return 0; -+ -+ if (addr + len > 0xffffffffUL) -+ len = 0xffffffffUL - addr; -+ -+ total += len; -+ *(grub_uint32_t *)data = total; -+ -+ return 0; -+} -+ - static int - heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, - void *data) - { -- unsigned long *total = data; -+ grub_uint32_t total = *(grub_uint32_t *)data; - - if (type != GRUB_MEMORY_AVAILABLE) - return 0; - -+ /* Do not consider memory beyond 4GB */ -+ if (addr > 0xffffffffUL) -+ return 0; -+ -+ if (addr + len > 0xffffffffUL) -+ len = 0xffffffffUL - addr; -+ - if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) - { - if (addr + len <= 0x180000) -@@ -170,10 +200,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, - } - len -= 1; /* Required for some firmware. */ - -- /* Never exceed HEAP_MAX_SIZE */ -- if (*total + len > HEAP_MAX_SIZE) -- len = HEAP_MAX_SIZE - *total; -- - /* In theory, firmware should already prevent this from happening by not - listing our own image in /memory/available. The check below is intended - as a safeguard in case that doesn't happen. However, it doesn't protect -@@ -185,6 +211,18 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, - len = 0; - } - -+ /* If this block contains 0x30000000 (768MB), do not claim below that. -+ Linux likes to claim memory at min(RMO top, 768MB) and works down -+ without reference to /memory/available. */ -+ if ((addr < 0x30000000) && ((addr + len) > 0x30000000)) -+ { -+ len = len - (0x30000000 - addr); -+ addr = 0x30000000; -+ } -+ -+ if (len > total) -+ len = total; -+ - if (len) - { - grub_err_t err; -@@ -193,10 +231,12 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, - if (err) - return err; - grub_mm_init_region ((void *) (grub_addr_t) addr, len); -+ total -= len; - } - -- *total += len; -- if (*total >= HEAP_MAX_SIZE) -+ *(grub_uint32_t *)data = total; -+ -+ if (total == 0) - return 1; - - return 0; -@@ -205,13 +245,22 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, - static void - grub_claim_heap (void) - { -- unsigned long total = 0; -+ grub_uint32_t total = 0; - - if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) -- heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, -- 1, &total); -- else -- grub_machine_mmap_iterate (heap_init, &total); -+ { -+ heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, -+ 1, &total); -+ return; -+ } -+ -+ grub_machine_mmap_iterate (heap_size, &total); -+ -+ total = total / 4; -+ if (total > HEAP_MAX_SIZE) -+ total = HEAP_MAX_SIZE; -+ -+ grub_machine_mmap_iterate (heap_init, &total); - } - #endif - -diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi -index 19f708ee66..90083772c8 100644 ---- a/docs/grub-dev.texi -+++ b/docs/grub-dev.texi -@@ -1047,7 +1047,9 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most - 1.6 GiB. - - On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275. --It allocates at most 32MiB for its heap. -+ -+On i386-ieee1275, GRUB allocates at most 32MiB for its heap. On -+powerpc-ieee1275, GRUB allocates up to 1GiB. - - On sparc64-ieee1275 stack is 256KiB and heap is 2MiB. - -@@ -1075,7 +1077,7 @@ In short: - @item i386-qemu @tab 60 KiB @tab < 4 GiB - @item *-efi @tab ? @tab < 1.6 GiB - @item i386-ieee1275 @tab ? @tab < 32 MiB --@item powerpc-ieee1275 @tab ? @tab < 32 MiB -+@item powerpc-ieee1275 @tab ? @tab < 1 GiB - @item sparc64-ieee1275 @tab 256KiB @tab 2 MiB - @item arm-uboot @tab 256KiB @tab 2 MiB - @item mips(el)-qemu_mips @tab 2MiB @tab 253 MiB diff --git a/0178-ieee1275-request-memory-with-ibm-client-architecture.patch b/0178-ieee1275-request-memory-with-ibm-client-architecture.patch new file mode 100644 index 0000000..4f3ab90 --- /dev/null +++ b/0178-ieee1275-request-memory-with-ibm-client-architecture.patch @@ -0,0 +1,268 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 16 Apr 2021 11:48:46 +1000 +Subject: [PATCH] ieee1275: request memory with ibm,client-architecture-support + +On PowerVM, the first time we boot a Linux partition, we may only get +256MB of real memory area, even if the partition has more memory. + +This isn't really enough. Fortunately, the Power Architecture Platform +Reference (PAPR) defines a method we can call to ask for more memory. +This is part of the broad and powerful ibm,client-architecture-support +(CAS) method. + +CAS can do an enormous amount of things on a PAPR platform: as well as +asking for memory, you can set the supported processor level, the interrupt +controller, hash vs radix mmu, and so on. We want to touch as little of +this as possible because we don't want to step on the toes of the future OS. + +If: + + - we are running under what we think is PowerVM (compatible property of / + begins with "IBM"), and + + - the full amount of RMA is less than 512MB (as determined by the reg + property of /memory) + +then call CAS as follows: (refer to the Linux on Power Architecture +Reference, LoPAR, which is public, at B.5.2.3): + + - Use the "any" PVR value and supply 2 option vectors. + + - Set option vector 1 (PowerPC Server Processor Architecture Level) + to "ignore". + + - Set option vector 2 with default or Linux-like options, including a + min-rma-size of 512MB. + +This will cause a CAS reboot and the partition will restart with 512MB +of RMA. Grub will notice the 512MB and not call CAS again. + +(A partition can be configured with only 256MB of memory, which would +mean this request couldn't be satisfied, but PFW refuses to load with +only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB, +but we will never call CAS under qemu/SLOF because /compatible won't +begin with "IBM".) + +One of the first things Linux does while still running under OpenFirmware +is to call CAS with a much fuller set of options (including asking for +512MB of memory). This includes a much more restrictive set of PVR values +and processor support levels, and this will induce another reboot. On this +reboot grub will again notice the higher RMA, and not call CAS. We will get +to Linux, Linux will call CAS but because the values are now set for Linux +this will not induce another CAS reboot and we will finally boot. + +On all subsequent boots, everything will be configured with 512MB of RMA +and all the settings Linux likes, so there will be no further CAS reboots. + +(phyp is super sticky with the RMA size - it persists even on cold boots. +So if you've ever booted Linux in a partition, you'll probably never have +grub call CAS. It'll only ever fire the first time a partition loads grub, +or if you deliberately lower the amount of memory your partition has below +512MB.) + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/ieee1275/cmain.c | 3 + + grub-core/kern/ieee1275/init.c | 144 ++++++++++++++++++++++++++++++++++++++- + include/grub/ieee1275/ieee1275.h | 8 ++- + 3 files changed, 152 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c +index 04df9d2c66..6435628ec5 100644 +--- a/grub-core/kern/ieee1275/cmain.c ++++ b/grub-core/kern/ieee1275/cmain.c +@@ -127,6 +127,9 @@ grub_ieee1275_find_options (void) + break; + } + } ++ ++ if (grub_strncmp (tmp, "IBM,", 4) == 0) ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY); + } + + if (is_smartfirmware) +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index c61d91a028..9704715c83 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -242,6 +242,135 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + return 0; + } + ++/* How much memory does OF believe it has? (regardless of whether ++ it's accessible or not) */ ++static grub_err_t ++grub_ieee1275_total_mem (grub_uint64_t *total) ++{ ++ grub_ieee1275_phandle_t root; ++ grub_ieee1275_phandle_t memory; ++ grub_uint32_t reg[4]; ++ grub_ssize_t reg_size; ++ grub_uint32_t address_cells = 1; ++ grub_uint32_t size_cells = 1; ++ grub_uint64_t size; ++ ++ /* If we fail to get to the end, report 0. */ ++ *total = 0; ++ ++ /* Determine the format of each entry in `reg'. */ ++ grub_ieee1275_finddevice ("/", &root); ++ grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells, ++ sizeof address_cells, 0); ++ grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells, ++ sizeof size_cells, 0); ++ ++ if (size_cells > address_cells) ++ address_cells = size_cells; ++ ++ /* Load `/memory/reg'. */ ++ if (grub_ieee1275_finddevice ("/memory", &memory)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, ++ "couldn't find /memory node"); ++ if (grub_ieee1275_get_integer_property (memory, "reg", reg, ++ sizeof reg, ®_size)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, ++ "couldn't examine /memory/reg property"); ++ if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, ++ "/memory response buffer exceeded"); ++ ++ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS)) ++ { ++ address_cells = 1; ++ size_cells = 1; ++ } ++ ++ /* Decode only the size */ ++ size = reg[address_cells]; ++ if (size_cells == 2) ++ size = (size << 32) | reg[address_cells + 1]; ++ ++ *total = size; ++ ++ return grub_errno; ++} ++ ++/* Based on linux - arch/powerpc/kernel/prom_init.c */ ++struct option_vector2 { ++ grub_uint8_t byte1; ++ grub_uint16_t reserved; ++ grub_uint32_t real_base; ++ grub_uint32_t real_size; ++ grub_uint32_t virt_base; ++ grub_uint32_t virt_size; ++ grub_uint32_t load_base; ++ grub_uint32_t min_rma; ++ grub_uint32_t min_load; ++ grub_uint8_t min_rma_percent; ++ grub_uint8_t max_pft_size; ++} __attribute__((packed)); ++ ++struct pvr_entry { ++ grub_uint32_t mask; ++ grub_uint32_t entry; ++}; ++ ++struct cas_vector { ++ struct { ++ struct pvr_entry terminal; ++ } pvr_list; ++ grub_uint8_t num_vecs; ++ grub_uint8_t vec1_size; ++ grub_uint8_t vec1; ++ grub_uint8_t vec2_size; ++ struct option_vector2 vec2; ++} __attribute__((packed)); ++ ++/* Call ibm,client-architecture-support to try to get more RMA. ++ We ask for 512MB which should be enough to verify a distro kernel. ++ We ignore most errors: if we don't succeed we'll proceed with whatever ++ memory we have. */ ++static void ++grub_ieee1275_ibm_cas (void) ++{ ++ int rc; ++ grub_ieee1275_ihandle_t root; ++ struct cas_args { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_ihandle_t ihandle; ++ grub_ieee1275_cell_t cas_addr; ++ grub_ieee1275_cell_t result; ++ } args; ++ struct cas_vector vector = { ++ .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ ++ .num_vecs = 2 - 1, ++ .vec1_size = 0, ++ .vec1 = 0x80, /* ignore */ ++ .vec2_size = 1 + sizeof(struct option_vector2) - 2, ++ .vec2 = { ++ 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 ++ }, ++ }; ++ ++ INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); ++ args.method = (grub_ieee1275_cell_t)"ibm,client-architecture-support"; ++ rc = grub_ieee1275_open("/", &root); ++ if (rc) { ++ grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS"); ++ return; ++ } ++ args.ihandle = root; ++ args.cas_addr = (grub_ieee1275_cell_t)&vector; ++ ++ grub_printf("Calling ibm,client-architecture-support..."); ++ IEEE1275_CALL_ENTRY_FN (&args); ++ grub_printf("done\n"); ++ ++ grub_ieee1275_close(root); ++} ++ + static void + grub_claim_heap (void) + { +@@ -249,11 +378,22 @@ grub_claim_heap (void) + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) + { +- heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, +- 1, &total); ++ heap_init (GRUB_IEEE1275_STATIC_HEAP_START, ++ GRUB_IEEE1275_STATIC_HEAP_LEN, 1, &total); + return; + } + ++ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) ++ { ++ grub_uint64_t rma_size; ++ grub_err_t err; ++ ++ err = grub_ieee1275_total_mem (&rma_size); ++ /* if we have an error, don't call CAS, just hope for the best */ ++ if (!err && rma_size < (512 * 1024 * 1024)) ++ grub_ieee1275_ibm_cas(); ++ } ++ + grub_machine_mmap_iterate (heap_size, &total); + + total = total / 4; +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index b5a1d49bbc..e0a6c2ce1e 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -149,7 +149,13 @@ enum grub_ieee1275_flag + + GRUB_IEEE1275_FLAG_RAW_DEVNAMES, + +- GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT ++ GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT, ++ ++ /* On PFW, the first time we boot a Linux partition, we may only get 256MB ++ of real memory area, even if the partition has more memory. Set this flag ++ if we think we're running under PFW. Then, if this flag is set, and the ++ RMA is only 256MB in size, try asking for more with CAS. */ ++ GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY, + }; + + extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); diff --git a/0179-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch b/0179-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch new file mode 100644 index 0000000..5728f26 --- /dev/null +++ b/0179-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch @@ -0,0 +1,315 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Sat, 8 May 2021 02:27:58 +0200 +Subject: [PATCH] appendedsig/x509: Also handle the Extended Key Usage + extension + +Red Hat certificates have both Key Usage and Extended Key Usage extensions +present, but the appended signatures x509 parser doesn't handle the latter +and so buils due finding an unrecognised critical extension: + +Error loading initial key: +../../grub-core/commands/appendedsig/x509.c:780:Unhandled critical x509 extension with OID 2.5.29.37 + +Fix this by also parsing the Extended Key Usage extension and handle it by +verifying that the certificate has a single purpose, that is code signing. + +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Daniel Axtens +--- + grub-core/commands/appendedsig/x509.c | 94 ++++++++++++++++++++++++++++++- + grub-core/tests/appended_signature_test.c | 29 +++++++++- + grub-core/tests/appended_signatures.h | 81 ++++++++++++++++++++++++++ + 3 files changed, 201 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +index 2b38b3670a..42ec65c54a 100644 +--- a/grub-core/commands/appendedsig/x509.c ++++ b/grub-core/commands/appendedsig/x509.c +@@ -47,6 +47,12 @@ const char *keyUsage_oid = "2.5.29.15"; + */ + const char *basicConstraints_oid = "2.5.29.19"; + ++/* ++ * RFC 5280 4.2.1.12 Extended Key Usage ++ */ ++const char *extendedKeyUsage_oid = "2.5.29.37"; ++const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; ++ + /* + * RFC 3279 2.3.1 + * +@@ -637,6 +643,77 @@ cleanup: + return err; + } + ++/* ++ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId ++ * ++ * KeyPurposeId ::= OBJECT IDENTIFIER ++ */ ++static grub_err_t ++verify_extended_key_usage (grub_uint8_t * value, int value_size) ++{ ++ asn1_node extendedasn; ++ int result, count; ++ grub_err_t err = GRUB_ERR_NONE; ++ char usage[MAX_OID_LEN]; ++ int usage_size = sizeof (usage); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", ++ &extendedasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Extended Key Usage"); ++ } ++ ++ result = asn1_der_decoding2 (&extendedasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Extended Key Usage: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * If EKUs are present, there must be exactly 1 and it must be a ++ * codeSigning usage. ++ */ ++ result = asn1_number_of_elements(extendedasn, "", &count); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting number of Extended Key Usages: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (extendedasn, "?1", usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Extended Key Usage: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected Extended Key Usage OID, got: %s", ++ usage); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&extendedasn); ++ return err; ++} + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension +@@ -660,7 +737,7 @@ verify_extensions (asn1_node cert) + { + int result; + int ext, num_extensions = 0; +- int usage_present = 0, constraints_present = 0; ++ int usage_present = 0, constraints_present = 0, extended_usage_present = 0; + char *oid_path, *critical_path, *value_path; + char extnID[MAX_OID_LEN]; + int extnID_size; +@@ -754,6 +831,15 @@ verify_extensions (asn1_node cert) + } + constraints_present++; + } ++ else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_extended_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ extended_usage_present++; ++ } + else if (grub_strncmp ("TRUE", critical, critical_size) == 0) + { + /* +@@ -785,6 +871,12 @@ verify_extensions (asn1_node cert) + "Unexpected number of basic constraints extensions - expected 1, got %d", + constraints_present); + } ++ if (extended_usage_present > 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d", ++ extended_usage_present); ++ } + return GRUB_ERR_NONE; + + cleanup_value: +diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c +index 88a485200d..dbba061662 100644 +--- a/grub-core/tests/appended_signature_test.c ++++ b/grub-core/tests/appended_signature_test.c +@@ -111,6 +111,22 @@ static struct grub_procfs_entry certificate_printable_der_entry = { + .get_contents = get_certificate_printable_der + }; + ++static char * ++get_certificate_eku_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_eku_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_eku_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_eku_der_entry = { ++ .name = "certificate_eku.der", ++ .get_contents = get_certificate_eku_der ++}; ++ + + static void + do_verify (const char *f, int is_valid) +@@ -149,6 +165,7 @@ appended_signature_test (void) + char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL }; + char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", + NULL }; ++ char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL }; + char *distrust_args[] = { (char *) "1", NULL }; + char *distrust2_args[] = { (char *) "2", NULL }; + grub_err_t err; +@@ -157,6 +174,7 @@ appended_signature_test (void) + grub_procfs_register ("certificate2.der", &certificate2_der_entry); + grub_procfs_register ("certificate_printable.der", + &certificate_printable_der_entry); ++ grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry); + + cmd_trust = grub_command_find ("trust_certificate"); + if (!cmd_trust) +@@ -266,16 +284,23 @@ appended_signature_test (void) + + /* + * Lastly, check a certificate that uses printableString rather than +- * utf8String loads properly. ++ * utf8String loads properly, and that a certificate with an appropriate ++ * extended key usage loads. + */ + err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable); + grub_test_assert (err == GRUB_ERR_NONE, +- "distrusting printable certificate failed: %d: %s", ++ "trusting printable certificate failed: %d: %s", ++ grub_errno, grub_errmsg); ++ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "trusting certificate with extended key usage failed: %d: %s", + grub_errno, grub_errmsg); + + grub_procfs_unregister (&certificate_der_entry); + grub_procfs_unregister (&certificate2_der_entry); + grub_procfs_unregister (&certificate_printable_der_entry); ++ grub_procfs_unregister (&certificate_eku_der_entry); + } + + GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test); +diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h +index aa3dc6278e..2e5ebd7d8b 100644 +--- a/grub-core/tests/appended_signatures.h ++++ b/grub-core/tests/appended_signatures.h +@@ -555,3 +555,84 @@ unsigned char certificate_printable_der[] = { + 0xd2 + }; + unsigned int certificate_printable_der_len = 829; ++ ++unsigned char certificate_eku_der[] = { ++ 0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, ++ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, ++ 0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86, ++ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63, ++ 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, ++ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32, ++ 0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33, ++ 0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, ++ 0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, ++ 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, ++ 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, ++ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20, ++ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, ++ 0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, ++ 0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, ++ 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15, ++ 0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85, ++ 0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06, ++ 0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5, ++ 0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76, ++ 0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd, ++ 0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c, ++ 0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9, ++ 0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78, ++ 0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29, ++ 0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb, ++ 0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09, ++ 0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6, ++ 0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27, ++ 0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7, ++ 0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55, ++ 0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68, ++ 0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90, ++ 0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62, ++ 0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16, ++ 0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b, ++ 0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01, ++ 0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, ++ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, ++ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, ++ 0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c, ++ 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, ++ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c, ++ 0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f, ++ 0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab, ++ 0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4, ++ 0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, ++ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, ++ 0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9, ++ 0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef, ++ 0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29, ++ 0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b, ++ 0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf, ++ 0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32, ++ 0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9, ++ 0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74, ++ 0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb, ++ 0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0, ++ 0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24, ++ 0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06, ++ 0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57, ++ 0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61, ++ 0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21, ++ 0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1, ++ 0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81, ++ 0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3, ++ 0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e, ++ 0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd, ++ 0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21, ++ 0x89, 0xa0, 0x55, 0xf7 ++}; ++unsigned int certificate_eku_der_len = 916; diff --git a/0179-ieee1275-request-memory-with-ibm-client-architecture.patch b/0179-ieee1275-request-memory-with-ibm-client-architecture.patch deleted file mode 100644 index 4f3ab90..0000000 --- a/0179-ieee1275-request-memory-with-ibm-client-architecture.patch +++ /dev/null @@ -1,268 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 16 Apr 2021 11:48:46 +1000 -Subject: [PATCH] ieee1275: request memory with ibm,client-architecture-support - -On PowerVM, the first time we boot a Linux partition, we may only get -256MB of real memory area, even if the partition has more memory. - -This isn't really enough. Fortunately, the Power Architecture Platform -Reference (PAPR) defines a method we can call to ask for more memory. -This is part of the broad and powerful ibm,client-architecture-support -(CAS) method. - -CAS can do an enormous amount of things on a PAPR platform: as well as -asking for memory, you can set the supported processor level, the interrupt -controller, hash vs radix mmu, and so on. We want to touch as little of -this as possible because we don't want to step on the toes of the future OS. - -If: - - - we are running under what we think is PowerVM (compatible property of / - begins with "IBM"), and - - - the full amount of RMA is less than 512MB (as determined by the reg - property of /memory) - -then call CAS as follows: (refer to the Linux on Power Architecture -Reference, LoPAR, which is public, at B.5.2.3): - - - Use the "any" PVR value and supply 2 option vectors. - - - Set option vector 1 (PowerPC Server Processor Architecture Level) - to "ignore". - - - Set option vector 2 with default or Linux-like options, including a - min-rma-size of 512MB. - -This will cause a CAS reboot and the partition will restart with 512MB -of RMA. Grub will notice the 512MB and not call CAS again. - -(A partition can be configured with only 256MB of memory, which would -mean this request couldn't be satisfied, but PFW refuses to load with -only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB, -but we will never call CAS under qemu/SLOF because /compatible won't -begin with "IBM".) - -One of the first things Linux does while still running under OpenFirmware -is to call CAS with a much fuller set of options (including asking for -512MB of memory). This includes a much more restrictive set of PVR values -and processor support levels, and this will induce another reboot. On this -reboot grub will again notice the higher RMA, and not call CAS. We will get -to Linux, Linux will call CAS but because the values are now set for Linux -this will not induce another CAS reboot and we will finally boot. - -On all subsequent boots, everything will be configured with 512MB of RMA -and all the settings Linux likes, so there will be no further CAS reboots. - -(phyp is super sticky with the RMA size - it persists even on cold boots. -So if you've ever booted Linux in a partition, you'll probably never have -grub call CAS. It'll only ever fire the first time a partition loads grub, -or if you deliberately lower the amount of memory your partition has below -512MB.) - -Signed-off-by: Daniel Axtens ---- - grub-core/kern/ieee1275/cmain.c | 3 + - grub-core/kern/ieee1275/init.c | 144 ++++++++++++++++++++++++++++++++++++++- - include/grub/ieee1275/ieee1275.h | 8 ++- - 3 files changed, 152 insertions(+), 3 deletions(-) - -diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c -index 04df9d2c66..6435628ec5 100644 ---- a/grub-core/kern/ieee1275/cmain.c -+++ b/grub-core/kern/ieee1275/cmain.c -@@ -127,6 +127,9 @@ grub_ieee1275_find_options (void) - break; - } - } -+ -+ if (grub_strncmp (tmp, "IBM,", 4) == 0) -+ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY); - } - - if (is_smartfirmware) -diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index c61d91a028..9704715c83 100644 ---- a/grub-core/kern/ieee1275/init.c -+++ b/grub-core/kern/ieee1275/init.c -@@ -242,6 +242,135 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, - return 0; - } - -+/* How much memory does OF believe it has? (regardless of whether -+ it's accessible or not) */ -+static grub_err_t -+grub_ieee1275_total_mem (grub_uint64_t *total) -+{ -+ grub_ieee1275_phandle_t root; -+ grub_ieee1275_phandle_t memory; -+ grub_uint32_t reg[4]; -+ grub_ssize_t reg_size; -+ grub_uint32_t address_cells = 1; -+ grub_uint32_t size_cells = 1; -+ grub_uint64_t size; -+ -+ /* If we fail to get to the end, report 0. */ -+ *total = 0; -+ -+ /* Determine the format of each entry in `reg'. */ -+ grub_ieee1275_finddevice ("/", &root); -+ grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells, -+ sizeof address_cells, 0); -+ grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells, -+ sizeof size_cells, 0); -+ -+ if (size_cells > address_cells) -+ address_cells = size_cells; -+ -+ /* Load `/memory/reg'. */ -+ if (grub_ieee1275_finddevice ("/memory", &memory)) -+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, -+ "couldn't find /memory node"); -+ if (grub_ieee1275_get_integer_property (memory, "reg", reg, -+ sizeof reg, ®_size)) -+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, -+ "couldn't examine /memory/reg property"); -+ if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg)) -+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, -+ "/memory response buffer exceeded"); -+ -+ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS)) -+ { -+ address_cells = 1; -+ size_cells = 1; -+ } -+ -+ /* Decode only the size */ -+ size = reg[address_cells]; -+ if (size_cells == 2) -+ size = (size << 32) | reg[address_cells + 1]; -+ -+ *total = size; -+ -+ return grub_errno; -+} -+ -+/* Based on linux - arch/powerpc/kernel/prom_init.c */ -+struct option_vector2 { -+ grub_uint8_t byte1; -+ grub_uint16_t reserved; -+ grub_uint32_t real_base; -+ grub_uint32_t real_size; -+ grub_uint32_t virt_base; -+ grub_uint32_t virt_size; -+ grub_uint32_t load_base; -+ grub_uint32_t min_rma; -+ grub_uint32_t min_load; -+ grub_uint8_t min_rma_percent; -+ grub_uint8_t max_pft_size; -+} __attribute__((packed)); -+ -+struct pvr_entry { -+ grub_uint32_t mask; -+ grub_uint32_t entry; -+}; -+ -+struct cas_vector { -+ struct { -+ struct pvr_entry terminal; -+ } pvr_list; -+ grub_uint8_t num_vecs; -+ grub_uint8_t vec1_size; -+ grub_uint8_t vec1; -+ grub_uint8_t vec2_size; -+ struct option_vector2 vec2; -+} __attribute__((packed)); -+ -+/* Call ibm,client-architecture-support to try to get more RMA. -+ We ask for 512MB which should be enough to verify a distro kernel. -+ We ignore most errors: if we don't succeed we'll proceed with whatever -+ memory we have. */ -+static void -+grub_ieee1275_ibm_cas (void) -+{ -+ int rc; -+ grub_ieee1275_ihandle_t root; -+ struct cas_args { -+ struct grub_ieee1275_common_hdr common; -+ grub_ieee1275_cell_t method; -+ grub_ieee1275_ihandle_t ihandle; -+ grub_ieee1275_cell_t cas_addr; -+ grub_ieee1275_cell_t result; -+ } args; -+ struct cas_vector vector = { -+ .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ -+ .num_vecs = 2 - 1, -+ .vec1_size = 0, -+ .vec1 = 0x80, /* ignore */ -+ .vec2_size = 1 + sizeof(struct option_vector2) - 2, -+ .vec2 = { -+ 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 -+ }, -+ }; -+ -+ INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); -+ args.method = (grub_ieee1275_cell_t)"ibm,client-architecture-support"; -+ rc = grub_ieee1275_open("/", &root); -+ if (rc) { -+ grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS"); -+ return; -+ } -+ args.ihandle = root; -+ args.cas_addr = (grub_ieee1275_cell_t)&vector; -+ -+ grub_printf("Calling ibm,client-architecture-support..."); -+ IEEE1275_CALL_ENTRY_FN (&args); -+ grub_printf("done\n"); -+ -+ grub_ieee1275_close(root); -+} -+ - static void - grub_claim_heap (void) - { -@@ -249,11 +378,22 @@ grub_claim_heap (void) - - if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) - { -- heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, -- 1, &total); -+ heap_init (GRUB_IEEE1275_STATIC_HEAP_START, -+ GRUB_IEEE1275_STATIC_HEAP_LEN, 1, &total); - return; - } - -+ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) -+ { -+ grub_uint64_t rma_size; -+ grub_err_t err; -+ -+ err = grub_ieee1275_total_mem (&rma_size); -+ /* if we have an error, don't call CAS, just hope for the best */ -+ if (!err && rma_size < (512 * 1024 * 1024)) -+ grub_ieee1275_ibm_cas(); -+ } -+ - grub_machine_mmap_iterate (heap_size, &total); - - total = total / 4; -diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h -index b5a1d49bbc..e0a6c2ce1e 100644 ---- a/include/grub/ieee1275/ieee1275.h -+++ b/include/grub/ieee1275/ieee1275.h -@@ -149,7 +149,13 @@ enum grub_ieee1275_flag - - GRUB_IEEE1275_FLAG_RAW_DEVNAMES, - -- GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT -+ GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT, -+ -+ /* On PFW, the first time we boot a Linux partition, we may only get 256MB -+ of real memory area, even if the partition has more memory. Set this flag -+ if we think we're running under PFW. Then, if this flag is set, and the -+ RMA is only 256MB in size, try asking for more with CAS. */ -+ GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY, - }; - - extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); diff --git a/0180-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch b/0180-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch deleted file mode 100644 index 5728f26..0000000 --- a/0180-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch +++ /dev/null @@ -1,315 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Sat, 8 May 2021 02:27:58 +0200 -Subject: [PATCH] appendedsig/x509: Also handle the Extended Key Usage - extension - -Red Hat certificates have both Key Usage and Extended Key Usage extensions -present, but the appended signatures x509 parser doesn't handle the latter -and so buils due finding an unrecognised critical extension: - -Error loading initial key: -../../grub-core/commands/appendedsig/x509.c:780:Unhandled critical x509 extension with OID 2.5.29.37 - -Fix this by also parsing the Extended Key Usage extension and handle it by -verifying that the certificate has a single purpose, that is code signing. - -Signed-off-by: Javier Martinez Canillas -Signed-off-by: Daniel Axtens ---- - grub-core/commands/appendedsig/x509.c | 94 ++++++++++++++++++++++++++++++- - grub-core/tests/appended_signature_test.c | 29 +++++++++- - grub-core/tests/appended_signatures.h | 81 ++++++++++++++++++++++++++ - 3 files changed, 201 insertions(+), 3 deletions(-) - -diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c -index 2b38b3670a..42ec65c54a 100644 ---- a/grub-core/commands/appendedsig/x509.c -+++ b/grub-core/commands/appendedsig/x509.c -@@ -47,6 +47,12 @@ const char *keyUsage_oid = "2.5.29.15"; - */ - const char *basicConstraints_oid = "2.5.29.19"; - -+/* -+ * RFC 5280 4.2.1.12 Extended Key Usage -+ */ -+const char *extendedKeyUsage_oid = "2.5.29.37"; -+const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; -+ - /* - * RFC 3279 2.3.1 - * -@@ -637,6 +643,77 @@ cleanup: - return err; - } - -+/* -+ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId -+ * -+ * KeyPurposeId ::= OBJECT IDENTIFIER -+ */ -+static grub_err_t -+verify_extended_key_usage (grub_uint8_t * value, int value_size) -+{ -+ asn1_node extendedasn; -+ int result, count; -+ grub_err_t err = GRUB_ERR_NONE; -+ char usage[MAX_OID_LEN]; -+ int usage_size = sizeof (usage); -+ -+ result = -+ asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", -+ &extendedasn); -+ if (result != ASN1_SUCCESS) -+ { -+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, -+ "Could not create ASN.1 structure for Extended Key Usage"); -+ } -+ -+ result = asn1_der_decoding2 (&extendedasn, value, &value_size, -+ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); -+ if (result != ASN1_SUCCESS) -+ { -+ err = -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "Error parsing DER for Extended Key Usage: %s", -+ asn1_error); -+ goto cleanup; -+ } -+ -+ /* -+ * If EKUs are present, there must be exactly 1 and it must be a -+ * codeSigning usage. -+ */ -+ result = asn1_number_of_elements(extendedasn, "", &count); -+ if (result != ASN1_SUCCESS) -+ { -+ err = -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "Error counting number of Extended Key Usages: %s", -+ asn1_strerror (result)); -+ goto cleanup; -+ } -+ -+ result = asn1_read_value (extendedasn, "?1", usage, &usage_size); -+ if (result != ASN1_SUCCESS) -+ { -+ err = -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "Error reading Extended Key Usage: %s", -+ asn1_strerror (result)); -+ goto cleanup; -+ } -+ -+ if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0) -+ { -+ err = -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "Unexpected Extended Key Usage OID, got: %s", -+ usage); -+ goto cleanup; -+ } -+ -+cleanup: -+ asn1_delete_structure (&extendedasn); -+ return err; -+} - - /* - * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension -@@ -660,7 +737,7 @@ verify_extensions (asn1_node cert) - { - int result; - int ext, num_extensions = 0; -- int usage_present = 0, constraints_present = 0; -+ int usage_present = 0, constraints_present = 0, extended_usage_present = 0; - char *oid_path, *critical_path, *value_path; - char extnID[MAX_OID_LEN]; - int extnID_size; -@@ -754,6 +831,15 @@ verify_extensions (asn1_node cert) - } - constraints_present++; - } -+ else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0) -+ { -+ err = verify_extended_key_usage (value, value_size); -+ if (err != GRUB_ERR_NONE) -+ { -+ goto cleanup_value; -+ } -+ extended_usage_present++; -+ } - else if (grub_strncmp ("TRUE", critical, critical_size) == 0) - { - /* -@@ -785,6 +871,12 @@ verify_extensions (asn1_node cert) - "Unexpected number of basic constraints extensions - expected 1, got %d", - constraints_present); - } -+ if (extended_usage_present > 1) -+ { -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d", -+ extended_usage_present); -+ } - return GRUB_ERR_NONE; - - cleanup_value: -diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c -index 88a485200d..dbba061662 100644 ---- a/grub-core/tests/appended_signature_test.c -+++ b/grub-core/tests/appended_signature_test.c -@@ -111,6 +111,22 @@ static struct grub_procfs_entry certificate_printable_der_entry = { - .get_contents = get_certificate_printable_der - }; - -+static char * -+get_certificate_eku_der (grub_size_t * sz) -+{ -+ char *ret; -+ *sz = certificate_eku_der_len; -+ ret = grub_malloc (*sz); -+ if (ret) -+ grub_memcpy (ret, certificate_eku_der, *sz); -+ return ret; -+} -+ -+static struct grub_procfs_entry certificate_eku_der_entry = { -+ .name = "certificate_eku.der", -+ .get_contents = get_certificate_eku_der -+}; -+ - - static void - do_verify (const char *f, int is_valid) -@@ -149,6 +165,7 @@ appended_signature_test (void) - char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL }; - char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", - NULL }; -+ char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL }; - char *distrust_args[] = { (char *) "1", NULL }; - char *distrust2_args[] = { (char *) "2", NULL }; - grub_err_t err; -@@ -157,6 +174,7 @@ appended_signature_test (void) - grub_procfs_register ("certificate2.der", &certificate2_der_entry); - grub_procfs_register ("certificate_printable.der", - &certificate_printable_der_entry); -+ grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry); - - cmd_trust = grub_command_find ("trust_certificate"); - if (!cmd_trust) -@@ -266,16 +284,23 @@ appended_signature_test (void) - - /* - * Lastly, check a certificate that uses printableString rather than -- * utf8String loads properly. -+ * utf8String loads properly, and that a certificate with an appropriate -+ * extended key usage loads. - */ - err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable); - grub_test_assert (err == GRUB_ERR_NONE, -- "distrusting printable certificate failed: %d: %s", -+ "trusting printable certificate failed: %d: %s", -+ grub_errno, grub_errmsg); -+ -+ err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku); -+ grub_test_assert (err == GRUB_ERR_NONE, -+ "trusting certificate with extended key usage failed: %d: %s", - grub_errno, grub_errmsg); - - grub_procfs_unregister (&certificate_der_entry); - grub_procfs_unregister (&certificate2_der_entry); - grub_procfs_unregister (&certificate_printable_der_entry); -+ grub_procfs_unregister (&certificate_eku_der_entry); - } - - GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test); -diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h -index aa3dc6278e..2e5ebd7d8b 100644 ---- a/grub-core/tests/appended_signatures.h -+++ b/grub-core/tests/appended_signatures.h -@@ -555,3 +555,84 @@ unsigned char certificate_printable_der[] = { - 0xd2 - }; - unsigned int certificate_printable_der_len = 829; -+ -+unsigned char certificate_eku_der[] = { -+ 0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01, -+ 0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45, -+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, -+ 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, -+ 0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, -+ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, -+ 0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86, -+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63, -+ 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, -+ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32, -+ 0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33, -+ 0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, -+ 0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, -+ 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, -+ 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, -+ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20, -+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, -+ 0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, -+ 0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, -+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, -+ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, -+ 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15, -+ 0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85, -+ 0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06, -+ 0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5, -+ 0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76, -+ 0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd, -+ 0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c, -+ 0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9, -+ 0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78, -+ 0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29, -+ 0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb, -+ 0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09, -+ 0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6, -+ 0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27, -+ 0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7, -+ 0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55, -+ 0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68, -+ 0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90, -+ 0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62, -+ 0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16, -+ 0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b, -+ 0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01, -+ 0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, -+ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, -+ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, -+ 0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c, -+ 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, -+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c, -+ 0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f, -+ 0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55, -+ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab, -+ 0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4, -+ 0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, -+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, -+ 0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9, -+ 0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef, -+ 0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29, -+ 0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b, -+ 0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf, -+ 0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32, -+ 0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9, -+ 0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74, -+ 0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb, -+ 0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0, -+ 0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24, -+ 0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06, -+ 0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57, -+ 0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61, -+ 0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21, -+ 0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1, -+ 0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81, -+ 0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3, -+ 0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e, -+ 0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd, -+ 0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21, -+ 0x89, 0xa0, 0x55, 0xf7 -+}; -+unsigned int certificate_eku_der_len = 916; diff --git a/0180-ieee1275-ofdisk-retry-on-open-failure.patch b/0180-ieee1275-ofdisk-retry-on-open-failure.patch new file mode 100644 index 0000000..9149773 --- /dev/null +++ b/0180-ieee1275-ofdisk-retry-on-open-failure.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Wed, 10 Mar 2021 14:17:52 -0500 +Subject: [PATCH] ieee1275/ofdisk: retry on open failure + +This patch aims to make grub more robust when booting from SAN/Multipath disks. + +If a path is failing intermittently so grub will retry the OPEN and READ the +disk (grub_ieee1275_open and grub_ieee1275_read) until the total amount of times +specified in MAX_RETRIES. + +Signed-off-by: Diego Domingos +--- + grub-core/disk/ieee1275/ofdisk.c | 25 ++++++++++++++++++++----- + include/grub/ieee1275/ofdisk.h | 8 ++++++++ + 2 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index ea7f78ac7d..55346849d3 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -225,7 +225,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + char *buf, *bufptr; + unsigned i; + +- if (grub_ieee1275_open (alias->path, &ihandle)) ++ ++ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle) ++ if (! ihandle) + return; + + /* This method doesn't need memory allocation for the table. Open +@@ -305,7 +307,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + return; + } + +- if (grub_ieee1275_open (alias->path, &ihandle)) ++ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle); ++ ++ if (! ihandle) + { + grub_free (buf); + grub_free (table); +@@ -495,7 +499,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + last_ihandle = 0; + last_devpath = NULL; + +- grub_ieee1275_open (op->open_path, &last_ihandle); ++ RETRY_IEEE1275_OFDISK_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; +@@ -571,7 +575,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) + last_ihandle = 0; + last_devpath = NULL; + +- grub_ieee1275_open (disk->data, &last_ihandle); ++ RETRY_IEEE1275_OFDISK_OPEN(disk->data, &last_ihandle); + if (! last_ihandle) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + last_devpath = disk->data; +@@ -598,12 +602,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + return err; + grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, + &actual); +- if (actual != (grub_ssize_t) (size << disk->log_sector_size)) ++ int i = 0; ++ while(actual != (grub_ssize_t) (size << disk->log_sector_size)){ ++ if (i>MAX_RETRIES){ + return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx " + "from `%s'"), + (unsigned long long) sector, + disk->name); ++ } ++ last_devpath = NULL; ++ err = grub_ofdisk_prepare (disk, sector); ++ if (err) ++ return err; + ++ grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, ++ &actual); ++ i++; ++ } + return 0; + } + +diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h +index 2f69e3f191..7d2d540930 100644 +--- a/include/grub/ieee1275/ofdisk.h ++++ b/include/grub/ieee1275/ofdisk.h +@@ -22,4 +22,12 @@ + extern void grub_ofdisk_init (void); + extern void grub_ofdisk_fini (void); + ++#define MAX_RETRIES 20 ++ ++ ++#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \ ++ if(!grub_ieee1275_open(device, last_ihandle)) \ ++ break; \ ++ grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); } ++ + #endif /* ! GRUB_INIT_HEADER */ diff --git a/0181-Allow-chainloading-EFI-apps-from-loop-mounts.patch b/0181-Allow-chainloading-EFI-apps-from-loop-mounts.patch new file mode 100644 index 0000000..c3101e1 --- /dev/null +++ b/0181-Allow-chainloading-EFI-apps-from-loop-mounts.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 11 Jun 2021 13:51:20 +0200 +Subject: [PATCH] Allow chainloading EFI apps from loop mounts. + +Signed-off-by: Dimitri John Ledkov +Signed-off-by: Robbie Harwood +--- + grub-core/disk/loopback.c | 9 +-------- + grub-core/loader/efi/chainloader.c | 23 +++++++++++++++++++++++ + include/grub/loopback.h | 30 ++++++++++++++++++++++++++++++ + 3 files changed, 54 insertions(+), 8 deletions(-) + create mode 100644 include/grub/loopback.h + +diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c +index 41bebd14fe..99f47924ec 100644 +--- a/grub-core/disk/loopback.c ++++ b/grub-core/disk/loopback.c +@@ -21,20 +21,13 @@ + #include + #include + #include ++#include + #include + #include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); + +-struct grub_loopback +-{ +- char *devname; +- grub_file_t file; +- struct grub_loopback *next; +- unsigned long id; +-}; +- + static struct grub_loopback *loopback_list; + static unsigned long last_id = 0; + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index d41e8ea14a..3af6b12292 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -901,6 +902,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; ++ grub_device_t orig_dev = 0; + grub_efi_device_path_t *dp = 0; + char *filename; + void *boot_image = 0; +@@ -958,6 +960,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + if (! dev) + goto fail; + ++ /* if device is loopback, use underlying dev */ ++ if (dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID) ++ { ++ struct grub_loopback *d; ++ orig_dev = dev; ++ d = dev->disk->data; ++ dev = d->file->device; ++ } ++ + if (dev->disk) + dev_handle = grub_efidisk_get_device_handle (dev->disk); + else if (dev->net && dev->net->server) +@@ -1065,6 +1076,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ if (orig_dev) ++ { ++ dev = orig_dev; ++ orig_dev = 0; ++ } ++ + rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize); + grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); + if (rc > 0) +@@ -1087,6 +1104,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + // -1 fall-through to fail + + fail: ++ if (orig_dev) ++ { ++ dev = orig_dev; ++ orig_dev = 0; ++ } ++ + if (dev) + grub_device_close (dev); + +diff --git a/include/grub/loopback.h b/include/grub/loopback.h +new file mode 100644 +index 0000000000..3b9a9e32e8 +--- /dev/null ++++ b/include/grub/loopback.h +@@ -0,0 +1,30 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2019 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_LOOPBACK_HEADER ++#define GRUB_LOOPBACK_HEADER 1 ++ ++struct grub_loopback ++{ ++ char *devname; ++ grub_file_t file; ++ struct grub_loopback *next; ++ unsigned long id; ++}; ++ ++#endif /* ! GRUB_LOOPBACK_HEADER */ diff --git a/0181-ieee1275-ofdisk-retry-on-open-failure.patch b/0181-ieee1275-ofdisk-retry-on-open-failure.patch deleted file mode 100644 index 9149773..0000000 --- a/0181-ieee1275-ofdisk-retry-on-open-failure.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Diego Domingos -Date: Wed, 10 Mar 2021 14:17:52 -0500 -Subject: [PATCH] ieee1275/ofdisk: retry on open failure - -This patch aims to make grub more robust when booting from SAN/Multipath disks. - -If a path is failing intermittently so grub will retry the OPEN and READ the -disk (grub_ieee1275_open and grub_ieee1275_read) until the total amount of times -specified in MAX_RETRIES. - -Signed-off-by: Diego Domingos ---- - grub-core/disk/ieee1275/ofdisk.c | 25 ++++++++++++++++++++----- - include/grub/ieee1275/ofdisk.h | 8 ++++++++ - 2 files changed, 28 insertions(+), 5 deletions(-) - -diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c -index ea7f78ac7d..55346849d3 100644 ---- a/grub-core/disk/ieee1275/ofdisk.c -+++ b/grub-core/disk/ieee1275/ofdisk.c -@@ -225,7 +225,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) - char *buf, *bufptr; - unsigned i; - -- if (grub_ieee1275_open (alias->path, &ihandle)) -+ -+ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle) -+ if (! ihandle) - return; - - /* This method doesn't need memory allocation for the table. Open -@@ -305,7 +307,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) - return; - } - -- if (grub_ieee1275_open (alias->path, &ihandle)) -+ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle); -+ -+ if (! ihandle) - { - grub_free (buf); - grub_free (table); -@@ -495,7 +499,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) - last_ihandle = 0; - last_devpath = NULL; - -- grub_ieee1275_open (op->open_path, &last_ihandle); -+ RETRY_IEEE1275_OFDISK_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; -@@ -571,7 +575,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) - last_ihandle = 0; - last_devpath = NULL; - -- grub_ieee1275_open (disk->data, &last_ihandle); -+ RETRY_IEEE1275_OFDISK_OPEN(disk->data, &last_ihandle); - if (! last_ihandle) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); - last_devpath = disk->data; -@@ -598,12 +602,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, - return err; - grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, - &actual); -- if (actual != (grub_ssize_t) (size << disk->log_sector_size)) -+ int i = 0; -+ while(actual != (grub_ssize_t) (size << disk->log_sector_size)){ -+ if (i>MAX_RETRIES){ - return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx " - "from `%s'"), - (unsigned long long) sector, - disk->name); -+ } -+ last_devpath = NULL; -+ err = grub_ofdisk_prepare (disk, sector); -+ if (err) -+ return err; - -+ grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, -+ &actual); -+ i++; -+ } - return 0; - } - -diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h -index 2f69e3f191..7d2d540930 100644 ---- a/include/grub/ieee1275/ofdisk.h -+++ b/include/grub/ieee1275/ofdisk.h -@@ -22,4 +22,12 @@ - extern void grub_ofdisk_init (void); - extern void grub_ofdisk_fini (void); - -+#define MAX_RETRIES 20 -+ -+ -+#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \ -+ if(!grub_ieee1275_open(device, last_ihandle)) \ -+ break; \ -+ grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); } -+ - #endif /* ! GRUB_INIT_HEADER */ diff --git a/0182-Allow-chainloading-EFI-apps-from-loop-mounts.patch b/0182-Allow-chainloading-EFI-apps-from-loop-mounts.patch deleted file mode 100644 index c3101e1..0000000 --- a/0182-Allow-chainloading-EFI-apps-from-loop-mounts.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dimitri John Ledkov -Date: Fri, 11 Jun 2021 13:51:20 +0200 -Subject: [PATCH] Allow chainloading EFI apps from loop mounts. - -Signed-off-by: Dimitri John Ledkov -Signed-off-by: Robbie Harwood ---- - grub-core/disk/loopback.c | 9 +-------- - grub-core/loader/efi/chainloader.c | 23 +++++++++++++++++++++++ - include/grub/loopback.h | 30 ++++++++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 8 deletions(-) - create mode 100644 include/grub/loopback.h - -diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c -index 41bebd14fe..99f47924ec 100644 ---- a/grub-core/disk/loopback.c -+++ b/grub-core/disk/loopback.c -@@ -21,20 +21,13 @@ - #include - #include - #include -+#include - #include - #include - #include - - GRUB_MOD_LICENSE ("GPLv3+"); - --struct grub_loopback --{ -- char *devname; -- grub_file_t file; -- struct grub_loopback *next; -- unsigned long id; --}; -- - static struct grub_loopback *loopback_list; - static unsigned long last_id = 0; - -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index d41e8ea14a..3af6b12292 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -901,6 +902,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - grub_efi_status_t status; - grub_efi_boot_services_t *b; - grub_device_t dev = 0; -+ grub_device_t orig_dev = 0; - grub_efi_device_path_t *dp = 0; - char *filename; - void *boot_image = 0; -@@ -958,6 +960,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - if (! dev) - goto fail; - -+ /* if device is loopback, use underlying dev */ -+ if (dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID) -+ { -+ struct grub_loopback *d; -+ orig_dev = dev; -+ d = dev->disk->data; -+ dev = d->file->device; -+ } -+ - if (dev->disk) - dev_handle = grub_efidisk_get_device_handle (dev->disk); - else if (dev->net && dev->net->server) -@@ -1065,6 +1076,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - } - #endif - -+ if (orig_dev) -+ { -+ dev = orig_dev; -+ orig_dev = 0; -+ } -+ - rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize); - grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); - if (rc > 0) -@@ -1087,6 +1104,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - // -1 fall-through to fail - - fail: -+ if (orig_dev) -+ { -+ dev = orig_dev; -+ orig_dev = 0; -+ } -+ - if (dev) - grub_device_close (dev); - -diff --git a/include/grub/loopback.h b/include/grub/loopback.h -new file mode 100644 -index 0000000000..3b9a9e32e8 ---- /dev/null -+++ b/include/grub/loopback.h -@@ -0,0 +1,30 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2019 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_LOOPBACK_HEADER -+#define GRUB_LOOPBACK_HEADER 1 -+ -+struct grub_loopback -+{ -+ char *devname; -+ grub_file_t file; -+ struct grub_loopback *next; -+ unsigned long id; -+}; -+ -+#endif /* ! GRUB_LOOPBACK_HEADER */ diff --git a/0182-efinet-Add-DHCP-proxy-support.patch b/0182-efinet-Add-DHCP-proxy-support.patch new file mode 100644 index 0000000..eed2dbb --- /dev/null +++ b/0182-efinet-Add-DHCP-proxy-support.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ian Page Hands +Date: Tue, 8 Jun 2021 13:48:56 -0400 +Subject: [PATCH] efinet: Add DHCP proxy support + +If a proxyDHCP configuration is used, the server name, server IP and boot +file values should be taken from the DHCP proxy offer instead of the DHCP +server ack packet. Currently that case is not handled, add support for it. + +Signed-off-by: Ian Page Hands +Signed-off-by: Robbie Harwood +--- + grub-core/net/drivers/efi/efinet.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index e11d759f19..1a24f38a21 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -850,10 +850,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + else + { + grub_dprintf ("efinet", "using ipv4 and dhcp\n"); ++ ++ struct grub_net_bootp_packet *dhcp_ack = &pxe_mode->dhcp_ack; ++ ++ if (pxe_mode->proxy_offer_received) ++ { ++ grub_dprintf ("efinet", "proxy offer receive"); ++ struct grub_net_bootp_packet *proxy_offer = &pxe_mode->proxy_offer; ++ ++ if (proxy_offer && dhcp_ack->boot_file[0] == '\0') ++ { ++ grub_dprintf ("efinet", "setting values from proxy offer"); ++ /* Here we got a proxy offer and the dhcp_ack has a nil boot_file ++ * Copy the proxy DHCP offer details into the bootp_packet we are ++ * sending forward as they are the deatils we need. ++ */ ++ *dhcp_ack->server_name = *proxy_offer->server_name; ++ *dhcp_ack->boot_file = *proxy_offer->boot_file; ++ dhcp_ack->server_ip = proxy_offer->server_ip; ++ } ++ } ++ + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) +- packet_buf, +- packet_bufsz, ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), + 1, device, path); + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + } diff --git a/0183-efinet-Add-DHCP-proxy-support.patch b/0183-efinet-Add-DHCP-proxy-support.patch deleted file mode 100644 index eed2dbb..0000000 --- a/0183-efinet-Add-DHCP-proxy-support.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ian Page Hands -Date: Tue, 8 Jun 2021 13:48:56 -0400 -Subject: [PATCH] efinet: Add DHCP proxy support - -If a proxyDHCP configuration is used, the server name, server IP and boot -file values should be taken from the DHCP proxy offer instead of the DHCP -server ack packet. Currently that case is not handled, add support for it. - -Signed-off-by: Ian Page Hands -Signed-off-by: Robbie Harwood ---- - grub-core/net/drivers/efi/efinet.c | 25 +++++++++++++++++++++++-- - 1 file changed, 23 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c -index e11d759f19..1a24f38a21 100644 ---- a/grub-core/net/drivers/efi/efinet.c -+++ b/grub-core/net/drivers/efi/efinet.c -@@ -850,10 +850,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, - else - { - grub_dprintf ("efinet", "using ipv4 and dhcp\n"); -+ -+ struct grub_net_bootp_packet *dhcp_ack = &pxe_mode->dhcp_ack; -+ -+ if (pxe_mode->proxy_offer_received) -+ { -+ grub_dprintf ("efinet", "proxy offer receive"); -+ struct grub_net_bootp_packet *proxy_offer = &pxe_mode->proxy_offer; -+ -+ if (proxy_offer && dhcp_ack->boot_file[0] == '\0') -+ { -+ grub_dprintf ("efinet", "setting values from proxy offer"); -+ /* Here we got a proxy offer and the dhcp_ack has a nil boot_file -+ * Copy the proxy DHCP offer details into the bootp_packet we are -+ * sending forward as they are the deatils we need. -+ */ -+ *dhcp_ack->server_name = *proxy_offer->server_name; -+ *dhcp_ack->boot_file = *proxy_offer->boot_file; -+ dhcp_ack->server_ip = proxy_offer->server_ip; -+ } -+ } -+ - grub_net_configure_by_dhcp_ack (card->name, card, 0, - (struct grub_net_bootp_packet *) -- packet_buf, -- packet_bufsz, -+ &pxe_mode->dhcp_ack, -+ sizeof (pxe_mode->dhcp_ack), - 1, device, path); - grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); - } diff --git a/0183-fs-ext2-Ignore-checksum-seed-incompat-feature.patch b/0183-fs-ext2-Ignore-checksum-seed-incompat-feature.patch new file mode 100644 index 0000000..3d7c641 --- /dev/null +++ b/0183-fs-ext2-Ignore-checksum-seed-incompat-feature.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 11 Jun 2021 00:01:29 +0200 +Subject: [PATCH] fs/ext2: Ignore checksum seed incompat feature + +This incompat feature is used to denote that the filesystem stored its +metadata checksum seed in the superblock. This is used to allow tune2fs +to change the UUID on a mounted metadata_csum filesystem without having +to rewrite all the disk metadata. + +But GRUB doesn't use the metadata checksum in anyway, so can just ignore +this feature if is enabled. This is consistent with GRUB filesystem code +in general which just does a best effort to access the filesystem's data. + +It may be removed from the ignored list in the future if supports to do +metadata checksumming verification is added to the read-only FS driver. + +Suggested-by: Eric Sandeen +Suggested-by: Lukas Czerner +Signed-off-by: Javier Martinez Canillas +--- + grub-core/fs/ext2.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c +index e7dd78e663..731d346f88 100644 +--- a/grub-core/fs/ext2.c ++++ b/grub-core/fs/ext2.c +@@ -103,6 +103,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 + #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 + #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 ++#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 + #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 + + /* The set of back-incompatible features this driver DOES support. Add (OR) +@@ -123,9 +124,16 @@ GRUB_MOD_LICENSE ("GPLv3+"); + * mmp: Not really back-incompatible - was added as such to + * avoid multiple read-write mounts. Safe to ignore for this + * RO driver. ++ * checksum seed: Not really back-incompatible - was added to allow tools ++ * such as tune2fs to change the UUID on a mounted metadata ++ * checksummed filesystem. Safe to ignore for now since the ++ * driver doesn't support checksum verification. But it must ++ * be removed from this list if that support is added later. ++ * + */ + #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \ +- | EXT4_FEATURE_INCOMPAT_MMP) ++ | EXT4_FEATURE_INCOMPAT_MMP \ ++ | EXT4_FEATURE_INCOMPAT_CSUM_SEED) + + + #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U diff --git a/0184-Don-t-update-the-cmdline-when-generating-legacy-menu.patch b/0184-Don-t-update-the-cmdline-when-generating-legacy-menu.patch new file mode 100644 index 0000000..b2783d1 --- /dev/null +++ b/0184-Don-t-update-the-cmdline-when-generating-legacy-menu.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 17 Jun 2021 14:31:42 +0200 +Subject: [PATCH] Don't update the cmdline when generating legacy menuentry + commands + +On OPAL ppc64le machines with an old petitboot version that doesn't have +support to parse BLS snippets, the grub2-mkconfig script is executed to +generate menuentry commands from the BLS snippets. + +In this case, the script is executed with the --no-grubenv-update option +that indicates that no side effects should happen when running the script. + +But the options field in the BLS snippets are updated regardless, only do +the update if --no-grubenv-update was not used. + +Signed-off-by: Javier Martinez Canillas +--- + util/grub.d/10_linux.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index e490e1a43a..865af3d6c4 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -256,7 +256,9 @@ if [ -z "\${kernelopts}" ]; then + fi + EOF + +- update_bls_cmdline ++ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ++ update_bls_cmdline ++ fi + + if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then + populate_menu diff --git a/0184-fs-ext2-Ignore-checksum-seed-incompat-feature.patch b/0184-fs-ext2-Ignore-checksum-seed-incompat-feature.patch deleted file mode 100644 index 3d7c641..0000000 --- a/0184-fs-ext2-Ignore-checksum-seed-incompat-feature.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Fri, 11 Jun 2021 00:01:29 +0200 -Subject: [PATCH] fs/ext2: Ignore checksum seed incompat feature - -This incompat feature is used to denote that the filesystem stored its -metadata checksum seed in the superblock. This is used to allow tune2fs -to change the UUID on a mounted metadata_csum filesystem without having -to rewrite all the disk metadata. - -But GRUB doesn't use the metadata checksum in anyway, so can just ignore -this feature if is enabled. This is consistent with GRUB filesystem code -in general which just does a best effort to access the filesystem's data. - -It may be removed from the ignored list in the future if supports to do -metadata checksumming verification is added to the read-only FS driver. - -Suggested-by: Eric Sandeen -Suggested-by: Lukas Czerner -Signed-off-by: Javier Martinez Canillas ---- - grub-core/fs/ext2.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c -index e7dd78e663..731d346f88 100644 ---- a/grub-core/fs/ext2.c -+++ b/grub-core/fs/ext2.c -@@ -103,6 +103,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); - #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 - #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 - #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 -+#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 - #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 - - /* The set of back-incompatible features this driver DOES support. Add (OR) -@@ -123,9 +124,16 @@ GRUB_MOD_LICENSE ("GPLv3+"); - * mmp: Not really back-incompatible - was added as such to - * avoid multiple read-write mounts. Safe to ignore for this - * RO driver. -+ * checksum seed: Not really back-incompatible - was added to allow tools -+ * such as tune2fs to change the UUID on a mounted metadata -+ * checksummed filesystem. Safe to ignore for now since the -+ * driver doesn't support checksum verification. But it must -+ * be removed from this list if that support is added later. -+ * - */ - #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \ -- | EXT4_FEATURE_INCOMPAT_MMP) -+ | EXT4_FEATURE_INCOMPAT_MMP \ -+ | EXT4_FEATURE_INCOMPAT_CSUM_SEED) - - - #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U diff --git a/0185-Don-t-update-the-cmdline-when-generating-legacy-menu.patch b/0185-Don-t-update-the-cmdline-when-generating-legacy-menu.patch deleted file mode 100644 index 1982847..0000000 --- a/0185-Don-t-update-the-cmdline-when-generating-legacy-menu.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Thu, 17 Jun 2021 14:31:42 +0200 -Subject: [PATCH] Don't update the cmdline when generating legacy menuentry - commands - -On OPAL ppc64le machines with an old petitboot version that doesn't have -support to parse BLS snippets, the grub2-mkconfig script is executed to -generate menuentry commands from the BLS snippets. - -In this case, the script is executed with the --no-grubenv-update option -that indicates that no side effects should happen when running the script. - -But the options field in the BLS snippets are updated regardless, only do -the update if --no-grubenv-update was not used. - -Signed-off-by: Javier Martinez Canillas ---- - util/grub.d/10_linux.in | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index c02c1f0820..6af84b44e1 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -256,7 +256,9 @@ if [ -z "\${kernelopts}" ]; then - fi - EOF - -- update_bls_cmdline -+ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then -+ update_bls_cmdline -+ fi - - if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then - populate_menu diff --git a/0185-Suppress-gettext-error-message.patch b/0185-Suppress-gettext-error-message.patch new file mode 100644 index 0000000..64b219a --- /dev/null +++ b/0185-Suppress-gettext-error-message.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Tue, 29 Jun 2021 13:17:42 +0200 +Subject: [PATCH] Suppress gettext error message + +Colin Watson's patch from comment #11 on the upstream bug: +https://savannah.gnu.org/bugs/?35880#comment11 + +Resolves: rhbz#1592124 + +Signed-off-by: Paulo Flabiano Smorigo +--- + grub-core/gettext/gettext.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 4d02e62c10..7ec81ca0b4 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -424,6 +424,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx, + grub_free (lang); + } + ++ /* If no translations are available, fall back to untranslated text. */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ + if (locale[0] == 'e' && locale[1] == 'n' + && (locale[2] == '\0' || locale[2] == '_')) + grub_errno = err = GRUB_ERR_NONE; diff --git a/0186-Suppress-gettext-error-message.patch b/0186-Suppress-gettext-error-message.patch deleted file mode 100644 index 64b219a..0000000 --- a/0186-Suppress-gettext-error-message.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Paulo Flabiano Smorigo -Date: Tue, 29 Jun 2021 13:17:42 +0200 -Subject: [PATCH] Suppress gettext error message - -Colin Watson's patch from comment #11 on the upstream bug: -https://savannah.gnu.org/bugs/?35880#comment11 - -Resolves: rhbz#1592124 - -Signed-off-by: Paulo Flabiano Smorigo ---- - grub-core/gettext/gettext.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c -index 4d02e62c10..7ec81ca0b4 100644 ---- a/grub-core/gettext/gettext.c -+++ b/grub-core/gettext/gettext.c -@@ -424,6 +424,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx, - grub_free (lang); - } - -+ /* If no translations are available, fall back to untranslated text. */ -+ if (err == GRUB_ERR_FILE_NOT_FOUND) -+ { -+ grub_errno = GRUB_ERR_NONE; -+ return 0; -+ } -+ - if (locale[0] == 'e' && locale[1] == 'n' - && (locale[2] == '\0' || locale[2] == '_')) - grub_errno = err = GRUB_ERR_NONE; diff --git a/0186-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch b/0186-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch new file mode 100644 index 0000000..b5d5e5c --- /dev/null +++ b/0186-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 5 Jul 2021 18:24:22 +0200 +Subject: [PATCH] grub-set-password: Always use /boot/grub2/user.cfg as + password default + +The GRUB configuration file is always placed in /boot/grub2/ now, even for +EFI. But the tool is still creating the user.cfg in the ESP and not there. + +Resolves: rhbz#1955294 + +Signed-off-by: Javier Martinez Canillas +--- + util/grub-set-password.in | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git a/util/grub-set-password.in b/util/grub-set-password.in +index c0b5ebbfdc..d8005e5a14 100644 +--- a/util/grub-set-password.in ++++ b/util/grub-set-password.in +@@ -1,11 +1,6 @@ + #!/bin/sh -e + +-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') +-if [ -d /sys/firmware/efi/efivars/ ]; then +- grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` +-else +- grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` +-fi ++grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` + + PACKAGE_VERSION="@PACKAGE_VERSION@" + PACKAGE_NAME="@PACKAGE_NAME@" +@@ -116,8 +111,6 @@ if [ -z "${MYPASS}" ]; then + exit 1 + fi + +-# on the ESP, these will fail to set the permissions, but it's okay because +-# the directory is protected. + install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : + chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : + echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg" diff --git a/0187-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch b/0187-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch deleted file mode 100644 index b5d5e5c..0000000 --- a/0187-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 5 Jul 2021 18:24:22 +0200 -Subject: [PATCH] grub-set-password: Always use /boot/grub2/user.cfg as - password default - -The GRUB configuration file is always placed in /boot/grub2/ now, even for -EFI. But the tool is still creating the user.cfg in the ESP and not there. - -Resolves: rhbz#1955294 - -Signed-off-by: Javier Martinez Canillas ---- - util/grub-set-password.in | 9 +-------- - 1 file changed, 1 insertion(+), 8 deletions(-) - -diff --git a/util/grub-set-password.in b/util/grub-set-password.in -index c0b5ebbfdc..d8005e5a14 100644 ---- a/util/grub-set-password.in -+++ b/util/grub-set-password.in -@@ -1,11 +1,6 @@ - #!/bin/sh -e - --EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') --if [ -d /sys/firmware/efi/efivars/ ]; then -- grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` --else -- grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` --fi -+grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` - - PACKAGE_VERSION="@PACKAGE_VERSION@" - PACKAGE_NAME="@PACKAGE_NAME@" -@@ -116,8 +111,6 @@ if [ -z "${MYPASS}" ]; then - exit 1 - fi - --# on the ESP, these will fail to set the permissions, but it's okay because --# the directory is protected. - install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : - chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : - echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg" diff --git a/0187-templates-Check-for-EFI-at-runtime-instead-of-config.patch b/0187-templates-Check-for-EFI-at-runtime-instead-of-config.patch new file mode 100644 index 0000000..265b967 --- /dev/null +++ b/0187-templates-Check-for-EFI-at-runtime-instead-of-config.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 6 Jul 2021 00:38:40 +0200 +Subject: [PATCH] templates: Check for EFI at runtime instead of config + generation time + +The 30_uefi-firmware template checks if an OsIndicationsSupported UEFI var +exists and EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, to decide whether +a "fwsetup" menu entry would be added or not to the GRUB menu. + +But this has the problem that it will only work if the configuration file +was created on an UEFI machine that supports booting to a firmware UI. + +This for example doesn't support creating GRUB config files when executing +on systems that support both UEFI and legacy BIOS booting. Since creating +the config file from legacy BIOS wouldn't allow to access the firmware UI. + +To prevent this, make the template to unconditionally create the grub.cfg +snippet but check at runtime if was booted through UEFI to decide if this +entry should be added. That way it won't be added when booting with BIOS. + +There's no need to check if EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, +since that's already done by the "fwsetup" command when is executed. + +Resolves: rhbz#1823864 + +Signed-off-by: Javier Martinez Canillas +--- + util/grub.d/30_uefi-firmware.in | 21 ++++++++------------- + 1 file changed, 8 insertions(+), 13 deletions(-) + +diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in +index d344d3883d..b6041b55e2 100644 +--- a/util/grub.d/30_uefi-firmware.in ++++ b/util/grub.d/30_uefi-firmware.in +@@ -26,19 +26,14 @@ export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + +-EFI_VARS_DIR=/sys/firmware/efi/efivars +-EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c +-OS_INDICATIONS="$EFI_VARS_DIR/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE" ++LABEL="UEFI Firmware Settings" + +-if [ -e "$OS_INDICATIONS" ] && \ +- [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') & 1 ))" = 1 ]; then +- LABEL="UEFI Firmware Settings" ++gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 + +- gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 +- +- cat << EOF +-menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { +- fwsetup +-} +-EOF ++cat << EOF ++if [ "\$grub_platform" = "efi" ]; then ++ menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { ++ fwsetup ++ } + fi ++EOF diff --git a/0188-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch b/0188-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch new file mode 100644 index 0000000..3b1a219 --- /dev/null +++ b/0188-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 6 Jul 2021 01:10:18 +0200 +Subject: [PATCH] efi: Print an error if boot to firmware setup is not + supported + +The "fwsetup" command is only registered if the firmware supports booting +to the firmware setup UI. But it could be possible that the GRUB config +already contains a "fwsetup" entry, because it was generated in a machine +that has support for this feature. + +To prevent users getting a "can't find command `fwsetup`" error if it is +not supported by the firmware, let's just always register the command but +print a more accurate message if the firmware doesn't support this option. + +Resolves: rhbz#1823864 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/commands/efi/efifwsetup.c | 43 ++++++++++++++++++++----------------- + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c +index eaca032838..328c45e82e 100644 +--- a/grub-core/commands/efi/efifwsetup.c ++++ b/grub-core/commands/efi/efifwsetup.c +@@ -27,6 +27,25 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + ++static grub_efi_boolean_t ++efifwsetup_is_supported (void) ++{ ++ grub_efi_uint64_t *os_indications_supported = NULL; ++ grub_size_t oi_size = 0; ++ grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; ++ ++ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, ++ (void **) &os_indications_supported); ++ ++ if (!os_indications_supported) ++ return 0; ++ ++ if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI) ++ return 1; ++ ++ return 0; ++} ++ + static grub_err_t + grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), +@@ -38,6 +57,10 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + grub_size_t oi_size; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + ++ if (!efifwsetup_is_supported ()) ++ return grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("Reboot to firmware setup is not supported")); ++ + grub_efi_get_variable ("OsIndications", &global, &oi_size, + (void **) &old_os_indications); + +@@ -56,28 +79,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + + static grub_command_t cmd = NULL; + +-static grub_efi_boolean_t +-efifwsetup_is_supported (void) +-{ +- grub_efi_uint64_t *os_indications_supported = NULL; +- grub_size_t oi_size = 0; +- grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; +- +- grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, +- (void **) &os_indications_supported); +- +- if (!os_indications_supported) +- return 0; +- +- if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI) +- return 1; +- +- return 0; +-} +- + GRUB_MOD_INIT (efifwsetup) + { +- if (efifwsetup_is_supported ()) + cmd = grub_register_command ("fwsetup", grub_cmd_fwsetup, NULL, + N_("Reboot into firmware setup menu.")); + diff --git a/0188-templates-Check-for-EFI-at-runtime-instead-of-config.patch b/0188-templates-Check-for-EFI-at-runtime-instead-of-config.patch deleted file mode 100644 index 265b967..0000000 --- a/0188-templates-Check-for-EFI-at-runtime-instead-of-config.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 6 Jul 2021 00:38:40 +0200 -Subject: [PATCH] templates: Check for EFI at runtime instead of config - generation time - -The 30_uefi-firmware template checks if an OsIndicationsSupported UEFI var -exists and EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, to decide whether -a "fwsetup" menu entry would be added or not to the GRUB menu. - -But this has the problem that it will only work if the configuration file -was created on an UEFI machine that supports booting to a firmware UI. - -This for example doesn't support creating GRUB config files when executing -on systems that support both UEFI and legacy BIOS booting. Since creating -the config file from legacy BIOS wouldn't allow to access the firmware UI. - -To prevent this, make the template to unconditionally create the grub.cfg -snippet but check at runtime if was booted through UEFI to decide if this -entry should be added. That way it won't be added when booting with BIOS. - -There's no need to check if EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, -since that's already done by the "fwsetup" command when is executed. - -Resolves: rhbz#1823864 - -Signed-off-by: Javier Martinez Canillas ---- - util/grub.d/30_uefi-firmware.in | 21 ++++++++------------- - 1 file changed, 8 insertions(+), 13 deletions(-) - -diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in -index d344d3883d..b6041b55e2 100644 ---- a/util/grub.d/30_uefi-firmware.in -+++ b/util/grub.d/30_uefi-firmware.in -@@ -26,19 +26,14 @@ export TEXTDOMAINDIR="@localedir@" - - . "$pkgdatadir/grub-mkconfig_lib" - --EFI_VARS_DIR=/sys/firmware/efi/efivars --EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c --OS_INDICATIONS="$EFI_VARS_DIR/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE" -+LABEL="UEFI Firmware Settings" - --if [ -e "$OS_INDICATIONS" ] && \ -- [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') & 1 ))" = 1 ]; then -- LABEL="UEFI Firmware Settings" -+gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 - -- gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 -- -- cat << EOF --menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { -- fwsetup --} --EOF -+cat << EOF -+if [ "\$grub_platform" = "efi" ]; then -+ menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { -+ fwsetup -+ } - fi -+EOF diff --git a/0189-arm64-Fix-EFI-loader-kernel-image-allocation.patch b/0189-arm64-Fix-EFI-loader-kernel-image-allocation.patch new file mode 100644 index 0000000..cc5458c --- /dev/null +++ b/0189-arm64-Fix-EFI-loader-kernel-image-allocation.patch @@ -0,0 +1,218 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Herrenschmidt +Date: Mon, 2 Aug 2021 23:10:01 +1000 +Subject: [PATCH] arm64: Fix EFI loader kernel image allocation + +We are currently allocating just enough memory for the file size, +which means that the kernel BSS is in limbo (and not even zeroed). + +We are also not honoring the alignment specified in the image +PE header. + +This makes us use the PE optional header in which the kernel puts the +actual size it needs, including BSS, and make sure we clear it, and +honors the specified alignment for the image. + +Signed-off-by: Benjamin Herrenschmidt +[pjones: arm: check for the PE magic for the compiled arch] +Signed-off-by: Peter Jones +Signed-off-by: Robbie Harwood +--- + grub-core/loader/arm64/linux.c | 100 +++++++++++++++++++++++++++-------------- + include/grub/arm/linux.h | 1 + + include/grub/arm64/linux.h | 1 + + 3 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 47f8cf0d84..f18d90bd74 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -41,6 +41,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; + static int loaded; + ++static void *kernel_alloc_addr; ++static grub_uint32_t kernel_alloc_pages; + static void *kernel_addr; + static grub_uint64_t kernel_size; + static grub_uint32_t handover_offset; +@@ -204,9 +206,8 @@ grub_linux_unload (void) + GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); + initrd_start = initrd_end = 0; + grub_free (linux_args); +- if (kernel_addr) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + grub_fdt_unload (); + return GRUB_ERR_NONE; + } +@@ -311,14 +312,35 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + ++static grub_err_t ++parse_pe_header (void *kernel, grub_uint64_t *total_size, ++ grub_uint32_t *entry_offset, ++ grub_uint32_t *alignment) ++{ ++ struct linux_arch_kernel_header *lh = kernel; ++ struct grub_armxx_linux_pe_header *pe; ++ ++ pe = (void *)((unsigned long)kernel + lh->hdr_offset); ++ ++ if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC) ++ return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic"); ++ ++ *total_size = pe->opt.image_size; ++ *entry_offset = pe->opt.entry_addr; ++ *alignment = pe->opt.section_alignment; ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- struct linux_arch_kernel_header lh; +- struct grub_armxx_linux_pe_header *pe; + grub_err_t err; ++ grub_off_t filelen; ++ grub_uint32_t align; ++ void *kernel = NULL; + int rc; + + grub_dl_ref (my_mod); +@@ -333,40 +355,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (!file) + goto fail; + +- kernel_size = grub_file_size (file); +- +- if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) +- return grub_errno; +- +- if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE) +- goto fail; +- +- grub_loader_unset(); +- +- grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); +- kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- grub_dprintf ("linux", "kernel numpages: %lld\n", +- (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- if (!kernel_addr) ++ filelen = grub_file_size (file); ++ kernel = grub_malloc(filelen); ++ if (!kernel) + { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer")); + goto fail; + } + +- grub_file_seek (file, 0); +- if (grub_file_read (file, kernel_addr, kernel_size) +- < (grub_int64_t) kernel_size) ++ if (grub_file_read (file, kernel, filelen) < (grub_ssize_t)filelen) + { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), ++ argv[0]); + goto fail; + } + +- grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); +- + if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { +- rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); ++ rc = grub_linuxefi_secure_validate (kernel, filelen); + if (rc <= 0) + { + grub_error (GRUB_ERR_INVALID_COMMAND, +@@ -375,8 +381,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + } + +- pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); +- handover_offset = pe->opt.entry_addr; ++ if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) ++ goto fail; ++ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) ++ goto fail; ++ grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); ++ grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); ++ grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); ++ ++ grub_loader_unset(); ++ ++ kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); ++ kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages); ++ grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages); ++ if (!kernel_alloc_addr) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); ++ ++ grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); ++ grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size)); ++ if (kernel_size > filelen) ++ grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen); ++ grub_free(kernel); ++ kernel = NULL; + + cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); + linux_args = grub_malloc (cmdline_size); +@@ -400,6 +430,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + fail: ++ if (kernel) ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + +@@ -412,9 +445,8 @@ fail: + if (linux_args && !loaded) + grub_free (linux_args); + +- if (kernel_addr && !loaded) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr && !loaded) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + + return grub_errno; + } +diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h +index b582f67f66..966a5074f5 100644 +--- a/include/grub/arm/linux.h ++++ b/include/grub/arm/linux.h +@@ -44,6 +44,7 @@ struct grub_arm_linux_pe_header + + #if defined(__arm__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC + # define linux_arch_kernel_header linux_arm_kernel_header + # define grub_armxx_linux_pe_header grub_arm_linux_pe_header + #endif +diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h +index ea030312df..422bf2bf24 100644 +--- a/include/grub/arm64/linux.h ++++ b/include/grub/arm64/linux.h +@@ -48,6 +48,7 @@ struct grub_arm64_linux_pe_header + + #if defined(__aarch64__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC + # define linux_arch_kernel_header linux_arm64_kernel_header + # define grub_armxx_linux_pe_header grub_arm64_linux_pe_header + #endif diff --git a/0189-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch b/0189-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch deleted file mode 100644 index 3b1a219..0000000 --- a/0189-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 6 Jul 2021 01:10:18 +0200 -Subject: [PATCH] efi: Print an error if boot to firmware setup is not - supported - -The "fwsetup" command is only registered if the firmware supports booting -to the firmware setup UI. But it could be possible that the GRUB config -already contains a "fwsetup" entry, because it was generated in a machine -that has support for this feature. - -To prevent users getting a "can't find command `fwsetup`" error if it is -not supported by the firmware, let's just always register the command but -print a more accurate message if the firmware doesn't support this option. - -Resolves: rhbz#1823864 - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/commands/efi/efifwsetup.c | 43 ++++++++++++++++++++----------------- - 1 file changed, 23 insertions(+), 20 deletions(-) - -diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c -index eaca032838..328c45e82e 100644 ---- a/grub-core/commands/efi/efifwsetup.c -+++ b/grub-core/commands/efi/efifwsetup.c -@@ -27,6 +27,25 @@ - - GRUB_MOD_LICENSE ("GPLv3+"); - -+static grub_efi_boolean_t -+efifwsetup_is_supported (void) -+{ -+ grub_efi_uint64_t *os_indications_supported = NULL; -+ grub_size_t oi_size = 0; -+ grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; -+ -+ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, -+ (void **) &os_indications_supported); -+ -+ if (!os_indications_supported) -+ return 0; -+ -+ if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI) -+ return 1; -+ -+ return 0; -+} -+ - static grub_err_t - grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), -@@ -38,6 +57,10 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), - grub_size_t oi_size; - grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; - -+ if (!efifwsetup_is_supported ()) -+ return grub_error (GRUB_ERR_INVALID_COMMAND, -+ N_("Reboot to firmware setup is not supported")); -+ - grub_efi_get_variable ("OsIndications", &global, &oi_size, - (void **) &old_os_indications); - -@@ -56,28 +79,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), - - static grub_command_t cmd = NULL; - --static grub_efi_boolean_t --efifwsetup_is_supported (void) --{ -- grub_efi_uint64_t *os_indications_supported = NULL; -- grub_size_t oi_size = 0; -- grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; -- -- grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, -- (void **) &os_indications_supported); -- -- if (!os_indications_supported) -- return 0; -- -- if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI) -- return 1; -- -- return 0; --} -- - GRUB_MOD_INIT (efifwsetup) - { -- if (efifwsetup_is_supported ()) - cmd = grub_register_command ("fwsetup", grub_cmd_fwsetup, NULL, - N_("Reboot into firmware setup menu.")); - diff --git a/0190-arm64-Fix-EFI-loader-kernel-image-allocation.patch b/0190-arm64-Fix-EFI-loader-kernel-image-allocation.patch deleted file mode 100644 index cc5458c..0000000 --- a/0190-arm64-Fix-EFI-loader-kernel-image-allocation.patch +++ /dev/null @@ -1,218 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Benjamin Herrenschmidt -Date: Mon, 2 Aug 2021 23:10:01 +1000 -Subject: [PATCH] arm64: Fix EFI loader kernel image allocation - -We are currently allocating just enough memory for the file size, -which means that the kernel BSS is in limbo (and not even zeroed). - -We are also not honoring the alignment specified in the image -PE header. - -This makes us use the PE optional header in which the kernel puts the -actual size it needs, including BSS, and make sure we clear it, and -honors the specified alignment for the image. - -Signed-off-by: Benjamin Herrenschmidt -[pjones: arm: check for the PE magic for the compiled arch] -Signed-off-by: Peter Jones -Signed-off-by: Robbie Harwood ---- - grub-core/loader/arm64/linux.c | 100 +++++++++++++++++++++++++++-------------- - include/grub/arm/linux.h | 1 + - include/grub/arm64/linux.h | 1 + - 3 files changed, 68 insertions(+), 34 deletions(-) - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index 47f8cf0d84..f18d90bd74 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -41,6 +41,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); - static grub_dl_t my_mod; - static int loaded; - -+static void *kernel_alloc_addr; -+static grub_uint32_t kernel_alloc_pages; - static void *kernel_addr; - static grub_uint64_t kernel_size; - static grub_uint32_t handover_offset; -@@ -204,9 +206,8 @@ grub_linux_unload (void) - GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); - initrd_start = initrd_end = 0; - grub_free (linux_args); -- if (kernel_addr) -- grub_efi_free_pages ((grub_addr_t) kernel_addr, -- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -+ if (kernel_alloc_addr) -+ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); - grub_fdt_unload (); - return GRUB_ERR_NONE; - } -@@ -311,14 +312,35 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - return grub_errno; - } - -+static grub_err_t -+parse_pe_header (void *kernel, grub_uint64_t *total_size, -+ grub_uint32_t *entry_offset, -+ grub_uint32_t *alignment) -+{ -+ struct linux_arch_kernel_header *lh = kernel; -+ struct grub_armxx_linux_pe_header *pe; -+ -+ pe = (void *)((unsigned long)kernel + lh->hdr_offset); -+ -+ if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC) -+ return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic"); -+ -+ *total_size = pe->opt.image_size; -+ *entry_offset = pe->opt.entry_addr; -+ *alignment = pe->opt.section_alignment; -+ -+ return GRUB_ERR_NONE; -+} -+ - static grub_err_t - grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) - { - grub_file_t file = 0; -- struct linux_arch_kernel_header lh; -- struct grub_armxx_linux_pe_header *pe; - grub_err_t err; -+ grub_off_t filelen; -+ grub_uint32_t align; -+ void *kernel = NULL; - int rc; - - grub_dl_ref (my_mod); -@@ -333,40 +355,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - if (!file) - goto fail; - -- kernel_size = grub_file_size (file); -- -- if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) -- return grub_errno; -- -- if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE) -- goto fail; -- -- grub_loader_unset(); -- -- grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); -- kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -- grub_dprintf ("linux", "kernel numpages: %lld\n", -- (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -- if (!kernel_addr) -+ filelen = grub_file_size (file); -+ kernel = grub_malloc(filelen); -+ if (!kernel) - { -- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer")); - goto fail; - } - -- grub_file_seek (file, 0); -- if (grub_file_read (file, kernel_addr, kernel_size) -- < (grub_int64_t) kernel_size) -+ if (grub_file_read (file, kernel, filelen) < (grub_ssize_t)filelen) - { -- if (!grub_errno) -- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); -+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), -+ argv[0]); - goto fail; - } - -- grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); -- - if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) - { -- rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); -+ rc = grub_linuxefi_secure_validate (kernel, filelen); - if (rc <= 0) - { - grub_error (GRUB_ERR_INVALID_COMMAND, -@@ -375,8 +381,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - } - -- pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); -- handover_offset = pe->opt.entry_addr; -+ if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) -+ goto fail; -+ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) -+ goto fail; -+ grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); -+ grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); -+ grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); -+ -+ grub_loader_unset(); -+ -+ kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); -+ kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages); -+ grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages); -+ if (!kernel_alloc_addr) -+ { -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); -+ goto fail; -+ } -+ kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); -+ -+ grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); -+ grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size)); -+ if (kernel_size > filelen) -+ grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen); -+ grub_free(kernel); -+ kernel = NULL; - - cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); - linux_args = grub_malloc (cmdline_size); -@@ -400,6 +430,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - - fail: -+ if (kernel) -+ grub_free (kernel); -+ - if (file) - grub_file_close (file); - -@@ -412,9 +445,8 @@ fail: - if (linux_args && !loaded) - grub_free (linux_args); - -- if (kernel_addr && !loaded) -- grub_efi_free_pages ((grub_addr_t) kernel_addr, -- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); -+ if (kernel_alloc_addr && !loaded) -+ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); - - return grub_errno; - } -diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h -index b582f67f66..966a5074f5 100644 ---- a/include/grub/arm/linux.h -+++ b/include/grub/arm/linux.h -@@ -44,6 +44,7 @@ struct grub_arm_linux_pe_header - - #if defined(__arm__) - # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE -+# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC - # define linux_arch_kernel_header linux_arm_kernel_header - # define grub_armxx_linux_pe_header grub_arm_linux_pe_header - #endif -diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h -index ea030312df..422bf2bf24 100644 ---- a/include/grub/arm64/linux.h -+++ b/include/grub/arm64/linux.h -@@ -48,6 +48,7 @@ struct grub_arm64_linux_pe_header - - #if defined(__aarch64__) - # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE -+# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC - # define linux_arch_kernel_header linux_arm64_kernel_header - # define grub_armxx_linux_pe_header grub_arm64_linux_pe_header - #endif diff --git a/0190-normal-main-Discover-the-device-to-read-the-config-f.patch b/0190-normal-main-Discover-the-device-to-read-the-config-f.patch new file mode 100644 index 0000000..2c9ca3a --- /dev/null +++ b/0190-normal-main-Discover-the-device-to-read-the-config-f.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 30 Aug 2021 12:31:18 +0200 +Subject: [PATCH] normal/main: Discover the device to read the config from as a + fallback + +The GRUB core.img is generated locally, when this is done the grub2-probe +tool figures out the device and partition that needs to be read to parse +the GRUB configuration file. + +But in some cases the core.img can't be generated on the host and instead +has to be done at package build time. For example, if needs to get signed +with a key that's only available on the package building infrastructure. + +If that's the case, the prefix variable won't have a device and partition +but only a directory path. So there's no way for GRUB to know from which +device has to read the configuration file. + +To allow GRUB to continue working on that scenario, fallback to iterating +over all the available devices, if reading the config failed when using +the prefix and fw_path variables. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/main.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 51 insertions(+), 7 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 7de9e4c36d..8f5fd81003 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -337,18 +337,13 @@ grub_enter_normal_mode (const char *config) + } + + static grub_err_t +-grub_try_normal (const char *variable) ++grub_try_normal_prefix (const char *prefix) + { + char *config; +- const char *prefix; + grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; + const char *net_search_cfg; + int disable_net_search = 0; + +- prefix = grub_env_get (variable); +- if (!prefix) +- return GRUB_ERR_FILE_NOT_FOUND; +- + net_search_cfg = grub_env_get ("feature_net_search_cfg"); + if (net_search_cfg && net_search_cfg[0] == 'n') + disable_net_search = 1; +@@ -362,7 +357,7 @@ grub_try_normal (const char *variable) + config = grub_malloc (config_len); + + if (! config) +- return GRUB_ERR_FILE_NOT_FOUND; ++ return err; + + grub_snprintf (config, config_len, "%s/grub.cfg", prefix); + err = grub_net_search_config_file (config); +@@ -391,6 +386,53 @@ grub_try_normal (const char *variable) + return err; + } + ++static int ++grub_try_normal_dev (const char *name, void *data) ++{ ++ grub_err_t err; ++ const char *prefix = grub_xasprintf ("(%s)%s", name, (char *)data); ++ ++ if (!prefix) ++ return 0; ++ ++ err = grub_try_normal_prefix (prefix); ++ if (err == GRUB_ERR_NONE) ++ return 1; ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_try_normal_discover (void) ++{ ++ char *prefix = grub_env_get ("prefix"); ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (!prefix) ++ return err; ++ ++ if (grub_device_iterate (grub_try_normal_dev, (void *)prefix)) ++ return GRUB_ERR_NONE; ++ ++ return err; ++} ++ ++static grub_err_t ++grub_try_normal (const char *variable) ++{ ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ const char *prefix; ++ ++ if (!variable) ++ return err; ++ ++ prefix = grub_env_get (variable); ++ if (!prefix) ++ return err; ++ ++ return grub_try_normal_prefix (prefix); ++} ++ + /* Enter normal mode from rescue mode. */ + static grub_err_t + grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), +@@ -405,6 +447,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + err = grub_try_normal ("fw_path"); + if (err == GRUB_ERR_FILE_NOT_FOUND) + err = grub_try_normal ("prefix"); ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_try_normal_discover (); + if (err == GRUB_ERR_FILE_NOT_FOUND) + grub_enter_normal_mode (0); + } diff --git a/0191-normal-main-Discover-the-device-to-read-the-config-f.patch b/0191-normal-main-Discover-the-device-to-read-the-config-f.patch deleted file mode 100644 index 2c9ca3a..0000000 --- a/0191-normal-main-Discover-the-device-to-read-the-config-f.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Mon, 30 Aug 2021 12:31:18 +0200 -Subject: [PATCH] normal/main: Discover the device to read the config from as a - fallback - -The GRUB core.img is generated locally, when this is done the grub2-probe -tool figures out the device and partition that needs to be read to parse -the GRUB configuration file. - -But in some cases the core.img can't be generated on the host and instead -has to be done at package build time. For example, if needs to get signed -with a key that's only available on the package building infrastructure. - -If that's the case, the prefix variable won't have a device and partition -but only a directory path. So there's no way for GRUB to know from which -device has to read the configuration file. - -To allow GRUB to continue working on that scenario, fallback to iterating -over all the available devices, if reading the config failed when using -the prefix and fw_path variables. - -Signed-off-by: Javier Martinez Canillas ---- - grub-core/normal/main.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 51 insertions(+), 7 deletions(-) - -diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c -index 7de9e4c36d..8f5fd81003 100644 ---- a/grub-core/normal/main.c -+++ b/grub-core/normal/main.c -@@ -337,18 +337,13 @@ grub_enter_normal_mode (const char *config) - } - - static grub_err_t --grub_try_normal (const char *variable) -+grub_try_normal_prefix (const char *prefix) - { - char *config; -- const char *prefix; - grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; - const char *net_search_cfg; - int disable_net_search = 0; - -- prefix = grub_env_get (variable); -- if (!prefix) -- return GRUB_ERR_FILE_NOT_FOUND; -- - net_search_cfg = grub_env_get ("feature_net_search_cfg"); - if (net_search_cfg && net_search_cfg[0] == 'n') - disable_net_search = 1; -@@ -362,7 +357,7 @@ grub_try_normal (const char *variable) - config = grub_malloc (config_len); - - if (! config) -- return GRUB_ERR_FILE_NOT_FOUND; -+ return err; - - grub_snprintf (config, config_len, "%s/grub.cfg", prefix); - err = grub_net_search_config_file (config); -@@ -391,6 +386,53 @@ grub_try_normal (const char *variable) - return err; - } - -+static int -+grub_try_normal_dev (const char *name, void *data) -+{ -+ grub_err_t err; -+ const char *prefix = grub_xasprintf ("(%s)%s", name, (char *)data); -+ -+ if (!prefix) -+ return 0; -+ -+ err = grub_try_normal_prefix (prefix); -+ if (err == GRUB_ERR_NONE) -+ return 1; -+ -+ return 0; -+} -+ -+static grub_err_t -+grub_try_normal_discover (void) -+{ -+ char *prefix = grub_env_get ("prefix"); -+ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; -+ -+ if (!prefix) -+ return err; -+ -+ if (grub_device_iterate (grub_try_normal_dev, (void *)prefix)) -+ return GRUB_ERR_NONE; -+ -+ return err; -+} -+ -+static grub_err_t -+grub_try_normal (const char *variable) -+{ -+ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; -+ const char *prefix; -+ -+ if (!variable) -+ return err; -+ -+ prefix = grub_env_get (variable); -+ if (!prefix) -+ return err; -+ -+ return grub_try_normal_prefix (prefix); -+} -+ - /* Enter normal mode from rescue mode. */ - static grub_err_t - grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), -@@ -405,6 +447,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), - err = grub_try_normal ("fw_path"); - if (err == GRUB_ERR_FILE_NOT_FOUND) - err = grub_try_normal ("prefix"); -+ if (err == GRUB_ERR_FILE_NOT_FOUND) -+ err = grub_try_normal_discover (); - if (err == GRUB_ERR_FILE_NOT_FOUND) - grub_enter_normal_mode (0); - } diff --git a/0191-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch b/0191-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch new file mode 100644 index 0000000..b9bc140 --- /dev/null +++ b/0191-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 19 Jul 2021 14:35:55 +1000 +Subject: [PATCH] powerpc: adjust setting of prefix for signed binary case + +On RHEL-signed powerpc grub, we sign a grub with -p /grub2 and expect +that there's a boot partition. + +Unfortunately grub_set_prefix_and_root tries to convert this to +($fwdevice)/grub2. This ends up being (ieee1275/disk)/grub2 and that +falls apart pretty quickly - there's no file-system on ieee1275/disk, +and it makes the search routine try things like +(ieee1275/disk,msdos2)(ieee1275/disk)/grub2 which also doesn't work. + +Detect if we would be about to create (ieee1275/disk)/path and don't: +preserve a prefix of /path instead and hope the search later finds us. + +Related: rhbz#1899864 + +Signed-off-by: Daniel Axtens +[rharwood@redhat.com: squash in fixup commit] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/main.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 44 insertions(+), 5 deletions(-) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index b573be6650..3fc3401472 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -216,13 +216,52 @@ grub_set_prefix_and_root (void) + if (device) + { + char *prefix_set; +- +- prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); +- if (prefix_set) ++ ++#ifdef __powerpc__ ++ /* We have to be careful here on powerpc-ieee1275 + signed grub. We ++ will have signed something with a prefix that doesn't have a device ++ because we cannot know in advance what partition we're on. ++ ++ We will have had !device earlier, so we will have set device=fwdevice ++ However, we want to make sure we do not end up setting prefix to be ++ ($fwdevice)/path, because we will then end up trying to boot or search ++ based on a prefix of (ieee1275/disk)/path, which will not work because ++ it's missing a partition. ++ ++ Also: ++ - You can end up with a device with an FS directly on it, without ++ a partition, e.g. ieee1275/cdrom. ++ ++ - powerpc-ieee1275 + grub-install sets e.g. prefix=(,gpt2)/path, ++ which will have now been extended to device=$fwdisk,partition ++ and path=/path ++ ++ - PowerVM will give us device names like ++ ieee1275//vdevice/v-scsi@3000006c/disk@8100000000000000 ++ and we don't want to try to encode some sort of truth table about ++ what sorts of paths represent disks with partition tables and those ++ without partition tables. ++ ++ So we act unless there is a comma in the device, which would indicate ++ a partition has already been specified. ++ ++ (If we only have a path, the code in normal to discover config files ++ will try both without partitions and then with any partitions so we ++ will cover both CDs and HDs.) ++ */ ++ if (grub_strchr (device, ',') == NULL) ++ grub_env_set ("prefix", path); ++ else ++#endif + { +- grub_env_set ("prefix", prefix_set); +- grub_free (prefix_set); ++ prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); ++ if (prefix_set) ++ { ++ grub_env_set ("prefix", prefix_set); ++ grub_free (prefix_set); ++ } + } ++ + grub_env_set ("root", device); + } + diff --git a/0192-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch b/0192-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch new file mode 100644 index 0000000..7fc40f1 --- /dev/null +++ b/0192-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Erwan Velu +Date: Wed, 25 Aug 2021 15:31:52 +0200 +Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock + +The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) +introduced the bigtime support by adding some features in v3 inodes. +This change extended grub_xfs_inode struct by 76 bytes but also changed +the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this +commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes +XFS_V2_INODE_SIZE becomes 16 bytes too small. + +As a result, the data structures aren't properly aligned and the GRUB +generates "attempt to read or write outside of partition" errors when +trying to read the XFS filesystem: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840 + error: attempt to read or write outside of partition. + +This commit change the XFS_V2_INODE_SIZE computation by subtracting 76 +bytes instead of 92 bytes from the actual size of grub_xfs_inode struct. +This 76 bytes value comes from added members: + 20 grub_uint8_t unused5 + 1 grub_uint64_t flags2 + 48 grub_uint8_t unused6 + +This patch explicitly splits the v2 and v3 parts of the structure. +The unused4 is still ending of the v2 structures and the v3 starts +at unused5. Thanks to this we will avoid future corruptions of v2 +or v3 inodes. + +The XFS_V2_INODE_SIZE is returning to its expected size and the +filesystem is back to a readable state: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (131) - 64, 768 + efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0 + grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024 + grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816 + grub> + +Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) + +Signed-off-by: Erwan Velu +Tested-by: Carlos Maiolino +Reviewed-by: Daniel Kiper +(cherry picked from commit a4b495520e4dc41a896a8b916a64eda9970c50ea) +--- + grub-core/fs/xfs.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 0f524c3a8a..e3816d1ec4 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy + grub_uint32_t nanosec; + } GRUB_PACKED; + ++/* ++ * The struct grub_xfs_inode layout was taken from the ++ * struct xfs_dinode_core which is described here: ++ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf ++ */ + struct grub_xfs_inode + { + grub_uint8_t magic[2]; +@@ -208,14 +213,15 @@ struct grub_xfs_inode + grub_uint32_t nextents; + grub_uint16_t unused3; + grub_uint8_t fork_offset; +- grub_uint8_t unused4[37]; ++ grub_uint8_t unused4[17]; /* Last member of inode v2. */ ++ grub_uint8_t unused5[20]; /* First member of inode v3. */ + grub_uint64_t flags2; +- grub_uint8_t unused5[48]; ++ grub_uint8_t unused6[48]; /* Last member of inode v3. */ + } GRUB_PACKED; + + #define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode) +-/* Size of struct grub_xfs_inode until fork_offset (included). */ +-#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92) ++/* Size of struct grub_xfs_inode v2, up to unused4 member included. */ ++#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + + struct grub_xfs_dirblock_tail + { diff --git a/0192-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch b/0192-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch deleted file mode 100644 index b9bc140..0000000 --- a/0192-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 19 Jul 2021 14:35:55 +1000 -Subject: [PATCH] powerpc: adjust setting of prefix for signed binary case - -On RHEL-signed powerpc grub, we sign a grub with -p /grub2 and expect -that there's a boot partition. - -Unfortunately grub_set_prefix_and_root tries to convert this to -($fwdevice)/grub2. This ends up being (ieee1275/disk)/grub2 and that -falls apart pretty quickly - there's no file-system on ieee1275/disk, -and it makes the search routine try things like -(ieee1275/disk,msdos2)(ieee1275/disk)/grub2 which also doesn't work. - -Detect if we would be about to create (ieee1275/disk)/path and don't: -preserve a prefix of /path instead and hope the search later finds us. - -Related: rhbz#1899864 - -Signed-off-by: Daniel Axtens -[rharwood@redhat.com: squash in fixup commit] -Signed-off-by: Robbie Harwood ---- - grub-core/kern/main.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 44 insertions(+), 5 deletions(-) - -diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c -index b573be6650..3fc3401472 100644 ---- a/grub-core/kern/main.c -+++ b/grub-core/kern/main.c -@@ -216,13 +216,52 @@ grub_set_prefix_and_root (void) - if (device) - { - char *prefix_set; -- -- prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); -- if (prefix_set) -+ -+#ifdef __powerpc__ -+ /* We have to be careful here on powerpc-ieee1275 + signed grub. We -+ will have signed something with a prefix that doesn't have a device -+ because we cannot know in advance what partition we're on. -+ -+ We will have had !device earlier, so we will have set device=fwdevice -+ However, we want to make sure we do not end up setting prefix to be -+ ($fwdevice)/path, because we will then end up trying to boot or search -+ based on a prefix of (ieee1275/disk)/path, which will not work because -+ it's missing a partition. -+ -+ Also: -+ - You can end up with a device with an FS directly on it, without -+ a partition, e.g. ieee1275/cdrom. -+ -+ - powerpc-ieee1275 + grub-install sets e.g. prefix=(,gpt2)/path, -+ which will have now been extended to device=$fwdisk,partition -+ and path=/path -+ -+ - PowerVM will give us device names like -+ ieee1275//vdevice/v-scsi@3000006c/disk@8100000000000000 -+ and we don't want to try to encode some sort of truth table about -+ what sorts of paths represent disks with partition tables and those -+ without partition tables. -+ -+ So we act unless there is a comma in the device, which would indicate -+ a partition has already been specified. -+ -+ (If we only have a path, the code in normal to discover config files -+ will try both without partitions and then with any partitions so we -+ will cover both CDs and HDs.) -+ */ -+ if (grub_strchr (device, ',') == NULL) -+ grub_env_set ("prefix", path); -+ else -+#endif - { -- grub_env_set ("prefix", prefix_set); -- grub_free (prefix_set); -+ prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); -+ if (prefix_set) -+ { -+ grub_env_set ("prefix", prefix_set); -+ grub_free (prefix_set); -+ } - } -+ - grub_env_set ("root", device); - } - diff --git a/0193-Print-module-name-on-license-check-failure.patch b/0193-Print-module-name-on-license-check-failure.patch new file mode 100644 index 0000000..5c30859 --- /dev/null +++ b/0193-Print-module-name-on-license-check-failure.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 12 Oct 2021 12:34:23 -0400 +Subject: [PATCH] Print module name on license check failure + +At the very least, this will make it easier to track down the problem +module - or, if something else has gone wrong, provide more information +for debugging. + +Signed-off-by: Robbie Harwood +--- + grub-core/kern/dl.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 9557254035..f304494574 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -528,14 +528,16 @@ grub_dl_find_section_index (Elf_Ehdr *e, const char *name) + Be sure to understand your license obligations. + */ + static grub_err_t +-grub_dl_check_license (Elf_Ehdr *e) ++grub_dl_check_license (grub_dl_t mod, Elf_Ehdr *e) + { + Elf_Shdr *s = grub_dl_find_section (e, ".module_license"); + if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0 + || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0 + || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0)) + return GRUB_ERR_NONE; +- return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license"); ++ return grub_error (GRUB_ERR_BAD_MODULE, ++ "incompatible license in module %s: %s", mod->name, ++ (char *) e + s->sh_offset); + } + + static grub_err_t +@@ -743,8 +745,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + constitutes linking) and GRUB core being licensed under GPLv3+. + Be sure to understand your license obligations. + */ +- if (grub_dl_check_license (e) +- || grub_dl_resolve_name (mod, e) ++ if (grub_dl_resolve_name (mod, e) ++ || grub_dl_check_license (mod, e) + || grub_dl_resolve_dependencies (mod, e) + || grub_dl_load_segments (mod, e) + || grub_dl_resolve_symbols (mod, e) diff --git a/0193-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch b/0193-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch deleted file mode 100644 index 7fc40f1..0000000 --- a/0193-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Erwan Velu -Date: Wed, 25 Aug 2021 15:31:52 +0200 -Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock - -The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) -introduced the bigtime support by adding some features in v3 inodes. -This change extended grub_xfs_inode struct by 76 bytes but also changed -the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this -commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes -XFS_V2_INODE_SIZE becomes 16 bytes too small. - -As a result, the data structures aren't properly aligned and the GRUB -generates "attempt to read or write outside of partition" errors when -trying to read the XFS filesystem: - - GNU GRUB version 2.11 - .... - grub> set debug=efi,gpt,xfs - grub> insmod part_gpt - grub> ls (hd0,gpt1)/ - partmap/gpt.c:93: Read a valid GPT header - partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 - fs/xfs.c:931: Reading sb - fs/xfs.c:270: Validating superblock - fs/xfs.c:295: XFS v4 superblock detected - fs/xfs.c:962: Reading root ino 128 - fs/xfs.c:515: Reading inode (128) - 64, 0 - fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840 - error: attempt to read or write outside of partition. - -This commit change the XFS_V2_INODE_SIZE computation by subtracting 76 -bytes instead of 92 bytes from the actual size of grub_xfs_inode struct. -This 76 bytes value comes from added members: - 20 grub_uint8_t unused5 - 1 grub_uint64_t flags2 - 48 grub_uint8_t unused6 - -This patch explicitly splits the v2 and v3 parts of the structure. -The unused4 is still ending of the v2 structures and the v3 starts -at unused5. Thanks to this we will avoid future corruptions of v2 -or v3 inodes. - -The XFS_V2_INODE_SIZE is returning to its expected size and the -filesystem is back to a readable state: - - GNU GRUB version 2.11 - .... - grub> set debug=efi,gpt,xfs - grub> insmod part_gpt - grub> ls (hd0,gpt1)/ - partmap/gpt.c:93: Read a valid GPT header - partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 - fs/xfs.c:931: Reading sb - fs/xfs.c:270: Validating superblock - fs/xfs.c:295: XFS v4 superblock detected - fs/xfs.c:962: Reading root ino 128 - fs/xfs.c:515: Reading inode (128) - 64, 0 - fs/xfs.c:515: Reading inode (128) - 64, 0 - fs/xfs.c:931: Reading sb - fs/xfs.c:270: Validating superblock - fs/xfs.c:295: XFS v4 superblock detected - fs/xfs.c:962: Reading root ino 128 - fs/xfs.c:515: Reading inode (128) - 64, 0 - fs/xfs.c:515: Reading inode (128) - 64, 0 - fs/xfs.c:515: Reading inode (128) - 64, 0 - fs/xfs.c:515: Reading inode (131) - 64, 768 - efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0 - grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024 - grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816 - grub> - -Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) - -Signed-off-by: Erwan Velu -Tested-by: Carlos Maiolino -Reviewed-by: Daniel Kiper -(cherry picked from commit a4b495520e4dc41a896a8b916a64eda9970c50ea) ---- - grub-core/fs/xfs.c | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c -index 0f524c3a8a..e3816d1ec4 100644 ---- a/grub-core/fs/xfs.c -+++ b/grub-core/fs/xfs.c -@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy - grub_uint32_t nanosec; - } GRUB_PACKED; - -+/* -+ * The struct grub_xfs_inode layout was taken from the -+ * struct xfs_dinode_core which is described here: -+ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf -+ */ - struct grub_xfs_inode - { - grub_uint8_t magic[2]; -@@ -208,14 +213,15 @@ struct grub_xfs_inode - grub_uint32_t nextents; - grub_uint16_t unused3; - grub_uint8_t fork_offset; -- grub_uint8_t unused4[37]; -+ grub_uint8_t unused4[17]; /* Last member of inode v2. */ -+ grub_uint8_t unused5[20]; /* First member of inode v3. */ - grub_uint64_t flags2; -- grub_uint8_t unused5[48]; -+ grub_uint8_t unused6[48]; /* Last member of inode v3. */ - } GRUB_PACKED; - - #define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode) --/* Size of struct grub_xfs_inode until fork_offset (included). */ --#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92) -+/* Size of struct grub_xfs_inode v2, up to unused4 member included. */ -+#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) - - struct grub_xfs_dirblock_tail - { diff --git a/0194-Print-module-name-on-license-check-failure.patch b/0194-Print-module-name-on-license-check-failure.patch deleted file mode 100644 index 5c30859..0000000 --- a/0194-Print-module-name-on-license-check-failure.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Tue, 12 Oct 2021 12:34:23 -0400 -Subject: [PATCH] Print module name on license check failure - -At the very least, this will make it easier to track down the problem -module - or, if something else has gone wrong, provide more information -for debugging. - -Signed-off-by: Robbie Harwood ---- - grub-core/kern/dl.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c -index 9557254035..f304494574 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -528,14 +528,16 @@ grub_dl_find_section_index (Elf_Ehdr *e, const char *name) - Be sure to understand your license obligations. - */ - static grub_err_t --grub_dl_check_license (Elf_Ehdr *e) -+grub_dl_check_license (grub_dl_t mod, Elf_Ehdr *e) - { - Elf_Shdr *s = grub_dl_find_section (e, ".module_license"); - if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0 - || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0 - || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0)) - return GRUB_ERR_NONE; -- return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license"); -+ return grub_error (GRUB_ERR_BAD_MODULE, -+ "incompatible license in module %s: %s", mod->name, -+ (char *) e + s->sh_offset); - } - - static grub_err_t -@@ -743,8 +745,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) - constitutes linking) and GRUB core being licensed under GPLv3+. - Be sure to understand your license obligations. - */ -- if (grub_dl_check_license (e) -- || grub_dl_resolve_name (mod, e) -+ if (grub_dl_resolve_name (mod, e) -+ || grub_dl_check_license (mod, e) - || grub_dl_resolve_dependencies (mod, e) - || grub_dl_load_segments (mod, e) - || grub_dl_resolve_symbols (mod, e) diff --git a/0194-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch b/0194-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch new file mode 100644 index 0000000..05417ed --- /dev/null +++ b/0194-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Oct 2021 09:53:15 +1100 +Subject: [PATCH] powerpc-ieee1275: load grub at 4MB, not 2MB + +This was first reported under PFW but reproduces under SLOF. + + - The core.elf was 2126152 = 0x207148 bytes in size with the following + program headers (per readelf): + +Entry point 0x200000 +There are 4 program headers, starting at offset 52 + +Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x000160 0x00200000 0x00200000 0x21f98 0x2971c RWE 0x8 + GNU_STACK 0x0220f8 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 + LOAD 0x0220f8 0x00232000 0x00232000 0x1e4e50 0x1e4e50 RWE 0x4 + NOTE 0x206f48 0x00000000 0x00000000 0x00200 0x00000 R 0x4 + + - SLOF places the ELF file at 0x4000 (after the reserved space for + interrupt handlers etc.) upwards. The image was 2126152 = 0x207148 + bytes in size, so it runs from 0x4000 - 0x20b148. We'll call 0x4000 the + load address. + +0x0 0x4000 0x20b148 + |----------|--------------| + | reserved | ELF contents | + + - SLOF then copies the first LOAD program header (for .text). That runs + for 0x21f98 bytes. It runs from + (load addr + 0x160) to (load addr + 0x160 + 0x21f98) + = 0x4160 to 0x260f8 + and we copy it to 0x200000 to 0x221f98. This overwrites the end of the + image: + +0x0 0x4000 0x200000 0x221f98 + |----------|------------|---------------| + | reserved | ELF cont.. | .text section | + + - SLOF zeros the bss up to PhysAddr + MemSize = 0x22971c + +0x0 0x4000 0x200000 0x221f98 0x22971c + |----------|------------|---------------|--------| + | reserved | ELF cont.. | .text section | bss 0s | + + - SLOF then goes to fulfil the next LOAD header (for mods), which is + for 0x1e4e50 bytes. We copy from + (load addr + 0x220f8) to (load addr + 0x220f8 + 0x1e4e50) + = 0x260f8 to 0x20af48 + and we copy it to 0x232000 to 0x416e50: + +0x0 0x4000 0x200000 0x221f98 0x22971c + |----------|------------|---------------|--------| + | reserved | ELF cont.. | .text section | bss 0s | + |-------------| + | copied area | + 0x260f8 0x20af48 + + This goes poorly: + +0x0 0x4000 0x200000 0x221f98 0x22971c 0x232000 0x40bf08 0x416e50 + |----------|------------|---------------|--------|-----|-----------|-------------| + | reserved | ELF cont.. | .text section | bss 0s | pad | some mods | .text start | + +This matches the observations on the running system - 0x40bf08 was where +the contents of memory no longer matched the contents of the ELF file. + +This was reported as a license verification failure on SLOF as the +last module's .module_license section fell past where the corruption +began. + +Signed-off-by: Daniel Axtens +[rharwood@redhat.com: trim very detailed commit message] +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 2 +- + include/grub/offsets.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 3f3459b2c7..6b00eb5557 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -89,7 +89,7 @@ kernel = { + i386_xen_pvh_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x100000'; + + mips_loongson_ldflags = '-Wl,-Ttext,0x80200000'; +- powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000'; ++ powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x400000'; + sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400'; + mips_arc_ldflags = '-Wl,-Ttext,$(TARGET_LINK_ADDR)'; + mips_qemu_mips_ldflags = '-Wl,-Ttext,0x80200000'; +diff --git a/include/grub/offsets.h b/include/grub/offsets.h +index 871e1cd4c3..69211aa798 100644 +--- a/include/grub/offsets.h ++++ b/include/grub/offsets.h +@@ -63,7 +63,7 @@ + #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 + + #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 +-#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 ++#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x400000 + + #define GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR 0x80200000 + diff --git a/0195-grub-mkconfig-restore-umask-for-grub.cfg.patch b/0195-grub-mkconfig-restore-umask-for-grub.cfg.patch new file mode 100644 index 0000000..76b73f5 --- /dev/null +++ b/0195-grub-mkconfig-restore-umask-for-grub.cfg.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang via Grub-devel +Date: Fri, 3 Dec 2021 16:13:28 +0800 +Subject: [PATCH] grub-mkconfig: restore umask for grub.cfg + +Since commit: + + ab2e53c8a grub-mkconfig: Honor a symlink when generating configuration +by grub-mkconfig + +has inadvertently discarded umask for creating grub.cfg in the process +of grub-mkconfig. The resulting wrong permission (0644) would allow +unprivileged users to read grub's configuration file content. This +presents a low confidentiality risk as grub.cfg may contain non-secured +plain-text passwords. + +This patch restores the missing umask and set the file mode of creation +to 0600 preventing unprivileged access. + +Fixes: CVE-2021-3981 + +Signed-off-by: Michael Chang +--- + util/grub-mkconfig.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index f55339a3f6..520a672cd2 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -311,7 +311,9 @@ and /etc/grub.d/* files or please file a bug report with + exit 1 + else + # none of the children aborted with error, install the new grub.cfg ++ oldumask=$(umask); umask 077 + cat ${grub_cfg}.new > ${grub_cfg} ++ umask $oldumask + rm -f ${grub_cfg}.new + fi + fi diff --git a/0195-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch b/0195-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch deleted file mode 100644 index 05417ed..0000000 --- a/0195-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 22 Oct 2021 09:53:15 +1100 -Subject: [PATCH] powerpc-ieee1275: load grub at 4MB, not 2MB - -This was first reported under PFW but reproduces under SLOF. - - - The core.elf was 2126152 = 0x207148 bytes in size with the following - program headers (per readelf): - -Entry point 0x200000 -There are 4 program headers, starting at offset 52 - -Program Headers: - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000160 0x00200000 0x00200000 0x21f98 0x2971c RWE 0x8 - GNU_STACK 0x0220f8 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 - LOAD 0x0220f8 0x00232000 0x00232000 0x1e4e50 0x1e4e50 RWE 0x4 - NOTE 0x206f48 0x00000000 0x00000000 0x00200 0x00000 R 0x4 - - - SLOF places the ELF file at 0x4000 (after the reserved space for - interrupt handlers etc.) upwards. The image was 2126152 = 0x207148 - bytes in size, so it runs from 0x4000 - 0x20b148. We'll call 0x4000 the - load address. - -0x0 0x4000 0x20b148 - |----------|--------------| - | reserved | ELF contents | - - - SLOF then copies the first LOAD program header (for .text). That runs - for 0x21f98 bytes. It runs from - (load addr + 0x160) to (load addr + 0x160 + 0x21f98) - = 0x4160 to 0x260f8 - and we copy it to 0x200000 to 0x221f98. This overwrites the end of the - image: - -0x0 0x4000 0x200000 0x221f98 - |----------|------------|---------------| - | reserved | ELF cont.. | .text section | - - - SLOF zeros the bss up to PhysAddr + MemSize = 0x22971c - -0x0 0x4000 0x200000 0x221f98 0x22971c - |----------|------------|---------------|--------| - | reserved | ELF cont.. | .text section | bss 0s | - - - SLOF then goes to fulfil the next LOAD header (for mods), which is - for 0x1e4e50 bytes. We copy from - (load addr + 0x220f8) to (load addr + 0x220f8 + 0x1e4e50) - = 0x260f8 to 0x20af48 - and we copy it to 0x232000 to 0x416e50: - -0x0 0x4000 0x200000 0x221f98 0x22971c - |----------|------------|---------------|--------| - | reserved | ELF cont.. | .text section | bss 0s | - |-------------| - | copied area | - 0x260f8 0x20af48 - - This goes poorly: - -0x0 0x4000 0x200000 0x221f98 0x22971c 0x232000 0x40bf08 0x416e50 - |----------|------------|---------------|--------|-----|-----------|-------------| - | reserved | ELF cont.. | .text section | bss 0s | pad | some mods | .text start | - -This matches the observations on the running system - 0x40bf08 was where -the contents of memory no longer matched the contents of the ELF file. - -This was reported as a license verification failure on SLOF as the -last module's .module_license section fell past where the corruption -began. - -Signed-off-by: Daniel Axtens -[rharwood@redhat.com: trim very detailed commit message] -Signed-off-by: Robbie Harwood ---- - grub-core/Makefile.core.def | 2 +- - include/grub/offsets.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 3f3459b2c7..6b00eb5557 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -89,7 +89,7 @@ kernel = { - i386_xen_pvh_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x100000'; - - mips_loongson_ldflags = '-Wl,-Ttext,0x80200000'; -- powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000'; -+ powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x400000'; - sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400'; - mips_arc_ldflags = '-Wl,-Ttext,$(TARGET_LINK_ADDR)'; - mips_qemu_mips_ldflags = '-Wl,-Ttext,0x80200000'; -diff --git a/include/grub/offsets.h b/include/grub/offsets.h -index 871e1cd4c3..69211aa798 100644 ---- a/include/grub/offsets.h -+++ b/include/grub/offsets.h -@@ -63,7 +63,7 @@ - #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 - - #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 --#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 -+#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x400000 - - #define GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR 0x80200000 - diff --git a/0196-fs-btrfs-Use-full-btrfs-bootloader-area.patch b/0196-fs-btrfs-Use-full-btrfs-bootloader-area.patch new file mode 100644 index 0000000..3f7198f --- /dev/null +++ b/0196-fs-btrfs-Use-full-btrfs-bootloader-area.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 13 Dec 2021 14:25:49 +0800 +Subject: [PATCH] fs/btrfs: Use full btrfs bootloader area + +Up to now GRUB can only embed to the first 64 KiB before primary +superblock of btrfs, effectively limiting the GRUB core size. That +could consequently pose restrictions to feature enablement like +advanced zstd compression. + +This patch attempts to utilize full unused area reserved by btrfs for +the bootloader outlined in the document [1]: + + The first 1MiB on each device is unused with the exception of primary + superblock that is on the offset 64KiB and spans 4KiB. + +Apart from that, adjacent sectors to superblock and first block group +are not used for embedding in case of overflow and logged access to +adjacent sectors could be useful for tracing it up. + +This patch has been tested to provide out of the box support for btrfs +zstd compression with which GRUB has been installed to the partition. + +[1] https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT + +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +(cherry picked from commit b0f06a81c6f31b6fa20be67a96b6683bba8210c9) +--- + grub-core/fs/btrfs.c | 90 ++++++++++++++++++++++++++++++++++++++++++++-------- + include/grub/disk.h | 2 ++ + 2 files changed, 79 insertions(+), 13 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 4cc86e9b79..07c0ff874b 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2476,6 +2476,33 @@ grub_btrfs_label (grub_device_t device, char **label) + } + + #ifdef GRUB_UTIL ++ ++struct embed_region { ++ unsigned int start; ++ unsigned int secs; ++}; ++ ++/* ++ * https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT ++ * The first 1 MiB on each device is unused with the exception of primary ++ * superblock that is on the offset 64 KiB and spans 4 KiB. ++ */ ++ ++static const struct { ++ struct embed_region available; ++ struct embed_region used[6]; ++} btrfs_head = { ++ .available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */ ++ .used = { ++ {0, 1}, /* boot.S. */ ++ {GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */ ++ {GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */ ++ {GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */ ++ {GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */ ++ {0, 0} /* Array terminator. */ ++ } ++}; ++ + static grub_err_t + grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + unsigned int *nsectors, +@@ -2483,25 +2510,62 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) + { +- unsigned i; ++ unsigned int i, j, n = 0; ++ const struct embed_region *u; ++ grub_disk_addr_t *map; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "BtrFS currently supports only PC-BIOS embedding"); + +- if (64 * 2 - 1 < *nsectors) +- return grub_error (GRUB_ERR_OUT_OF_RANGE, +- N_("your core.img is unusually large. " +- "It won't fit in the embedding area")); +- +- *nsectors = 64 * 2 - 1; +- if (*nsectors > max_nsectors) +- *nsectors = max_nsectors; +- *sectors = grub_calloc (*nsectors, sizeof (**sectors)); +- if (!*sectors) ++ map = grub_calloc (btrfs_head.available.secs, sizeof (*map)); ++ if (map == NULL) + return grub_errno; +- for (i = 0; i < *nsectors; i++) +- (*sectors)[i] = i + 1; ++ ++ /* ++ * Populating the map array so that it can be used to index if a disk ++ * address is available to embed: ++ * - 0: available, ++ * - 1: unavailable. ++ */ ++ for (u = btrfs_head.used; u->secs; ++u) ++ { ++ unsigned int end = u->start + u->secs; ++ ++ if (end > btrfs_head.available.secs) ++ end = btrfs_head.available.secs; ++ for (i = u->start; i < end; ++i) ++ map[i] = 1; ++ } ++ ++ /* Adding up n until it matches total size of available embedding area. */ ++ for (i = 0; i < btrfs_head.available.secs; ++i) ++ if (map[i] == 0) ++ n++; ++ ++ if (n < *nsectors) ++ { ++ grub_free (map); ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("your core.img is unusually large. " ++ "It won't fit in the embedding area")); ++ } ++ ++ if (n > max_nsectors) ++ n = max_nsectors; ++ ++ /* ++ * Populating the array so that it can used to index disk block address for ++ * an image file's offset to be embedded on disk (the unit is in sectors): ++ * - i: The disk block address relative to btrfs_head.available.start, ++ * - j: The offset in image file. ++ */ ++ for (i = 0, j = 0; i < btrfs_head.available.secs && j < n; ++i) ++ if (map[i] == 0) ++ map[j++] = btrfs_head.available.start + i; ++ ++ *nsectors = n; ++ *sectors = map; + + return GRUB_ERR_NONE; + } +diff --git a/include/grub/disk.h b/include/grub/disk.h +index f95aca929a..06210a7049 100644 +--- a/include/grub/disk.h ++++ b/include/grub/disk.h +@@ -182,6 +182,8 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t; + /* Return value of grub_disk_native_sectors() in case disk size is unknown. */ + #define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL + ++#define GRUB_DISK_KiB_TO_SECTORS(x) ((x) << (10 - GRUB_DISK_SECTOR_BITS)) ++ + /* Convert sector number from one sector size to another. */ + static inline grub_disk_addr_t + grub_convert_sector (grub_disk_addr_t sector, diff --git a/0196-grub-mkconfig-restore-umask-for-grub.cfg.patch b/0196-grub-mkconfig-restore-umask-for-grub.cfg.patch deleted file mode 100644 index 76b73f5..0000000 --- a/0196-grub-mkconfig-restore-umask-for-grub.cfg.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang via Grub-devel -Date: Fri, 3 Dec 2021 16:13:28 +0800 -Subject: [PATCH] grub-mkconfig: restore umask for grub.cfg - -Since commit: - - ab2e53c8a grub-mkconfig: Honor a symlink when generating configuration -by grub-mkconfig - -has inadvertently discarded umask for creating grub.cfg in the process -of grub-mkconfig. The resulting wrong permission (0644) would allow -unprivileged users to read grub's configuration file content. This -presents a low confidentiality risk as grub.cfg may contain non-secured -plain-text passwords. - -This patch restores the missing umask and set the file mode of creation -to 0600 preventing unprivileged access. - -Fixes: CVE-2021-3981 - -Signed-off-by: Michael Chang ---- - util/grub-mkconfig.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in -index f55339a3f6..520a672cd2 100644 ---- a/util/grub-mkconfig.in -+++ b/util/grub-mkconfig.in -@@ -311,7 +311,9 @@ and /etc/grub.d/* files or please file a bug report with - exit 1 - else - # none of the children aborted with error, install the new grub.cfg -+ oldumask=$(umask); umask 077 - cat ${grub_cfg}.new > ${grub_cfg} -+ umask $oldumask - rm -f ${grub_cfg}.new - fi - fi diff --git a/0197-Add-Fedora-location-of-DejaVu-SANS-font.patch b/0197-Add-Fedora-location-of-DejaVu-SANS-font.patch new file mode 100644 index 0000000..070fc24 --- /dev/null +++ b/0197-Add-Fedora-location-of-DejaVu-SANS-font.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: fluteze +Date: Sat, 27 Nov 2021 10:54:44 -0600 +Subject: [PATCH] Add Fedora location of DejaVu SANS font + +In Fedora 35, and possibly earlier, grub would fail to configure with a +complaint about DejaVu being "not found" even though it was installed. +The DejaVu sans font search path is updated to reflect the +distribution's current install path. + +Signed-off-by: Erik Edwards +[rharwood@redhat.com: slight commit message edits] +Signed-off-by: Robbie Harwood +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index ab0d326f00..40c4338bce 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1784,7 +1784,7 @@ fi + + if test x"$starfield_excuse" = x; then + for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do +- for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do ++ for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype /usr/share/fonts/dejavu-sans-fonts; do + if test -f "$dir/DejaVuSans.$ext"; then + DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext" + break 2 diff --git a/0197-fs-btrfs-Use-full-btrfs-bootloader-area.patch b/0197-fs-btrfs-Use-full-btrfs-bootloader-area.patch deleted file mode 100644 index 3f7198f..0000000 --- a/0197-fs-btrfs-Use-full-btrfs-bootloader-area.patch +++ /dev/null @@ -1,160 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Mon, 13 Dec 2021 14:25:49 +0800 -Subject: [PATCH] fs/btrfs: Use full btrfs bootloader area - -Up to now GRUB can only embed to the first 64 KiB before primary -superblock of btrfs, effectively limiting the GRUB core size. That -could consequently pose restrictions to feature enablement like -advanced zstd compression. - -This patch attempts to utilize full unused area reserved by btrfs for -the bootloader outlined in the document [1]: - - The first 1MiB on each device is unused with the exception of primary - superblock that is on the offset 64KiB and spans 4KiB. - -Apart from that, adjacent sectors to superblock and first block group -are not used for embedding in case of overflow and logged access to -adjacent sectors could be useful for tracing it up. - -This patch has been tested to provide out of the box support for btrfs -zstd compression with which GRUB has been installed to the partition. - -[1] https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT - -Signed-off-by: Michael Chang -Reviewed-by: Daniel Kiper -(cherry picked from commit b0f06a81c6f31b6fa20be67a96b6683bba8210c9) ---- - grub-core/fs/btrfs.c | 90 ++++++++++++++++++++++++++++++++++++++++++++-------- - include/grub/disk.h | 2 ++ - 2 files changed, 79 insertions(+), 13 deletions(-) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 4cc86e9b79..07c0ff874b 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -2476,6 +2476,33 @@ grub_btrfs_label (grub_device_t device, char **label) - } - - #ifdef GRUB_UTIL -+ -+struct embed_region { -+ unsigned int start; -+ unsigned int secs; -+}; -+ -+/* -+ * https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT -+ * The first 1 MiB on each device is unused with the exception of primary -+ * superblock that is on the offset 64 KiB and spans 4 KiB. -+ */ -+ -+static const struct { -+ struct embed_region available; -+ struct embed_region used[6]; -+} btrfs_head = { -+ .available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */ -+ .used = { -+ {0, 1}, /* boot.S. */ -+ {GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */ -+ {GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */ -+ {GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */ -+ {GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */ -+ {0, 0} /* Array terminator. */ -+ } -+}; -+ - static grub_err_t - grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), - unsigned int *nsectors, -@@ -2483,25 +2510,62 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), - grub_embed_type_t embed_type, - grub_disk_addr_t **sectors) - { -- unsigned i; -+ unsigned int i, j, n = 0; -+ const struct embed_region *u; -+ grub_disk_addr_t *map; - - if (embed_type != GRUB_EMBED_PCBIOS) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "BtrFS currently supports only PC-BIOS embedding"); - -- if (64 * 2 - 1 < *nsectors) -- return grub_error (GRUB_ERR_OUT_OF_RANGE, -- N_("your core.img is unusually large. " -- "It won't fit in the embedding area")); -- -- *nsectors = 64 * 2 - 1; -- if (*nsectors > max_nsectors) -- *nsectors = max_nsectors; -- *sectors = grub_calloc (*nsectors, sizeof (**sectors)); -- if (!*sectors) -+ map = grub_calloc (btrfs_head.available.secs, sizeof (*map)); -+ if (map == NULL) - return grub_errno; -- for (i = 0; i < *nsectors; i++) -- (*sectors)[i] = i + 1; -+ -+ /* -+ * Populating the map array so that it can be used to index if a disk -+ * address is available to embed: -+ * - 0: available, -+ * - 1: unavailable. -+ */ -+ for (u = btrfs_head.used; u->secs; ++u) -+ { -+ unsigned int end = u->start + u->secs; -+ -+ if (end > btrfs_head.available.secs) -+ end = btrfs_head.available.secs; -+ for (i = u->start; i < end; ++i) -+ map[i] = 1; -+ } -+ -+ /* Adding up n until it matches total size of available embedding area. */ -+ for (i = 0; i < btrfs_head.available.secs; ++i) -+ if (map[i] == 0) -+ n++; -+ -+ if (n < *nsectors) -+ { -+ grub_free (map); -+ return grub_error (GRUB_ERR_OUT_OF_RANGE, -+ N_("your core.img is unusually large. " -+ "It won't fit in the embedding area")); -+ } -+ -+ if (n > max_nsectors) -+ n = max_nsectors; -+ -+ /* -+ * Populating the array so that it can used to index disk block address for -+ * an image file's offset to be embedded on disk (the unit is in sectors): -+ * - i: The disk block address relative to btrfs_head.available.start, -+ * - j: The offset in image file. -+ */ -+ for (i = 0, j = 0; i < btrfs_head.available.secs && j < n; ++i) -+ if (map[i] == 0) -+ map[j++] = btrfs_head.available.start + i; -+ -+ *nsectors = n; -+ *sectors = map; - - return GRUB_ERR_NONE; - } -diff --git a/include/grub/disk.h b/include/grub/disk.h -index f95aca929a..06210a7049 100644 ---- a/include/grub/disk.h -+++ b/include/grub/disk.h -@@ -182,6 +182,8 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t; - /* Return value of grub_disk_native_sectors() in case disk size is unknown. */ - #define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL - -+#define GRUB_DISK_KiB_TO_SECTORS(x) ((x) << (10 - GRUB_DISK_SECTOR_BITS)) -+ - /* Convert sector number from one sector size to another. */ - static inline grub_disk_addr_t - grub_convert_sector (grub_disk_addr_t sector, diff --git a/0198-Add-Fedora-location-of-DejaVu-SANS-font.patch b/0198-Add-Fedora-location-of-DejaVu-SANS-font.patch deleted file mode 100644 index c3e45e4..0000000 --- a/0198-Add-Fedora-location-of-DejaVu-SANS-font.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: fluteze -Date: Sat, 27 Nov 2021 10:54:44 -0600 -Subject: [PATCH] Add Fedora location of DejaVu SANS font - -In Fedora 35, and possibly earlier, grub would fail to configure with a -complaint about DejaVu being "not found" even though it was installed. -The DejaVu sans font search path is updated to reflect the -distribution's current install path. - -Signed-off-by: Erik Edwards -[rharwood@redhat.com: slight commit message edits] -Signed-off-by: Robbie Harwood ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index f069d84039..88e33e0f0c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1785,7 +1785,7 @@ fi - - if test x"$starfield_excuse" = x; then - for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do -- for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do -+ for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype /usr/share/fonts/dejavu-sans-fonts; do - if test -f "$dir/DejaVuSans.$ext"; then - DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext" - break 2 diff --git a/0198-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch b/0198-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch new file mode 100644 index 0000000..200cd51 --- /dev/null +++ b/0198-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 11:30:32 +0100 +Subject: [PATCH] normal/menu: Don't show "Booting `%s'" msg when auto-booting + with TIMEOUT_STYLE_HIDDEN + +When the user has asked the menu code to be hidden/quiet and the current +entry is being autobooted because the timeout has expired don't show +the "Booting `%s'" msg. + +This is necessary to let flicker-free boots really be flicker free, +otherwise the "Booting `%s'" msg will kick the EFI fb into text mode +and show the msg, breaking the flicker-free experience. + +Signed-off-by: Hans de Goede +--- + grub-core/normal/menu.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index ec0c92bade..c8516a5a08 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -606,13 +606,15 @@ print_countdown (struct grub_term_coordinate *pos, int n) + entry to be executed is a result of an automatic default selection because + of the timeout. */ + static int +-run_menu (grub_menu_t menu, int nested, int *auto_boot) ++run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) + { + grub_uint64_t saved_time; + int default_entry, current_entry; + int timeout; + enum timeout_style timeout_style; + ++ *notify_boot = 1; ++ + default_entry = get_entry_number (menu, "default"); + + /* If DEFAULT_ENTRY is not within the menu entries, fall back to +@@ -687,6 +689,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + if (timeout == 0) + { + *auto_boot = 1; ++ *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN; + return default_entry; + } + +@@ -840,12 +843,16 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + + /* Callback invoked immediately before a menu entry is executed. */ + static void +-notify_booting (grub_menu_entry_t entry, +- void *userdata __attribute__((unused))) ++notify_booting (grub_menu_entry_t entry, void *userdata) + { +- grub_printf (" "); +- grub_printf_ (N_("Booting `%s'"), entry->title); +- grub_printf ("\n\n"); ++ int *notify_boot = userdata; ++ ++ if (*notify_boot) ++ { ++ grub_printf (" "); ++ grub_printf_ (N_("Booting `%s'"), entry->title); ++ grub_printf ("\n\n"); ++ } + } + + /* Callback invoked when a default menu entry executed because of a timeout +@@ -893,8 +900,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + int boot_entry; + grub_menu_entry_t e; + int auto_boot; ++ int notify_boot; + +- boot_entry = run_menu (menu, nested, &auto_boot); ++ boot_entry = run_menu (menu, nested, &auto_boot, ¬ify_boot); + if (boot_entry < 0) + break; + +@@ -906,7 +914,7 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + + if (auto_boot) + grub_menu_execute_with_fallback (menu, e, autobooted, +- &execution_callback, 0); ++ &execution_callback, ¬ify_boot); + else + grub_menu_execute_entry (e, 0); + if (autobooted) diff --git a/0199-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch b/0199-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch new file mode 100644 index 0000000..0f99c22 --- /dev/null +++ b/0199-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 11:30:33 +0100 +Subject: [PATCH] EFI: suppress the "Welcome to GRUB!" message in EFI builds + +Grub EFI builds are now often used in combination with flicker-free +boot, but this breaks with upstream grub because the "Welcome to GRUB!" +message will kick the EFI fb into text mode and show the msg, +breaking the flicker-free experience. + +EFI systems are so fast, that when the menu or the countdown are enabled +the message will be immediately overwritten, so in these cases not +printing the message does not matter. + +And in case when the timeout_style is set to TIMEOUT_STYLE_HIDDEN, +the user has asked grub to be quiet (for example to allow flickfree +boot) annd thus the message should not be printed. + +Signed-off-by: Hans de Goede +--- + grub-core/kern/main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 3fc3401472..993b8a8598 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -317,10 +317,13 @@ grub_main (void) + + grub_boot_time ("After machine init."); + ++ /* This breaks flicker-free boot on EFI systems, so disable it there. */ ++#ifndef GRUB_MACHINE_EFI + /* Hello. */ + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); ++#endif + + /* Init verifiers API. */ + grub_verifiers_init (); diff --git a/0199-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch b/0199-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch deleted file mode 100644 index 200cd51..0000000 --- a/0199-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 28 Jan 2022 11:30:32 +0100 -Subject: [PATCH] normal/menu: Don't show "Booting `%s'" msg when auto-booting - with TIMEOUT_STYLE_HIDDEN - -When the user has asked the menu code to be hidden/quiet and the current -entry is being autobooted because the timeout has expired don't show -the "Booting `%s'" msg. - -This is necessary to let flicker-free boots really be flicker free, -otherwise the "Booting `%s'" msg will kick the EFI fb into text mode -and show the msg, breaking the flicker-free experience. - -Signed-off-by: Hans de Goede ---- - grub-core/normal/menu.c | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - -diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index ec0c92bade..c8516a5a08 100644 ---- a/grub-core/normal/menu.c -+++ b/grub-core/normal/menu.c -@@ -606,13 +606,15 @@ print_countdown (struct grub_term_coordinate *pos, int n) - entry to be executed is a result of an automatic default selection because - of the timeout. */ - static int --run_menu (grub_menu_t menu, int nested, int *auto_boot) -+run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) - { - grub_uint64_t saved_time; - int default_entry, current_entry; - int timeout; - enum timeout_style timeout_style; - -+ *notify_boot = 1; -+ - default_entry = get_entry_number (menu, "default"); - - /* If DEFAULT_ENTRY is not within the menu entries, fall back to -@@ -687,6 +689,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) - if (timeout == 0) - { - *auto_boot = 1; -+ *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN; - return default_entry; - } - -@@ -840,12 +843,16 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) - - /* Callback invoked immediately before a menu entry is executed. */ - static void --notify_booting (grub_menu_entry_t entry, -- void *userdata __attribute__((unused))) -+notify_booting (grub_menu_entry_t entry, void *userdata) - { -- grub_printf (" "); -- grub_printf_ (N_("Booting `%s'"), entry->title); -- grub_printf ("\n\n"); -+ int *notify_boot = userdata; -+ -+ if (*notify_boot) -+ { -+ grub_printf (" "); -+ grub_printf_ (N_("Booting `%s'"), entry->title); -+ grub_printf ("\n\n"); -+ } - } - - /* Callback invoked when a default menu entry executed because of a timeout -@@ -893,8 +900,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted) - int boot_entry; - grub_menu_entry_t e; - int auto_boot; -+ int notify_boot; - -- boot_entry = run_menu (menu, nested, &auto_boot); -+ boot_entry = run_menu (menu, nested, &auto_boot, ¬ify_boot); - if (boot_entry < 0) - break; - -@@ -906,7 +914,7 @@ show_menu (grub_menu_t menu, int nested, int autobooted) - - if (auto_boot) - grub_menu_execute_with_fallback (menu, e, autobooted, -- &execution_callback, 0); -+ &execution_callback, ¬ify_boot); - else - grub_menu_execute_entry (e, 0); - if (autobooted) diff --git a/0200-EFI-console-Do-not-set-colorstate-until-the-first-te.patch b/0200-EFI-console-Do-not-set-colorstate-until-the-first-te.patch new file mode 100644 index 0000000..ade6aae --- /dev/null +++ b/0200-EFI-console-Do-not-set-colorstate-until-the-first-te.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 12:43:48 +0100 +Subject: [PATCH] EFI: console: Do not set colorstate until the first text + output + +GRUB_MOD_INIT(normal) does an unconditional: + +grub_env_set ("color_normal", "light-gray/black"); + +which triggers a grub_term_setcolorstate() call. The original version +of the "efi/console: Do not set text-mode until we actually need it" patch: +https://lists.gnu.org/archive/html/grub-devel/2018-03/msg00125.html + +Protected against this by caching the requested state in +grub_console_setcolorstate () and then only applying it when the first +text output actually happens. During refactoring to move the +grub_console_setcolorstate () up higher in the grub-core/term/efi/console.c +file the code to cache the color-state + bail early was accidentally +dropped. + +Restore the cache the color-state + bail early behavior from the original. + +Cc: Javier Martinez Canillas +Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") +Signed-off-by: Hans de Goede +--- + grub-core/term/efi/console.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c +index 2f1ae85ba7..c44b2ac318 100644 +--- a/grub-core/term/efi/console.c ++++ b/grub-core/term/efi/console.c +@@ -82,6 +82,16 @@ grub_console_setcolorstate (struct grub_term_output *term + { + grub_efi_simple_text_output_interface_t *o; + ++ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) ++ { ++ /* ++ * Cache colorstate changes before the first text-output, this avoids ++ * "color_normal" environment writes causing a switch to textmode. ++ */ ++ text_colorstate = state; ++ return; ++ } ++ + if (grub_efi_is_finished) + return; + diff --git a/0200-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch b/0200-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch deleted file mode 100644 index 0f99c22..0000000 --- a/0200-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 28 Jan 2022 11:30:33 +0100 -Subject: [PATCH] EFI: suppress the "Welcome to GRUB!" message in EFI builds - -Grub EFI builds are now often used in combination with flicker-free -boot, but this breaks with upstream grub because the "Welcome to GRUB!" -message will kick the EFI fb into text mode and show the msg, -breaking the flicker-free experience. - -EFI systems are so fast, that when the menu or the countdown are enabled -the message will be immediately overwritten, so in these cases not -printing the message does not matter. - -And in case when the timeout_style is set to TIMEOUT_STYLE_HIDDEN, -the user has asked grub to be quiet (for example to allow flickfree -boot) annd thus the message should not be printed. - -Signed-off-by: Hans de Goede ---- - grub-core/kern/main.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c -index 3fc3401472..993b8a8598 100644 ---- a/grub-core/kern/main.c -+++ b/grub-core/kern/main.c -@@ -317,10 +317,13 @@ grub_main (void) - - grub_boot_time ("After machine init."); - -+ /* This breaks flicker-free boot on EFI systems, so disable it there. */ -+#ifndef GRUB_MACHINE_EFI - /* Hello. */ - grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); - grub_printf ("Welcome to GRUB!\n\n"); - grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); -+#endif - - /* Init verifiers API. */ - grub_verifiers_init (); diff --git a/0201-EFI-console-Do-not-set-colorstate-until-the-first-te.patch b/0201-EFI-console-Do-not-set-colorstate-until-the-first-te.patch deleted file mode 100644 index ade6aae..0000000 --- a/0201-EFI-console-Do-not-set-colorstate-until-the-first-te.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 28 Jan 2022 12:43:48 +0100 -Subject: [PATCH] EFI: console: Do not set colorstate until the first text - output - -GRUB_MOD_INIT(normal) does an unconditional: - -grub_env_set ("color_normal", "light-gray/black"); - -which triggers a grub_term_setcolorstate() call. The original version -of the "efi/console: Do not set text-mode until we actually need it" patch: -https://lists.gnu.org/archive/html/grub-devel/2018-03/msg00125.html - -Protected against this by caching the requested state in -grub_console_setcolorstate () and then only applying it when the first -text output actually happens. During refactoring to move the -grub_console_setcolorstate () up higher in the grub-core/term/efi/console.c -file the code to cache the color-state + bail early was accidentally -dropped. - -Restore the cache the color-state + bail early behavior from the original. - -Cc: Javier Martinez Canillas -Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") -Signed-off-by: Hans de Goede ---- - grub-core/term/efi/console.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c -index 2f1ae85ba7..c44b2ac318 100644 ---- a/grub-core/term/efi/console.c -+++ b/grub-core/term/efi/console.c -@@ -82,6 +82,16 @@ grub_console_setcolorstate (struct grub_term_output *term - { - grub_efi_simple_text_output_interface_t *o; - -+ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) -+ { -+ /* -+ * Cache colorstate changes before the first text-output, this avoids -+ * "color_normal" environment writes causing a switch to textmode. -+ */ -+ text_colorstate = state; -+ return; -+ } -+ - if (grub_efi_is_finished) - return; - diff --git a/0201-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch b/0201-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch new file mode 100644 index 0000000..5fab5db --- /dev/null +++ b/0201-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 12:43:49 +0100 +Subject: [PATCH] EFI: console: Do not set cursor until the first text output + +To allow flickerfree boot the EFI console code does not call +grub_efi_set_text_mode (1) until some text is actually output. + +Depending on if the output text is because of an error loading +e.g. the .cfg file; or because of showing the menu the cursor needs +to be on or off when the first text is shown. + +So far the cursor was hardcoded to being on, but this is causing +drawing artifacts + slow drawing of the menu as reported here: +https://bugzilla.redhat.com/show_bug.cgi?id=1946969 + +Handle the cursorstate in the same way as the colorstate to fix this, +when no text has been output yet, just cache the cursorstate and +then use the last set value when the first text is output. + +Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") +Signed-off-by: Hans de Goede +--- + grub-core/term/efi/console.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c +index c44b2ac318..a3622e4fe5 100644 +--- a/grub-core/term/efi/console.c ++++ b/grub-core/term/efi/console.c +@@ -31,7 +31,15 @@ typedef enum { + } + grub_text_mode; + ++typedef enum { ++ GRUB_CURSOR_MODE_UNDEFINED = -1, ++ GRUB_CURSOR_MODE_OFF = 0, ++ GRUB_CURSUR_MODE_ON ++} ++grub_cursor_mode; ++ + static grub_text_mode text_mode = GRUB_TEXT_MODE_UNDEFINED; ++static grub_cursor_mode cursor_mode = GRUB_CURSOR_MODE_UNDEFINED; + static grub_term_color_state text_colorstate = GRUB_TERM_COLOR_UNDEFINED; + + static grub_uint32_t +@@ -119,8 +127,12 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), + { + grub_efi_simple_text_output_interface_t *o; + +- if (grub_efi_is_finished) +- return; ++ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) ++ { ++ /* Cache cursor changes before the first text-output */ ++ cursor_mode = on; ++ return; ++ } + + o = grub_efi_system_table->con_out; + efi_call_2 (o->enable_cursor, o, on); +@@ -143,7 +155,8 @@ grub_prepare_for_text_output (struct grub_term_output *term) + return GRUB_ERR_BAD_DEVICE; + } + +- grub_console_setcursor (term, 1); ++ if (cursor_mode != GRUB_CURSOR_MODE_UNDEFINED) ++ grub_console_setcursor (term, cursor_mode); + if (text_colorstate != GRUB_TERM_COLOR_UNDEFINED) + grub_console_setcolorstate (term, text_colorstate); + text_mode = GRUB_TEXT_MODE_AVAILABLE; diff --git a/0202-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch b/0202-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch deleted file mode 100644 index 5fab5db..0000000 --- a/0202-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 28 Jan 2022 12:43:49 +0100 -Subject: [PATCH] EFI: console: Do not set cursor until the first text output - -To allow flickerfree boot the EFI console code does not call -grub_efi_set_text_mode (1) until some text is actually output. - -Depending on if the output text is because of an error loading -e.g. the .cfg file; or because of showing the menu the cursor needs -to be on or off when the first text is shown. - -So far the cursor was hardcoded to being on, but this is causing -drawing artifacts + slow drawing of the menu as reported here: -https://bugzilla.redhat.com/show_bug.cgi?id=1946969 - -Handle the cursorstate in the same way as the colorstate to fix this, -when no text has been output yet, just cache the cursorstate and -then use the last set value when the first text is output. - -Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") -Signed-off-by: Hans de Goede ---- - grub-core/term/efi/console.c | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c -index c44b2ac318..a3622e4fe5 100644 ---- a/grub-core/term/efi/console.c -+++ b/grub-core/term/efi/console.c -@@ -31,7 +31,15 @@ typedef enum { - } - grub_text_mode; - -+typedef enum { -+ GRUB_CURSOR_MODE_UNDEFINED = -1, -+ GRUB_CURSOR_MODE_OFF = 0, -+ GRUB_CURSUR_MODE_ON -+} -+grub_cursor_mode; -+ - static grub_text_mode text_mode = GRUB_TEXT_MODE_UNDEFINED; -+static grub_cursor_mode cursor_mode = GRUB_CURSOR_MODE_UNDEFINED; - static grub_term_color_state text_colorstate = GRUB_TERM_COLOR_UNDEFINED; - - static grub_uint32_t -@@ -119,8 +127,12 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), - { - grub_efi_simple_text_output_interface_t *o; - -- if (grub_efi_is_finished) -- return; -+ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) -+ { -+ /* Cache cursor changes before the first text-output */ -+ cursor_mode = on; -+ return; -+ } - - o = grub_efi_system_table->con_out; - efi_call_2 (o->enable_cursor, o, on); -@@ -143,7 +155,8 @@ grub_prepare_for_text_output (struct grub_term_output *term) - return GRUB_ERR_BAD_DEVICE; - } - -- grub_console_setcursor (term, 1); -+ if (cursor_mode != GRUB_CURSOR_MODE_UNDEFINED) -+ grub_console_setcursor (term, cursor_mode); - if (text_colorstate != GRUB_TERM_COLOR_UNDEFINED) - grub_console_setcolorstate (term, text_colorstate); - text_mode = GRUB_TEXT_MODE_AVAILABLE; diff --git a/0202-Use-visual-indentation-in-config.h.in.patch b/0202-Use-visual-indentation-in-config.h.in.patch new file mode 100644 index 0000000..978eb07 --- /dev/null +++ b/0202-Use-visual-indentation-in-config.h.in.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 15 Dec 2021 15:46:13 -0500 +Subject: [PATCH] Use visual indentation in config.h.in + +Signed-off-by: Robbie Harwood +(cherry picked from commit de8051f34de0aa55c921a510974e5bb27e39c17b) +[rharwood: GRUB_RPM_CONFIG presence] +--- + config.h.in | 58 +++++++++++++++++++++++++++++----------------------------- + 1 file changed, 29 insertions(+), 29 deletions(-) + +diff --git a/config.h.in b/config.h.in +index c80e3e0aba..f2ed0066ec 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -23,47 +23,47 @@ + #define MINILZO_CFG_SKIP_LZO1X_DECOMPRESS 1 + + #if defined (GRUB_BUILD) +-#undef ENABLE_NLS +-#define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@ +-#define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@ +-#if defined __APPLE__ +-# if defined __BIG_ENDIAN__ +-# define BUILD_WORDS_BIGENDIAN 1 +-# else +-# define BUILD_WORDS_BIGENDIAN 0 +-# endif +-#else +-#define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@ +-#endif ++# undef ENABLE_NLS ++# define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@ ++# define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@ ++# if defined __APPLE__ ++# if defined __BIG_ENDIAN__ ++# define BUILD_WORDS_BIGENDIAN 1 ++# else ++# define BUILD_WORDS_BIGENDIAN 0 ++# endif ++# else /* !defined __APPLE__ */ ++# define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@ ++# endif /* !defined __APPLE__ */ + #elif defined (GRUB_UTIL) || !defined (GRUB_MACHINE) +-#include +-#else +-#define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@ ++# include ++#else /* !defined GRUB_UTIL && defined GRUB_MACHINE */ ++# define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@ + /* Define if C symbols get an underscore after compilation. */ +-#define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ ++# define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ + /* Define it to one of __bss_start, edata and _edata. */ +-#define BSS_START_SYMBOL @BSS_START_SYMBOL@ ++# define BSS_START_SYMBOL @BSS_START_SYMBOL@ + /* Define it to either end or _end. */ +-#define END_SYMBOL @END_SYMBOL@ ++# define END_SYMBOL @END_SYMBOL@ + /* Name of package. */ +-#define PACKAGE "@PACKAGE@" ++# define PACKAGE "@PACKAGE@" + /* Version number of package. */ +-#define VERSION "@VERSION@" ++# define VERSION "@VERSION@" + /* Define to the full name and version of this package. */ +-#define PACKAGE_STRING "@PACKAGE_STRING@" ++# define PACKAGE_STRING "@PACKAGE_STRING@" + /* Define to the version of this package. */ +-#define PACKAGE_VERSION "@PACKAGE_VERSION@" ++# define PACKAGE_VERSION "@PACKAGE_VERSION@" + /* Define to the full name of this package. */ +-#define PACKAGE_NAME "@PACKAGE_NAME@" ++# define PACKAGE_NAME "@PACKAGE_NAME@" + /* Define to the address where bug reports for this package should be sent. */ +-#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" ++# define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +-#define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" +-#define GRUB_PLATFORM "@GRUB_PLATFORM@" +-#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" ++# define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" ++# define GRUB_PLATFORM "@GRUB_PLATFORM@" ++# define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" + +-#define RE_ENABLE_I18N 1 ++# define RE_ENABLE_I18N 1 + +-#define _GNU_SOURCE 1 ++# define _GNU_SOURCE 1 + + #endif diff --git a/0203-Use-visual-indentation-in-config.h.in.patch b/0203-Use-visual-indentation-in-config.h.in.patch deleted file mode 100644 index 978eb07..0000000 --- a/0203-Use-visual-indentation-in-config.h.in.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Wed, 15 Dec 2021 15:46:13 -0500 -Subject: [PATCH] Use visual indentation in config.h.in - -Signed-off-by: Robbie Harwood -(cherry picked from commit de8051f34de0aa55c921a510974e5bb27e39c17b) -[rharwood: GRUB_RPM_CONFIG presence] ---- - config.h.in | 58 +++++++++++++++++++++++++++++----------------------------- - 1 file changed, 29 insertions(+), 29 deletions(-) - -diff --git a/config.h.in b/config.h.in -index c80e3e0aba..f2ed0066ec 100644 ---- a/config.h.in -+++ b/config.h.in -@@ -23,47 +23,47 @@ - #define MINILZO_CFG_SKIP_LZO1X_DECOMPRESS 1 - - #if defined (GRUB_BUILD) --#undef ENABLE_NLS --#define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@ --#define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@ --#if defined __APPLE__ --# if defined __BIG_ENDIAN__ --# define BUILD_WORDS_BIGENDIAN 1 --# else --# define BUILD_WORDS_BIGENDIAN 0 --# endif --#else --#define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@ --#endif -+# undef ENABLE_NLS -+# define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@ -+# define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@ -+# if defined __APPLE__ -+# if defined __BIG_ENDIAN__ -+# define BUILD_WORDS_BIGENDIAN 1 -+# else -+# define BUILD_WORDS_BIGENDIAN 0 -+# endif -+# else /* !defined __APPLE__ */ -+# define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@ -+# endif /* !defined __APPLE__ */ - #elif defined (GRUB_UTIL) || !defined (GRUB_MACHINE) --#include --#else --#define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@ -+# include -+#else /* !defined GRUB_UTIL && defined GRUB_MACHINE */ -+# define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@ - /* Define if C symbols get an underscore after compilation. */ --#define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ -+# define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ - /* Define it to one of __bss_start, edata and _edata. */ --#define BSS_START_SYMBOL @BSS_START_SYMBOL@ -+# define BSS_START_SYMBOL @BSS_START_SYMBOL@ - /* Define it to either end or _end. */ --#define END_SYMBOL @END_SYMBOL@ -+# define END_SYMBOL @END_SYMBOL@ - /* Name of package. */ --#define PACKAGE "@PACKAGE@" -+# define PACKAGE "@PACKAGE@" - /* Version number of package. */ --#define VERSION "@VERSION@" -+# define VERSION "@VERSION@" - /* Define to the full name and version of this package. */ --#define PACKAGE_STRING "@PACKAGE_STRING@" -+# define PACKAGE_STRING "@PACKAGE_STRING@" - /* Define to the version of this package. */ --#define PACKAGE_VERSION "@PACKAGE_VERSION@" -+# define PACKAGE_VERSION "@PACKAGE_VERSION@" - /* Define to the full name of this package. */ --#define PACKAGE_NAME "@PACKAGE_NAME@" -+# define PACKAGE_NAME "@PACKAGE_NAME@" - /* Define to the address where bug reports for this package should be sent. */ --#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" -+# define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" - --#define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" --#define GRUB_PLATFORM "@GRUB_PLATFORM@" --#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" -+# define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" -+# define GRUB_PLATFORM "@GRUB_PLATFORM@" -+# define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" - --#define RE_ENABLE_I18N 1 -+# define RE_ENABLE_I18N 1 - --#define _GNU_SOURCE 1 -+# define _GNU_SOURCE 1 - - #endif diff --git a/0203-Where-present-ensure-config-util.h-precedes-config.h.patch b/0203-Where-present-ensure-config-util.h-precedes-config.h.patch new file mode 100644 index 0000000..626c4b4 --- /dev/null +++ b/0203-Where-present-ensure-config-util.h-precedes-config.h.patch @@ -0,0 +1,275 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 22 Feb 2022 16:57:54 -0500 +Subject: [PATCH] Where present, ensure config-util.h precedes config.h + +gnulib defines go in config-util.h, and we need to know whether to +provide duplicates in config.h or not. + +Signed-off-by: Robbie Harwood +(cherry picked from commit 46e82b28e1a75703d0424c7e13d009171310c6cd) +[rharwood: gensymlist isn't part of tarballs] +--- + grub-core/disk/host.c | 2 +- + grub-core/kern/emu/argp_common.c | 2 +- + grub-core/kern/emu/main.c | 2 +- + grub-core/osdep/aros/config.c | 2 +- + grub-core/osdep/basic/emunet.c | 2 +- + grub-core/osdep/basic/init.c | 2 +- + grub-core/osdep/haiku/getroot.c | 2 +- + grub-core/osdep/linux/emunet.c | 2 +- + grub-core/osdep/unix/config.c | 2 +- + grub-core/osdep/unix/cputime.c | 2 +- + grub-core/osdep/unix/dl.c | 2 +- + grub-core/osdep/unix/emuconsole.c | 2 +- + grub-core/osdep/unix/getroot.c | 2 +- + grub-core/osdep/windows/config.c | 2 +- + grub-core/osdep/windows/cputime.c | 2 +- + grub-core/osdep/windows/dl.c | 2 +- + grub-core/osdep/windows/emuconsole.c | 2 +- + grub-core/osdep/windows/init.c | 2 +- + 18 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/grub-core/disk/host.c b/grub-core/disk/host.c +index c151d225df..f34529f86a 100644 +--- a/grub-core/disk/host.c ++++ b/grub-core/disk/host.c +@@ -20,8 +20,8 @@ + /* When using the disk, make a reference to this module. Otherwise + the user will end up with a useless module :-). */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/kern/emu/argp_common.c b/grub-core/kern/emu/argp_common.c +index 1668858703..8cb4608c3d 100644 +--- a/grub-core/kern/emu/argp_common.c ++++ b/grub-core/kern/emu/argp_common.c +@@ -17,8 +17,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #pragma GCC diagnostic ignored "-Wmissing-prototypes" + #pragma GCC diagnostic ignored "-Wmissing-declarations" +diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c +index 846fe9715e..3e7929cc4a 100644 +--- a/grub-core/kern/emu/main.c ++++ b/grub-core/kern/emu/main.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/aros/config.c b/grub-core/osdep/aros/config.c +index c82d0ea8e7..55f5728efc 100644 +--- a/grub-core/osdep/aros/config.c ++++ b/grub-core/osdep/aros/config.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/basic/emunet.c b/grub-core/osdep/basic/emunet.c +index 6362e5cfbb..dbfd316d61 100644 +--- a/grub-core/osdep/basic/emunet.c ++++ b/grub-core/osdep/basic/emunet.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/basic/init.c b/grub-core/osdep/basic/init.c +index c54c710dbc..b104c7e162 100644 +--- a/grub-core/osdep/basic/init.c ++++ b/grub-core/osdep/basic/init.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/haiku/getroot.c b/grub-core/osdep/haiku/getroot.c +index 4e123c0903..927a1ebc94 100644 +--- a/grub-core/osdep/haiku/getroot.c ++++ b/grub-core/osdep/haiku/getroot.c +@@ -1,5 +1,5 @@ +-#include + #include ++#include + #include + #include + #include +diff --git a/grub-core/osdep/linux/emunet.c b/grub-core/osdep/linux/emunet.c +index 19b188f09e..d5a6417355 100644 +--- a/grub-core/osdep/linux/emunet.c ++++ b/grub-core/osdep/linux/emunet.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c +index 46a881530c..0ce0e309ac 100644 +--- a/grub-core/osdep/unix/config.c ++++ b/grub-core/osdep/unix/config.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/cputime.c b/grub-core/osdep/unix/cputime.c +index cff359a3b9..fb6ff55a1a 100644 +--- a/grub-core/osdep/unix/cputime.c ++++ b/grub-core/osdep/unix/cputime.c +@@ -1,5 +1,5 @@ +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/dl.c b/grub-core/osdep/unix/dl.c +index 562b101a28..99b189bc1c 100644 +--- a/grub-core/osdep/unix/dl.c ++++ b/grub-core/osdep/unix/dl.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/emuconsole.c b/grub-core/osdep/unix/emuconsole.c +index 7308798efe..cac159424d 100644 +--- a/grub-core/osdep/unix/emuconsole.c ++++ b/grub-core/osdep/unix/emuconsole.c +@@ -17,8 +17,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c +index 46d7116c6e..4f436284ce 100644 +--- a/grub-core/osdep/unix/getroot.c ++++ b/grub-core/osdep/unix/getroot.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/config.c b/grub-core/osdep/windows/config.c +index 928ab1a49b..2bb8a2fd88 100644 +--- a/grub-core/osdep/windows/config.c ++++ b/grub-core/osdep/windows/config.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/cputime.c b/grub-core/osdep/windows/cputime.c +index 3568aa2d35..5d06d79dd5 100644 +--- a/grub-core/osdep/windows/cputime.c ++++ b/grub-core/osdep/windows/cputime.c +@@ -1,5 +1,5 @@ +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/dl.c b/grub-core/osdep/windows/dl.c +index eec6a24ad7..8eab7057e4 100644 +--- a/grub-core/osdep/windows/dl.c ++++ b/grub-core/osdep/windows/dl.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c +index 4fb3693cc0..17a44de469 100644 +--- a/grub-core/osdep/windows/emuconsole.c ++++ b/grub-core/osdep/windows/emuconsole.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/init.c b/grub-core/osdep/windows/init.c +index 6297de6326..51a9647dde 100644 +--- a/grub-core/osdep/windows/init.c ++++ b/grub-core/osdep/windows/init.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + #include + #include + #include diff --git a/0204-Drop-gnulib-fix-base64.patch.patch b/0204-Drop-gnulib-fix-base64.patch.patch new file mode 100644 index 0000000..054e476 --- /dev/null +++ b/0204-Drop-gnulib-fix-base64.patch.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Thu, 28 Oct 2021 15:07:50 -0400 +Subject: [PATCH] Drop gnulib fix-base64.patch + +Originally added in 9fbdec2f6b4fa8b549daa4d49134d1fe89d95ef9 and +subsequently modified in 552c9fd08122a3036c724ce96dfe68aa2f75705f, +fix-base64.patch handled two problems we have using gnulib, which are +exerciesd by the base64 module but not directly caused by it. + +First, grub2 defines its own bool type, while gnulib expects the +equivalent of stdbool.h to be present. Rather than patching gnulib, +instead use gnulib's stdbool module to provide a bool type if needed. +(Suggested by Simon Josefsson.) + +Second, our config.h doesn't always inherit config-util.h, which is +where gnulib-related options like _GL_ATTRIBUTE_CONST end up. +fix-base64.h worked around this by defining the attribute away, but this +workaround is better placed in config.h itself, not a gnulib patch. + +Signed-off-by: Robbie Harwood +(cherry picked from commit 54fd1c3301dd15f6b6212c12887265e8a6cbc076) +--- + grub-core/lib/posix_wrap/sys/types.h | 7 +++---- + grub-core/lib/xzembed/xz.h | 5 +---- + bootstrap.conf | 3 ++- + conf/Makefile.extra-dist | 1 - + config.h.in | 4 ++++ + grub-core/lib/gnulib-patches/fix-base64.patch | 21 --------------------- + 6 files changed, 10 insertions(+), 31 deletions(-) + delete mode 100644 grub-core/lib/gnulib-patches/fix-base64.patch + +diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h +index f63412c8da..2f3e865495 100644 +--- a/grub-core/lib/posix_wrap/sys/types.h ++++ b/grub-core/lib/posix_wrap/sys/types.h +@@ -23,11 +23,10 @@ + + #include + ++/* Provided by gnulib if not present. */ ++#include ++ + typedef grub_ssize_t ssize_t; +-#ifndef GRUB_POSIX_BOOL_DEFINED +-typedef enum { false = 0, true = 1 } bool; +-#define GRUB_POSIX_BOOL_DEFINED 1 +-#endif + + typedef grub_uint8_t uint8_t; + typedef grub_uint16_t uint16_t; +diff --git a/grub-core/lib/xzembed/xz.h b/grub-core/lib/xzembed/xz.h +index f7b32d8003..d1417039aa 100644 +--- a/grub-core/lib/xzembed/xz.h ++++ b/grub-core/lib/xzembed/xz.h +@@ -29,10 +29,7 @@ + #include + #include + #include +- +-#ifndef GRUB_POSIX_BOOL_DEFINED +-typedef enum { false = 0, true = 1 } bool; +-#endif ++#include + + /** + * enum xz_ret - Return codes +diff --git a/bootstrap.conf b/bootstrap.conf +index 52d4af44be..645e3a459c 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -35,6 +35,7 @@ gnulib_modules=" + realloc-gnu + regex + save-cwd ++ stdbool + " + + gnulib_tool_option_extras="\ +@@ -79,7 +80,7 @@ cp -a INSTALL INSTALL.grub + + bootstrap_post_import_hook () { + set -e +- for patchname in fix-base64 fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ ++ for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ + fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do + patch -d grub-core/lib/gnulib -p2 \ + < "grub-core/lib/gnulib-patches/$patchname.patch" +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index ad235de7fc..f4791dc6ca 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -31,7 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh + EXTRA_DIST += grub-core/genemuinit.sh + EXTRA_DIST += grub-core/genemuinitheader.sh + +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-base64.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch +diff --git a/config.h.in b/config.h.in +index f2ed0066ec..9c7b4afaaa 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -66,4 +66,8 @@ + + # define _GNU_SOURCE 1 + ++# ifndef _GL_INLINE_HEADER_BEGIN ++# define _GL_ATTRIBUTE_CONST __attribute__ ((const)) ++# endif /* !_GL_INLINE_HEADER_BEGIN */ ++ + #endif +diff --git a/grub-core/lib/gnulib-patches/fix-base64.patch b/grub-core/lib/gnulib-patches/fix-base64.patch +deleted file mode 100644 +index 985db12797..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-base64.patch ++++ /dev/null +@@ -1,21 +0,0 @@ +-diff --git a/lib/base64.h b/lib/base64.h +-index 9cd0183b8..185a2afa1 100644 +---- a/lib/base64.h +-+++ b/lib/base64.h +-@@ -21,8 +21,14 @@ +- /* Get size_t. */ +- # include +- +--/* Get bool. */ +--# include +-+#ifndef GRUB_POSIX_BOOL_DEFINED +-+typedef enum { false = 0, true = 1 } bool; +-+#define GRUB_POSIX_BOOL_DEFINED 1 +-+#endif +-+ +-+#ifndef _GL_ATTRIBUTE_CONST +-+# define _GL_ATTRIBUTE_CONST /* empty */ +-+#endif +- +- # ifdef __cplusplus +- extern "C" { diff --git a/0204-Where-present-ensure-config-util.h-precedes-config.h.patch b/0204-Where-present-ensure-config-util.h-precedes-config.h.patch deleted file mode 100644 index 626c4b4..0000000 --- a/0204-Where-present-ensure-config-util.h-precedes-config.h.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Tue, 22 Feb 2022 16:57:54 -0500 -Subject: [PATCH] Where present, ensure config-util.h precedes config.h - -gnulib defines go in config-util.h, and we need to know whether to -provide duplicates in config.h or not. - -Signed-off-by: Robbie Harwood -(cherry picked from commit 46e82b28e1a75703d0424c7e13d009171310c6cd) -[rharwood: gensymlist isn't part of tarballs] ---- - grub-core/disk/host.c | 2 +- - grub-core/kern/emu/argp_common.c | 2 +- - grub-core/kern/emu/main.c | 2 +- - grub-core/osdep/aros/config.c | 2 +- - grub-core/osdep/basic/emunet.c | 2 +- - grub-core/osdep/basic/init.c | 2 +- - grub-core/osdep/haiku/getroot.c | 2 +- - grub-core/osdep/linux/emunet.c | 2 +- - grub-core/osdep/unix/config.c | 2 +- - grub-core/osdep/unix/cputime.c | 2 +- - grub-core/osdep/unix/dl.c | 2 +- - grub-core/osdep/unix/emuconsole.c | 2 +- - grub-core/osdep/unix/getroot.c | 2 +- - grub-core/osdep/windows/config.c | 2 +- - grub-core/osdep/windows/cputime.c | 2 +- - grub-core/osdep/windows/dl.c | 2 +- - grub-core/osdep/windows/emuconsole.c | 2 +- - grub-core/osdep/windows/init.c | 2 +- - 18 files changed, 18 insertions(+), 18 deletions(-) - -diff --git a/grub-core/disk/host.c b/grub-core/disk/host.c -index c151d225df..f34529f86a 100644 ---- a/grub-core/disk/host.c -+++ b/grub-core/disk/host.c -@@ -20,8 +20,8 @@ - /* When using the disk, make a reference to this module. Otherwise - the user will end up with a useless module :-). */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/kern/emu/argp_common.c b/grub-core/kern/emu/argp_common.c -index 1668858703..8cb4608c3d 100644 ---- a/grub-core/kern/emu/argp_common.c -+++ b/grub-core/kern/emu/argp_common.c -@@ -17,8 +17,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #pragma GCC diagnostic ignored "-Wmissing-prototypes" - #pragma GCC diagnostic ignored "-Wmissing-declarations" -diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c -index 846fe9715e..3e7929cc4a 100644 ---- a/grub-core/kern/emu/main.c -+++ b/grub-core/kern/emu/main.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/aros/config.c b/grub-core/osdep/aros/config.c -index c82d0ea8e7..55f5728efc 100644 ---- a/grub-core/osdep/aros/config.c -+++ b/grub-core/osdep/aros/config.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/basic/emunet.c b/grub-core/osdep/basic/emunet.c -index 6362e5cfbb..dbfd316d61 100644 ---- a/grub-core/osdep/basic/emunet.c -+++ b/grub-core/osdep/basic/emunet.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/basic/init.c b/grub-core/osdep/basic/init.c -index c54c710dbc..b104c7e162 100644 ---- a/grub-core/osdep/basic/init.c -+++ b/grub-core/osdep/basic/init.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/haiku/getroot.c b/grub-core/osdep/haiku/getroot.c -index 4e123c0903..927a1ebc94 100644 ---- a/grub-core/osdep/haiku/getroot.c -+++ b/grub-core/osdep/haiku/getroot.c -@@ -1,5 +1,5 @@ --#include - #include -+#include - #include - #include - #include -diff --git a/grub-core/osdep/linux/emunet.c b/grub-core/osdep/linux/emunet.c -index 19b188f09e..d5a6417355 100644 ---- a/grub-core/osdep/linux/emunet.c -+++ b/grub-core/osdep/linux/emunet.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c -index 46a881530c..0ce0e309ac 100644 ---- a/grub-core/osdep/unix/config.c -+++ b/grub-core/osdep/unix/config.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/unix/cputime.c b/grub-core/osdep/unix/cputime.c -index cff359a3b9..fb6ff55a1a 100644 ---- a/grub-core/osdep/unix/cputime.c -+++ b/grub-core/osdep/unix/cputime.c -@@ -1,5 +1,5 @@ --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/unix/dl.c b/grub-core/osdep/unix/dl.c -index 562b101a28..99b189bc1c 100644 ---- a/grub-core/osdep/unix/dl.c -+++ b/grub-core/osdep/unix/dl.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/unix/emuconsole.c b/grub-core/osdep/unix/emuconsole.c -index 7308798efe..cac159424d 100644 ---- a/grub-core/osdep/unix/emuconsole.c -+++ b/grub-core/osdep/unix/emuconsole.c -@@ -17,8 +17,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c -index 46d7116c6e..4f436284ce 100644 ---- a/grub-core/osdep/unix/getroot.c -+++ b/grub-core/osdep/unix/getroot.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/windows/config.c b/grub-core/osdep/windows/config.c -index 928ab1a49b..2bb8a2fd88 100644 ---- a/grub-core/osdep/windows/config.c -+++ b/grub-core/osdep/windows/config.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/windows/cputime.c b/grub-core/osdep/windows/cputime.c -index 3568aa2d35..5d06d79dd5 100644 ---- a/grub-core/osdep/windows/cputime.c -+++ b/grub-core/osdep/windows/cputime.c -@@ -1,5 +1,5 @@ --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/windows/dl.c b/grub-core/osdep/windows/dl.c -index eec6a24ad7..8eab7057e4 100644 ---- a/grub-core/osdep/windows/dl.c -+++ b/grub-core/osdep/windows/dl.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c -index 4fb3693cc0..17a44de469 100644 ---- a/grub-core/osdep/windows/emuconsole.c -+++ b/grub-core/osdep/windows/emuconsole.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - - #include - #include -diff --git a/grub-core/osdep/windows/init.c b/grub-core/osdep/windows/init.c -index 6297de6326..51a9647dde 100644 ---- a/grub-core/osdep/windows/init.c -+++ b/grub-core/osdep/windows/init.c -@@ -16,8 +16,8 @@ - * along with GRUB. If not, see . - */ - --#include - #include -+#include - #include - #include - #include diff --git a/0205-Drop-gnulib-fix-base64.patch.patch b/0205-Drop-gnulib-fix-base64.patch.patch deleted file mode 100644 index 054e476..0000000 --- a/0205-Drop-gnulib-fix-base64.patch.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Thu, 28 Oct 2021 15:07:50 -0400 -Subject: [PATCH] Drop gnulib fix-base64.patch - -Originally added in 9fbdec2f6b4fa8b549daa4d49134d1fe89d95ef9 and -subsequently modified in 552c9fd08122a3036c724ce96dfe68aa2f75705f, -fix-base64.patch handled two problems we have using gnulib, which are -exerciesd by the base64 module but not directly caused by it. - -First, grub2 defines its own bool type, while gnulib expects the -equivalent of stdbool.h to be present. Rather than patching gnulib, -instead use gnulib's stdbool module to provide a bool type if needed. -(Suggested by Simon Josefsson.) - -Second, our config.h doesn't always inherit config-util.h, which is -where gnulib-related options like _GL_ATTRIBUTE_CONST end up. -fix-base64.h worked around this by defining the attribute away, but this -workaround is better placed in config.h itself, not a gnulib patch. - -Signed-off-by: Robbie Harwood -(cherry picked from commit 54fd1c3301dd15f6b6212c12887265e8a6cbc076) ---- - grub-core/lib/posix_wrap/sys/types.h | 7 +++---- - grub-core/lib/xzembed/xz.h | 5 +---- - bootstrap.conf | 3 ++- - conf/Makefile.extra-dist | 1 - - config.h.in | 4 ++++ - grub-core/lib/gnulib-patches/fix-base64.patch | 21 --------------------- - 6 files changed, 10 insertions(+), 31 deletions(-) - delete mode 100644 grub-core/lib/gnulib-patches/fix-base64.patch - -diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h -index f63412c8da..2f3e865495 100644 ---- a/grub-core/lib/posix_wrap/sys/types.h -+++ b/grub-core/lib/posix_wrap/sys/types.h -@@ -23,11 +23,10 @@ - - #include - -+/* Provided by gnulib if not present. */ -+#include -+ - typedef grub_ssize_t ssize_t; --#ifndef GRUB_POSIX_BOOL_DEFINED --typedef enum { false = 0, true = 1 } bool; --#define GRUB_POSIX_BOOL_DEFINED 1 --#endif - - typedef grub_uint8_t uint8_t; - typedef grub_uint16_t uint16_t; -diff --git a/grub-core/lib/xzembed/xz.h b/grub-core/lib/xzembed/xz.h -index f7b32d8003..d1417039aa 100644 ---- a/grub-core/lib/xzembed/xz.h -+++ b/grub-core/lib/xzembed/xz.h -@@ -29,10 +29,7 @@ - #include - #include - #include -- --#ifndef GRUB_POSIX_BOOL_DEFINED --typedef enum { false = 0, true = 1 } bool; --#endif -+#include - - /** - * enum xz_ret - Return codes -diff --git a/bootstrap.conf b/bootstrap.conf -index 52d4af44be..645e3a459c 100644 ---- a/bootstrap.conf -+++ b/bootstrap.conf -@@ -35,6 +35,7 @@ gnulib_modules=" - realloc-gnu - regex - save-cwd -+ stdbool - " - - gnulib_tool_option_extras="\ -@@ -79,7 +80,7 @@ cp -a INSTALL INSTALL.grub - - bootstrap_post_import_hook () { - set -e -- for patchname in fix-base64 fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ -+ for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ - fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do - patch -d grub-core/lib/gnulib -p2 \ - < "grub-core/lib/gnulib-patches/$patchname.patch" -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index ad235de7fc..f4791dc6ca 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -31,7 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh - EXTRA_DIST += grub-core/genemuinit.sh - EXTRA_DIST += grub-core/genemuinitheader.sh - --EXTRA_DIST += grub-core/lib/gnulib-patches/fix-base64.patch - EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch - EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch - EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch -diff --git a/config.h.in b/config.h.in -index f2ed0066ec..9c7b4afaaa 100644 ---- a/config.h.in -+++ b/config.h.in -@@ -66,4 +66,8 @@ - - # define _GNU_SOURCE 1 - -+# ifndef _GL_INLINE_HEADER_BEGIN -+# define _GL_ATTRIBUTE_CONST __attribute__ ((const)) -+# endif /* !_GL_INLINE_HEADER_BEGIN */ -+ - #endif -diff --git a/grub-core/lib/gnulib-patches/fix-base64.patch b/grub-core/lib/gnulib-patches/fix-base64.patch -deleted file mode 100644 -index 985db12797..0000000000 ---- a/grub-core/lib/gnulib-patches/fix-base64.patch -+++ /dev/null -@@ -1,21 +0,0 @@ --diff --git a/lib/base64.h b/lib/base64.h --index 9cd0183b8..185a2afa1 100644 ----- a/lib/base64.h --+++ b/lib/base64.h --@@ -21,8 +21,14 @@ -- /* Get size_t. */ -- # include -- ---/* Get bool. */ ---# include --+#ifndef GRUB_POSIX_BOOL_DEFINED --+typedef enum { false = 0, true = 1 } bool; --+#define GRUB_POSIX_BOOL_DEFINED 1 --+#endif --+ --+#ifndef _GL_ATTRIBUTE_CONST --+# define _GL_ATTRIBUTE_CONST /* empty */ --+#endif -- -- # ifdef __cplusplus -- extern "C" { diff --git a/0205-Drop-gnulib-no-abort.patch.patch b/0205-Drop-gnulib-no-abort.patch.patch new file mode 100644 index 0000000..a12789f --- /dev/null +++ b/0205-Drop-gnulib-no-abort.patch.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 5 Jan 2022 16:42:11 -0500 +Subject: [PATCH] Drop gnulib no-abort.patch + +Originally added in db7337a3d353a817ffe9eb4a3702120527100be9, this +patched out all relevant invocations of abort() in gnulib. While it was +not documented why at the time, testing suggests that there's no abort() +implementation available for gnulib to use. + +gnulib's position is that the use of abort() is correct here, since it +happens when input violates a "shall" from POSIX. Additionally, the +code in question is probably not reachable. Since abort() is more +friendly to user-space, they prefer to make no change, so we can just +carry a define instead. (Suggested by Paul Eggert.) + +Signed-off-by: Robbie Harwood +(cherry picked from commit 5137c8eb3ec11c3217acea1a93a3f88f3fa4cbca) +--- + bootstrap.conf | 2 +- + conf/Makefile.extra-dist | 1 - + config.h.in | 3 +++ + grub-core/lib/gnulib-patches/no-abort.patch | 26 -------------------------- + 4 files changed, 4 insertions(+), 28 deletions(-) + delete mode 100644 grub-core/lib/gnulib-patches/no-abort.patch + +diff --git a/bootstrap.conf b/bootstrap.conf +index 645e3a459c..71ce943c7d 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -81,7 +81,7 @@ cp -a INSTALL INSTALL.grub + bootstrap_post_import_hook () { + set -e + for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ +- fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do ++ fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do + patch -d grub-core/lib/gnulib -p2 \ + < "grub-core/lib/gnulib-patches/$patchname.patch" + done +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index f4791dc6ca..5eef708338 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -38,7 +38,6 @@ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/no-abort.patch + + EXTRA_DIST += grub-core/lib/libgcrypt + EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic +diff --git a/config.h.in b/config.h.in +index 9c7b4afaaa..c3134309c6 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -68,6 +68,9 @@ + + # ifndef _GL_INLINE_HEADER_BEGIN + # define _GL_ATTRIBUTE_CONST __attribute__ ((const)) ++ ++/* We don't have an abort() for gnulib to call in regexp. */ ++# define abort __builtin_unreachable + # endif /* !_GL_INLINE_HEADER_BEGIN */ + + #endif +diff --git a/grub-core/lib/gnulib-patches/no-abort.patch b/grub-core/lib/gnulib-patches/no-abort.patch +deleted file mode 100644 +index e469c4762e..0000000000 +--- a/grub-core/lib/gnulib-patches/no-abort.patch ++++ /dev/null +@@ -1,26 +0,0 @@ +-diff --git a/lib/regcomp.c b/lib/regcomp.c +-index cc85f35ac..de45ebb5c 100644 +---- a/lib/regcomp.c +-+++ b/lib/regcomp.c +-@@ -528,9 +528,9 @@ regerror (int errcode, const regex_t *__restrict preg, char *__restrict errbuf, +- to this routine. If we are given anything else, or if other regex +- code generates an invalid error code, then the program has a bug. +- Dump core so we can fix it. */ +-- abort (); +-- +-- msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); +-+ msg = gettext ("unknown regexp error"); +-+ else +-+ msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); +- +- msg_size = strlen (msg) + 1; /* Includes the null. */ +- +-@@ -1136,7 +1136,7 @@ optimize_utf8 (re_dfa_t *dfa) +- } +- break; +- default: +-- abort (); +-+ break; +- } +- +- if (mb_chars || has_period) diff --git a/0206-Drop-gnulib-no-abort.patch.patch b/0206-Drop-gnulib-no-abort.patch.patch deleted file mode 100644 index a12789f..0000000 --- a/0206-Drop-gnulib-no-abort.patch.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Wed, 5 Jan 2022 16:42:11 -0500 -Subject: [PATCH] Drop gnulib no-abort.patch - -Originally added in db7337a3d353a817ffe9eb4a3702120527100be9, this -patched out all relevant invocations of abort() in gnulib. While it was -not documented why at the time, testing suggests that there's no abort() -implementation available for gnulib to use. - -gnulib's position is that the use of abort() is correct here, since it -happens when input violates a "shall" from POSIX. Additionally, the -code in question is probably not reachable. Since abort() is more -friendly to user-space, they prefer to make no change, so we can just -carry a define instead. (Suggested by Paul Eggert.) - -Signed-off-by: Robbie Harwood -(cherry picked from commit 5137c8eb3ec11c3217acea1a93a3f88f3fa4cbca) ---- - bootstrap.conf | 2 +- - conf/Makefile.extra-dist | 1 - - config.h.in | 3 +++ - grub-core/lib/gnulib-patches/no-abort.patch | 26 -------------------------- - 4 files changed, 4 insertions(+), 28 deletions(-) - delete mode 100644 grub-core/lib/gnulib-patches/no-abort.patch - -diff --git a/bootstrap.conf b/bootstrap.conf -index 645e3a459c..71ce943c7d 100644 ---- a/bootstrap.conf -+++ b/bootstrap.conf -@@ -81,7 +81,7 @@ cp -a INSTALL INSTALL.grub - bootstrap_post_import_hook () { - set -e - for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ -- fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do -+ fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do - patch -d grub-core/lib/gnulib -p2 \ - < "grub-core/lib/gnulib-patches/$patchname.patch" - done -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index f4791dc6ca..5eef708338 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -38,7 +38,6 @@ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch - EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch - EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch - EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch --EXTRA_DIST += grub-core/lib/gnulib-patches/no-abort.patch - - EXTRA_DIST += grub-core/lib/libgcrypt - EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic -diff --git a/config.h.in b/config.h.in -index 9c7b4afaaa..c3134309c6 100644 ---- a/config.h.in -+++ b/config.h.in -@@ -68,6 +68,9 @@ - - # ifndef _GL_INLINE_HEADER_BEGIN - # define _GL_ATTRIBUTE_CONST __attribute__ ((const)) -+ -+/* We don't have an abort() for gnulib to call in regexp. */ -+# define abort __builtin_unreachable - # endif /* !_GL_INLINE_HEADER_BEGIN */ - - #endif -diff --git a/grub-core/lib/gnulib-patches/no-abort.patch b/grub-core/lib/gnulib-patches/no-abort.patch -deleted file mode 100644 -index e469c4762e..0000000000 ---- a/grub-core/lib/gnulib-patches/no-abort.patch -+++ /dev/null -@@ -1,26 +0,0 @@ --diff --git a/lib/regcomp.c b/lib/regcomp.c --index cc85f35ac..de45ebb5c 100644 ----- a/lib/regcomp.c --+++ b/lib/regcomp.c --@@ -528,9 +528,9 @@ regerror (int errcode, const regex_t *__restrict preg, char *__restrict errbuf, -- to this routine. If we are given anything else, or if other regex -- code generates an invalid error code, then the program has a bug. -- Dump core so we can fix it. */ --- abort (); --- --- msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); --+ msg = gettext ("unknown regexp error"); --+ else --+ msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); -- -- msg_size = strlen (msg) + 1; /* Includes the null. */ -- --@@ -1136,7 +1136,7 @@ optimize_utf8 (re_dfa_t *dfa) -- } -- break; -- default: --- abort (); --+ break; -- } -- -- if (mb_chars || has_period) diff --git a/0206-Update-gnulib-version-and-drop-most-gnulib-patches.patch b/0206-Update-gnulib-version-and-drop-most-gnulib-patches.patch new file mode 100644 index 0000000..f9fa207 --- /dev/null +++ b/0206-Update-gnulib-version-and-drop-most-gnulib-patches.patch @@ -0,0 +1,832 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 15 Dec 2021 15:07:50 -0500 +Subject: [PATCH] Update gnulib version and drop most gnulib patches + +In addition to the changes carried in our gnulib patches, several +Coverity and code hygiene fixes that were previously downstream are also +included in this 3-year gnulib increment. + +Unfortunately, fix-width.patch is retained. + +Bump minimum autoconf version from 2.63 to 2.64 and automake from 1.11 +to 1.14, as required by gnulib. + +Sync bootstrap script itself with gnulib. + +Update regexp module for new dynarray dependency. + +Fix various new warnings. + +Signed-off-by: Robbie Harwood +(cherry picked from commit deb18ff931c3133c2aa536a92bd92e50d6615303) +[rharwood: backport around requirements in INSTALL] +--- + configure.ac | 2 +- + grub-core/Makefile.core.def | 3 + + grub-core/disk/luks2.c | 4 +- + grub-core/lib/posix_wrap/limits.h | 6 +- + include/grub/compiler.h | 4 +- + include/grub/list.h | 2 +- + INSTALL | 2 +- + bootstrap | 291 ++++++++++++--------- + bootstrap.conf | 22 +- + conf/Makefile.extra-dist | 6 - + config.h.in | 68 +++++ + grub-core/lib/gnulib-patches/fix-null-deref.patch | 13 - + .../lib/gnulib-patches/fix-null-state-deref.patch | 12 - + .../gnulib-patches/fix-regcomp-uninit-token.patch | 15 -- + .../gnulib-patches/fix-regexec-null-deref.patch | 12 - + .../lib/gnulib-patches/fix-uninit-structure.patch | 11 - + .../lib/gnulib-patches/fix-unused-value.patch | 14 - + 17 files changed, 262 insertions(+), 225 deletions(-) + delete mode 100644 grub-core/lib/gnulib-patches/fix-null-deref.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-null-state-deref.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-uninit-structure.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-unused-value.patch + +diff --git a/configure.ac b/configure.ac +index 40c4338bce..79f45ef1e1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -49,7 +49,7 @@ AC_CANONICAL_TARGET + program_prefix="${save_program_prefix}" + + AM_INIT_AUTOMAKE([1.11]) +-AC_PREREQ(2.63) ++AC_PREREQ(2.64) + AC_CONFIG_SRCDIR([include/grub/dl.h]) + AC_CONFIG_HEADER([config-util.h]) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 6b00eb5557..39233096f2 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -762,6 +762,9 @@ module = { + name = regexp; + common = commands/regexp.c; + common = commands/wildcard.c; ++ common = lib/gnulib/malloc/dynarray_finalize.c; ++ common = lib/gnulib/malloc/dynarray_emplace_enlarge.c; ++ common = lib/gnulib/malloc/dynarray_resize.c; + common = lib/gnulib/regex.c; + cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; + cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 371a53b837..c917a5f91e 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -389,7 +389,7 @@ luks2_verify_key (grub_luks2_digest_t *d, grub_uint8_t *candidate_key, + { + grub_uint8_t candidate_digest[GRUB_CRYPTODISK_MAX_KEYLEN]; + grub_uint8_t digest[GRUB_CRYPTODISK_MAX_KEYLEN], salt[GRUB_CRYPTODISK_MAX_KEYLEN]; +- grub_size_t saltlen = sizeof (salt), digestlen = sizeof (digest); ++ idx_t saltlen = sizeof (salt), digestlen = sizeof (digest); + const gcry_md_spec_t *hash; + gcry_err_code_t gcry_ret; + +@@ -428,7 +428,7 @@ luks2_decrypt_key (grub_uint8_t *out_key, + grub_uint8_t area_key[GRUB_CRYPTODISK_MAX_KEYLEN]; + grub_uint8_t salt[GRUB_CRYPTODISK_MAX_KEYLEN]; + grub_uint8_t *split_key = NULL; +- grub_size_t saltlen = sizeof (salt); ++ idx_t saltlen = sizeof (salt); + char cipher[32], *p; + const gcry_md_spec_t *hash; + gcry_err_code_t gcry_ret; +diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h +index 591dbf3289..4be7b40806 100644 +--- a/grub-core/lib/posix_wrap/limits.h ++++ b/grub-core/lib/posix_wrap/limits.h +@@ -25,7 +25,11 @@ + #define USHRT_MAX GRUB_USHRT_MAX + #define UINT_MAX GRUB_UINT_MAX + #define ULONG_MAX GRUB_ULONG_MAX +-#define SIZE_MAX GRUB_SIZE_MAX ++ ++/* gnulib also defines this type */ ++#ifndef SIZE_MAX ++# define SIZE_MAX GRUB_SIZE_MAX ++#endif + + #define SCHAR_MIN GRUB_SCHAR_MIN + #define SCHAR_MAX GRUB_SCHAR_MAX +diff --git a/include/grub/compiler.h b/include/grub/compiler.h +index ebafec6895..441a9eca07 100644 +--- a/include/grub/compiler.h ++++ b/include/grub/compiler.h +@@ -30,10 +30,10 @@ + + /* Does this compiler support compile-time error attributes? */ + #if GNUC_PREREQ(4,3) +-# define ATTRIBUTE_ERROR(msg) \ ++# define GRUB_ATTRIBUTE_ERROR(msg) \ + __attribute__ ((__error__ (msg))) + #else +-# define ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) ++# define GRUB_ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) + #endif + + #if GNUC_PREREQ(4,4) +diff --git a/include/grub/list.h b/include/grub/list.h +index b13acb9624..21f4b4b44a 100644 +--- a/include/grub/list.h ++++ b/include/grub/list.h +@@ -40,7 +40,7 @@ void EXPORT_FUNC(grub_list_remove) (grub_list_t item); + + static inline void * + grub_bad_type_cast_real (int line, const char *file) +- ATTRIBUTE_ERROR ("bad type cast between incompatible grub types"); ++ GRUB_ATTRIBUTE_ERROR ("bad type cast between incompatible grub types"); + + static inline void * + grub_bad_type_cast_real (int line, const char *file) +diff --git a/INSTALL b/INSTALL +index 79a0af7d93..ee9f536f76 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -42,7 +42,7 @@ If you use a development snapshot or want to hack on GRUB you may + need the following. + + * Python 2.6 or later +-* Autoconf 2.63 or later ++* Autoconf 2.64 or later + * Automake 1.11 or later + + Prerequisites for make-check: +diff --git a/bootstrap b/bootstrap +index 5b08e7e2d4..dc2238f4ad 100755 +--- a/bootstrap ++++ b/bootstrap +@@ -1,10 +1,10 @@ + #! /bin/sh + # Print a version string. +-scriptversion=2019-01-04.17; # UTC ++scriptversion=2022-01-26.05; # UTC + + # Bootstrap this package from checked-out sources. + +-# Copyright (C) 2003-2019 Free Software Foundation, Inc. ++# Copyright (C) 2003-2022 Free Software Foundation, Inc. + + # 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 +@@ -47,7 +47,7 @@ PERL="${PERL-perl}" + + me=$0 + +-default_gnulib_url=git://git.sv.gnu.org/gnulib ++default_gnulib_url=https://git.savannah.gnu.org/git/gnulib.git + + usage() { + cat </dev/null) ++if test -z "$package"; then ++ package=$(sed -n "$extract_package_name" configure.ac) \ ++ || die 'cannot find package name in configure.ac' ++fi + gnulib_name=lib$package + + build_aux=build-aux +@@ -290,6 +313,116 @@ find_tool () + eval "export $find_tool_envvar" + } + ++# Strip blank and comment lines to leave significant entries. ++gitignore_entries() { ++ sed '/^#/d; /^$/d' "$@" ++} ++ ++# If $STR is not already on a line by itself in $FILE, insert it at the start. ++# Entries are inserted at the start of the ignore list to ensure existing ++# entries starting with ! are not overridden. Such entries support ++# whitelisting exceptions after a more generic blacklist pattern. ++insert_if_absent() { ++ file=$1 ++ str=$2 ++ test -f $file || touch $file ++ test -r $file || die "Error: failed to read ignore file: $file" ++ duplicate_entries=$(gitignore_entries $file | sort | uniq -d) ++ if [ "$duplicate_entries" ] ; then ++ die "Error: Duplicate entries in $file: " $duplicate_entries ++ fi ++ linesold=$(gitignore_entries $file | wc -l) ++ linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l) ++ if [ $linesold != $linesnew ] ; then ++ { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \ ++ || die "insert_if_absent $file $str: failed" ++ fi ++} ++ ++# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with ++# insert_if_absent. ++insert_vc_ignore() { ++ vc_ignore_file="$1" ++ pattern="$2" ++ case $vc_ignore_file in ++ *.gitignore) ++ # A .gitignore entry that does not start with '/' applies ++ # recursively to subdirectories, so prepend '/' to every ++ # .gitignore entry. ++ pattern=$(echo "$pattern" | sed s,^,/,);; ++ esac ++ insert_if_absent "$vc_ignore_file" "$pattern" ++} ++ ++symlink_to_dir() ++{ ++ src=$1/$2 ++ dst=${3-$2} ++ ++ test -f "$src" && { ++ ++ # If the destination directory doesn't exist, create it. ++ # This is required at least for "lib/uniwidth/cjk.h". ++ dst_dir=$(dirname "$dst") ++ if ! test -d "$dst_dir"; then ++ mkdir -p "$dst_dir" ++ ++ # If we've just created a directory like lib/uniwidth, ++ # tell version control system(s) it's ignorable. ++ # FIXME: for now, this does only one level ++ parent=$(dirname "$dst_dir") ++ for dot_ig in x $vc_ignore; do ++ test $dot_ig = x && continue ++ ig=$parent/$dot_ig ++ insert_vc_ignore $ig "${dst_dir##*/}" ++ done ++ fi ++ ++ if $copy; then ++ { ++ test ! -h "$dst" || { ++ echo "$me: rm -f $dst" && ++ rm -f "$dst" ++ } ++ } && ++ test -f "$dst" && ++ cmp -s "$src" "$dst" || { ++ echo "$me: cp -fp $src $dst" && ++ cp -fp "$src" "$dst" ++ } ++ else ++ # Leave any existing symlink alone, if it already points to the source, ++ # so that broken build tools that care about symlink times ++ # aren't confused into doing unnecessary builds. Conversely, if the ++ # existing symlink's timestamp is older than the source, make it afresh, ++ # so that broken tools aren't confused into skipping needed builds. See ++ # . ++ test -h "$dst" && ++ src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 && ++ dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 && ++ test "$src_i" = "$dst_i" && ++ both_ls=$(ls -dt "$src" "$dst") && ++ test "X$both_ls" = "X$dst$nl$src" || { ++ dot_dots= ++ case $src in ++ /*) ;; ++ *) ++ case /$dst/ in ++ *//* | */../* | */./* | /*/*/*/*/*/) ++ die "invalid symlink calculation: $src -> $dst";; ++ /*/*/*/*/) dot_dots=../../../;; ++ /*/*/*/) dot_dots=../../;; ++ /*/*/) dot_dots=../;; ++ esac;; ++ esac ++ ++ echo "$me: ln -fs $dot_dots$src $dst" && ++ ln -fs "$dot_dots$src" "$dst" ++ } ++ fi ++ } ++} ++ + # Override the default configuration, if necessary. + # Make sure that bootstrap.conf is sourced from the current directory + # if we were invoked as "sh bootstrap". +@@ -320,6 +453,12 @@ do + --help) + usage + exit;; ++ --version) ++ set -e ++ echo "bootstrap $scriptversion" ++ echo "$copyright" ++ exit 0 ++ ;; + --gnulib-srcdir=*) + GNULIB_SRCDIR=${option#--gnulib-srcdir=};; + --skip-po) +@@ -335,7 +474,7 @@ do + --no-git) + use_git=false;; + *) +- die "$option: unknown option";; ++ bootstrap_option_hook $option || die "$option: unknown option";; + esac + done + +@@ -346,47 +485,6 @@ if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then + die "Bootstrapping from a non-checked-out distribution is risky." + fi + +-# Strip blank and comment lines to leave significant entries. +-gitignore_entries() { +- sed '/^#/d; /^$/d' "$@" +-} +- +-# If $STR is not already on a line by itself in $FILE, insert it at the start. +-# Entries are inserted at the start of the ignore list to ensure existing +-# entries starting with ! are not overridden. Such entries support +-# whitelisting exceptions after a more generic blacklist pattern. +-insert_if_absent() { +- file=$1 +- str=$2 +- test -f $file || touch $file +- test -r $file || die "Error: failed to read ignore file: $file" +- duplicate_entries=$(gitignore_entries $file | sort | uniq -d) +- if [ "$duplicate_entries" ] ; then +- die "Error: Duplicate entries in $file: " $duplicate_entries +- fi +- linesold=$(gitignore_entries $file | wc -l) +- linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l) +- if [ $linesold != $linesnew ] ; then +- { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \ +- || die "insert_if_absent $file $str: failed" +- fi +-} +- +-# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with +-# insert_if_absent. +-insert_vc_ignore() { +- vc_ignore_file="$1" +- pattern="$2" +- case $vc_ignore_file in +- *.gitignore) +- # A .gitignore entry that does not start with '/' applies +- # recursively to subdirectories, so prepend '/' to every +- # .gitignore entry. +- pattern=$(echo "$pattern" | sed s,^,/,);; +- esac +- insert_if_absent "$vc_ignore_file" "$pattern" +-} +- + # Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac. + found_aux_dir=no + grep '^[ ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \ +@@ -665,9 +763,25 @@ if $use_gnulib; then + shallow= + if test -z "$GNULIB_REVISION"; then + git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' ++ git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \ ++ || cleanup_gnulib ++ else ++ git fetch -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' ++ mkdir -p "$gnulib_path" ++ # Only want a shallow checkout of $GNULIB_REVISION, but git does not ++ # support cloning by commit hash. So attempt a shallow fetch by commit ++ # hash to minimize the amount of data downloaded and changes needed to ++ # be processed, which can drastically reduce download and processing ++ # time for checkout. If the fetch by commit fails, a shallow fetch can ++ # not be performed because we do not know what the depth of the commit ++ # is without fetching all commits. So fallback to fetching all commits. ++ git -C "$gnulib_path" init ++ git -C "$gnulib_path" remote add origin ${GNULIB_URL:-$default_gnulib_url} ++ git -C "$gnulib_path" fetch $shallow origin "$GNULIB_REVISION" \ ++ || git -C "$gnulib_path" fetch origin \ ++ || cleanup_gnulib ++ git -C "$gnulib_path" reset --hard FETCH_HEAD + fi +- git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \ +- || cleanup_gnulib + + trap - 1 2 13 15 + fi +@@ -784,75 +898,6 @@ case $SKIP_PO in + fi;; + esac + +-symlink_to_dir() +-{ +- src=$1/$2 +- dst=${3-$2} +- +- test -f "$src" && { +- +- # If the destination directory doesn't exist, create it. +- # This is required at least for "lib/uniwidth/cjk.h". +- dst_dir=$(dirname "$dst") +- if ! test -d "$dst_dir"; then +- mkdir -p "$dst_dir" +- +- # If we've just created a directory like lib/uniwidth, +- # tell version control system(s) it's ignorable. +- # FIXME: for now, this does only one level +- parent=$(dirname "$dst_dir") +- for dot_ig in x $vc_ignore; do +- test $dot_ig = x && continue +- ig=$parent/$dot_ig +- insert_vc_ignore $ig "${dst_dir##*/}" +- done +- fi +- +- if $copy; then +- { +- test ! -h "$dst" || { +- echo "$me: rm -f $dst" && +- rm -f "$dst" +- } +- } && +- test -f "$dst" && +- cmp -s "$src" "$dst" || { +- echo "$me: cp -fp $src $dst" && +- cp -fp "$src" "$dst" +- } +- else +- # Leave any existing symlink alone, if it already points to the source, +- # so that broken build tools that care about symlink times +- # aren't confused into doing unnecessary builds. Conversely, if the +- # existing symlink's timestamp is older than the source, make it afresh, +- # so that broken tools aren't confused into skipping needed builds. See +- # . +- test -h "$dst" && +- src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 && +- dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 && +- test "$src_i" = "$dst_i" && +- both_ls=$(ls -dt "$src" "$dst") && +- test "X$both_ls" = "X$dst$nl$src" || { +- dot_dots= +- case $src in +- /*) ;; +- *) +- case /$dst/ in +- *//* | */../* | */./* | /*/*/*/*/*/) +- die "invalid symlink calculation: $src -> $dst";; +- /*/*/*/*/) dot_dots=../../../;; +- /*/*/*/) dot_dots=../../;; +- /*/*/) dot_dots=../;; +- esac;; +- esac +- +- echo "$me: ln -fs $dot_dots$src $dst" && +- ln -fs "$dot_dots$src" "$dst" +- } +- fi +- } +-} +- + version_controlled_file() { + parent=$1 + file=$2 +@@ -970,7 +1015,7 @@ bootstrap_post_import_hook \ + # Uninitialized submodules are listed with an initial dash. + if $use_git && git submodule | grep '^-' >/dev/null; then + die "some git submodules are not initialized. " \ +- "Run 'git submodule init' and bootstrap again." ++ "Run 'git submodule update --init' and bootstrap again." + fi + + # Remove any dangling symlink matching "*.m4" or "*.[ch]" in some +@@ -1064,7 +1109,7 @@ bootstrap_epilogue + + echo "$0: done. Now you can run './configure'." + +-# Local variables: ++# Local Variables: + # eval: (add-hook 'before-save-hook 'time-stamp) + # time-stamp-start: "scriptversion=" + # time-stamp-format: "%:y-%02m-%02d.%02H" +diff --git a/bootstrap.conf b/bootstrap.conf +index 71ce943c7d..e4e5f3750a 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -1,6 +1,6 @@ + # Bootstrap configuration. + +-# Copyright (C) 2006-2019 Free Software Foundation, Inc. ++# Copyright (C) 2006-2022 Free Software Foundation, Inc. + + # 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 +@@ -16,11 +16,10 @@ + # along with this program. If not, see . + + +-GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263 ++GNULIB_REVISION=9f48fb992a3d7e96610c4ce8be969cff2d61a01b + + # gnulib modules used by this package. +-# mbswidth is used by gnulib-fix-width.diff's changes to argp rather than +-# directly. ++# mbswidth is used by fix-width.diff's changes to argp rather than directly. + gnulib_modules=" + argp + base64 +@@ -67,8 +66,8 @@ SKIP_PO=t + + # Build prerequisites + buildreq="\ +-autoconf 2.63 +-automake 1.11 ++autoconf 2.64 ++automake 1.14 + gettext 0.18.3 + git 1.5.5 + tar - +@@ -80,11 +79,12 @@ cp -a INSTALL INSTALL.grub + + bootstrap_post_import_hook () { + set -e +- for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ +- fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do +- patch -d grub-core/lib/gnulib -p2 \ +- < "grub-core/lib/gnulib-patches/$patchname.patch" +- done ++ ++ # Instead of patching our gnulib and therefore maintaining a fork, submit ++ # changes to gnulib and update the hash above when they've merged. Do not ++ # add new patches here. ++ patch -d grub-core/lib/gnulib -p2 < grub-core/lib/gnulib-patches/fix-width.patch ++ + for patchname in \ + 0001-Support-POTFILES-shell \ + 0002-Handle-gettext_printf-shell-function \ +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 5eef708338..26ac8765e3 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -31,12 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh + EXTRA_DIST += grub-core/genemuinit.sh + EXTRA_DIST += grub-core/genemuinitheader.sh + +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch + + EXTRA_DIST += grub-core/lib/libgcrypt +diff --git a/config.h.in b/config.h.in +index c3134309c6..512d1bbe13 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -67,10 +67,78 @@ + # define _GNU_SOURCE 1 + + # ifndef _GL_INLINE_HEADER_BEGIN ++/* gnulib gets configured against the host, not the target, and the rest of ++ * our buildsystem works around that. This is difficult to avoid as gnulib's ++ * detection requires a more capable system than our target. Instead, we ++ * reach in and set values appropriately - intentionally setting more than the ++ * bare minimum. If, when updating gnulib, something breaks, there's probably ++ * a change needed here or in grub-core/Makefile.core.def. */ ++# define SIZE_MAX ((size_t) -1) ++# define _GL_ATTRIBUTE_ALLOC_SIZE(args) \ ++ __attribute__ ((__alloc_size__ args)) ++# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__)) ++# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__)) ++# define _GL_ATTRIBUTE_COLD __attribute__ ((cold)) + # define _GL_ATTRIBUTE_CONST __attribute__ ((const)) ++# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute ((__malloc__ (f, i))) ++# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1) ++# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__)) ++# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg))) ++# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE \ ++ __attribute__ ((externally_visible)) ++# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) ++# define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__)) ++# define _GL_ATTRIBUTE_MALLOC __attribute__ ((malloc)) ++# define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED ++# define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__)) ++# define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__)) ++# define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__)) ++# define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args)) ++# define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__)) ++# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__)) ++# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) ++# define _GL_ATTRIBUTE_RETURNS_NONNULL \ ++ __attribute__ ((__returns_nonnull__)) ++# define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos)) ++# define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) ++# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg))) ++# define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2))) ++# define _GL_GNUC_PREREQ GNUC_PREREQ ++# define _GL_INLINE inline ++# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED ++ ++/* We can't use __has_attribute for these because gcc-5.1 is too old for ++ * that. Everything above is present in that version, though. */ ++# if __GNUC__ >= 7 ++# define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((fallthrough)) ++# else ++# define _GL_ATTRIBUTE_FALLTHROUGH /* empty */ ++# endif ++ ++# ifndef ASM_FILE ++typedef __INT_FAST32_TYPE__ int_fast32_t; ++typedef __UINT_FAST32_TYPE__ uint_fast32_t; ++# endif ++ ++/* Ensure ialloc nests static/non-static inline properly. */ ++# define IALLOC_INLINE static inline ++ ++/* gnulib uses these for blocking out warnings they can't/won't fix. gnulib ++ * also makes the decision about whether to provide a declaration for ++ * reallocarray() at compile-time, so this is a convenient place to override - ++ * it's used by the ialloc module, which is used by base64. */ ++# define _GL_INLINE_HEADER_BEGIN _Pragma ("GCC diagnostic push") \ ++ void * \ ++ reallocarray (void *ptr, unsigned int nmemb, unsigned int size); ++# define _GL_INLINE_HEADER_END _Pragma ("GCC diagnostic pop") + + /* We don't have an abort() for gnulib to call in regexp. */ + # define abort __builtin_unreachable + # endif /* !_GL_INLINE_HEADER_BEGIN */ + ++/* gnulib doesn't build cleanly with older compilers. */ ++# if __GNUC__ < 11 ++_Pragma ("GCC diagnostic ignored \"-Wtype-limits\"") ++# endif ++ + #endif +diff --git a/grub-core/lib/gnulib-patches/fix-null-deref.patch b/grub-core/lib/gnulib-patches/fix-null-deref.patch +deleted file mode 100644 +index 8fafa153a4..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-null-deref.patch ++++ /dev/null +@@ -1,13 +0,0 @@ +-diff --git a/lib/argp-parse.c b/lib/argp-parse.c +-index 6dec57310..900adad54 100644 +---- a/lib/argp-parse.c +-+++ b/lib/argp-parse.c +-@@ -940,7 +940,7 @@ weak_alias (__argp_parse, argp_parse) +- void * +- __argp_input (const struct argp *argp, const struct argp_state *state) +- { +-- if (state) +-+ if (state && state->pstate) +- { +- struct group *group; +- struct parser *parser = state->pstate; +diff --git a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch b/grub-core/lib/gnulib-patches/fix-null-state-deref.patch +deleted file mode 100644 +index 813ec09c8a..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch ++++ /dev/null +@@ -1,12 +0,0 @@ +---- 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/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch b/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch +deleted file mode 100644 +index 02e06315df..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch ++++ /dev/null +@@ -1,15 +0,0 @@ +---- a/lib/regcomp.c 2020-11-24 17:06:08.159223858 +0000 +-+++ b/lib/regcomp.c 2020-11-24 17:06:15.630253923 +0000 +-@@ -3808,11 +3808,7 @@ +- create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, +- re_token_type_t type) +- { +-- re_token_t t; +--#if defined GCC_LINT || defined lint +-- memset (&t, 0, sizeof t); +--#endif +-- t.type = type; +-+ re_token_t t = { .type = type }; +- return create_token_tree (dfa, left, right, &t); +- } +- +diff --git a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch b/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch +deleted file mode 100644 +index db6dac9c9e..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch ++++ /dev/null +@@ -1,12 +0,0 @@ +---- 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/grub-core/lib/gnulib-patches/fix-uninit-structure.patch b/grub-core/lib/gnulib-patches/fix-uninit-structure.patch +deleted file mode 100644 +index 7b4d9f67af..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch ++++ /dev/null +@@ -1,11 +0,0 @@ +---- 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/grub-core/lib/gnulib-patches/fix-unused-value.patch b/grub-core/lib/gnulib-patches/fix-unused-value.patch +deleted file mode 100644 +index ba51f1bf22..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-unused-value.patch ++++ /dev/null +@@ -1,14 +0,0 @@ +---- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000 +-+++ b/lib/regexec.c 2020-10-21 14:32:07.961765604 +0000 +-@@ -828,7 +828,11 @@ +- break; +- if (__glibc_unlikely (err != REG_NOMATCH)) +- 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 = -1; +-+#endif +- } +- else +- break; /* We found a match. */ diff --git a/0207-Update-gnulib-version-and-drop-most-gnulib-patches.patch b/0207-Update-gnulib-version-and-drop-most-gnulib-patches.patch deleted file mode 100644 index f0e2cc0..0000000 --- a/0207-Update-gnulib-version-and-drop-most-gnulib-patches.patch +++ /dev/null @@ -1,832 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Wed, 15 Dec 2021 15:07:50 -0500 -Subject: [PATCH] Update gnulib version and drop most gnulib patches - -In addition to the changes carried in our gnulib patches, several -Coverity and code hygiene fixes that were previously downstream are also -included in this 3-year gnulib increment. - -Unfortunately, fix-width.patch is retained. - -Bump minimum autoconf version from 2.63 to 2.64 and automake from 1.11 -to 1.14, as required by gnulib. - -Sync bootstrap script itself with gnulib. - -Update regexp module for new dynarray dependency. - -Fix various new warnings. - -Signed-off-by: Robbie Harwood -(cherry picked from commit deb18ff931c3133c2aa536a92bd92e50d6615303) -[rharwood: backport around requirements in INSTALL] ---- - configure.ac | 2 +- - grub-core/Makefile.core.def | 3 + - grub-core/disk/luks2.c | 4 +- - grub-core/lib/posix_wrap/limits.h | 6 +- - include/grub/compiler.h | 4 +- - include/grub/list.h | 2 +- - INSTALL | 2 +- - bootstrap | 291 ++++++++++++--------- - bootstrap.conf | 22 +- - conf/Makefile.extra-dist | 6 - - config.h.in | 68 +++++ - grub-core/lib/gnulib-patches/fix-null-deref.patch | 13 - - .../lib/gnulib-patches/fix-null-state-deref.patch | 12 - - .../gnulib-patches/fix-regcomp-uninit-token.patch | 15 -- - .../gnulib-patches/fix-regexec-null-deref.patch | 12 - - .../lib/gnulib-patches/fix-uninit-structure.patch | 11 - - .../lib/gnulib-patches/fix-unused-value.patch | 14 - - 17 files changed, 262 insertions(+), 225 deletions(-) - delete mode 100644 grub-core/lib/gnulib-patches/fix-null-deref.patch - delete mode 100644 grub-core/lib/gnulib-patches/fix-null-state-deref.patch - delete mode 100644 grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch - delete mode 100644 grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch - delete mode 100644 grub-core/lib/gnulib-patches/fix-uninit-structure.patch - delete mode 100644 grub-core/lib/gnulib-patches/fix-unused-value.patch - -diff --git a/configure.ac b/configure.ac -index 88e33e0f0c..871235b91b 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -49,7 +49,7 @@ AC_CANONICAL_TARGET - program_prefix="${save_program_prefix}" - - AM_INIT_AUTOMAKE([1.11]) --AC_PREREQ(2.63) -+AC_PREREQ(2.64) - AC_CONFIG_SRCDIR([include/grub/dl.h]) - AC_CONFIG_HEADER([config-util.h]) - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 6b00eb5557..39233096f2 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -762,6 +762,9 @@ module = { - name = regexp; - common = commands/regexp.c; - common = commands/wildcard.c; -+ common = lib/gnulib/malloc/dynarray_finalize.c; -+ common = lib/gnulib/malloc/dynarray_emplace_enlarge.c; -+ common = lib/gnulib/malloc/dynarray_resize.c; - common = lib/gnulib/regex.c; - cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; - cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; -diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c -index 371a53b837..c917a5f91e 100644 ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -389,7 +389,7 @@ luks2_verify_key (grub_luks2_digest_t *d, grub_uint8_t *candidate_key, - { - grub_uint8_t candidate_digest[GRUB_CRYPTODISK_MAX_KEYLEN]; - grub_uint8_t digest[GRUB_CRYPTODISK_MAX_KEYLEN], salt[GRUB_CRYPTODISK_MAX_KEYLEN]; -- grub_size_t saltlen = sizeof (salt), digestlen = sizeof (digest); -+ idx_t saltlen = sizeof (salt), digestlen = sizeof (digest); - const gcry_md_spec_t *hash; - gcry_err_code_t gcry_ret; - -@@ -428,7 +428,7 @@ luks2_decrypt_key (grub_uint8_t *out_key, - grub_uint8_t area_key[GRUB_CRYPTODISK_MAX_KEYLEN]; - grub_uint8_t salt[GRUB_CRYPTODISK_MAX_KEYLEN]; - grub_uint8_t *split_key = NULL; -- grub_size_t saltlen = sizeof (salt); -+ idx_t saltlen = sizeof (salt); - char cipher[32], *p; - const gcry_md_spec_t *hash; - gcry_err_code_t gcry_ret; -diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h -index 591dbf3289..4be7b40806 100644 ---- a/grub-core/lib/posix_wrap/limits.h -+++ b/grub-core/lib/posix_wrap/limits.h -@@ -25,7 +25,11 @@ - #define USHRT_MAX GRUB_USHRT_MAX - #define UINT_MAX GRUB_UINT_MAX - #define ULONG_MAX GRUB_ULONG_MAX --#define SIZE_MAX GRUB_SIZE_MAX -+ -+/* gnulib also defines this type */ -+#ifndef SIZE_MAX -+# define SIZE_MAX GRUB_SIZE_MAX -+#endif - - #define SCHAR_MIN GRUB_SCHAR_MIN - #define SCHAR_MAX GRUB_SCHAR_MAX -diff --git a/include/grub/compiler.h b/include/grub/compiler.h -index ebafec6895..441a9eca07 100644 ---- a/include/grub/compiler.h -+++ b/include/grub/compiler.h -@@ -30,10 +30,10 @@ - - /* Does this compiler support compile-time error attributes? */ - #if GNUC_PREREQ(4,3) --# define ATTRIBUTE_ERROR(msg) \ -+# define GRUB_ATTRIBUTE_ERROR(msg) \ - __attribute__ ((__error__ (msg))) - #else --# define ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) -+# define GRUB_ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) - #endif - - #if GNUC_PREREQ(4,4) -diff --git a/include/grub/list.h b/include/grub/list.h -index b13acb9624..21f4b4b44a 100644 ---- a/include/grub/list.h -+++ b/include/grub/list.h -@@ -40,7 +40,7 @@ void EXPORT_FUNC(grub_list_remove) (grub_list_t item); - - static inline void * - grub_bad_type_cast_real (int line, const char *file) -- ATTRIBUTE_ERROR ("bad type cast between incompatible grub types"); -+ GRUB_ATTRIBUTE_ERROR ("bad type cast between incompatible grub types"); - - static inline void * - grub_bad_type_cast_real (int line, const char *file) -diff --git a/INSTALL b/INSTALL -index 79a0af7d93..ee9f536f76 100644 ---- a/INSTALL -+++ b/INSTALL -@@ -42,7 +42,7 @@ If you use a development snapshot or want to hack on GRUB you may - need the following. - - * Python 2.6 or later --* Autoconf 2.63 or later -+* Autoconf 2.64 or later - * Automake 1.11 or later - - Prerequisites for make-check: -diff --git a/bootstrap b/bootstrap -index 5b08e7e2d4..dc2238f4ad 100755 ---- a/bootstrap -+++ b/bootstrap -@@ -1,10 +1,10 @@ - #! /bin/sh - # Print a version string. --scriptversion=2019-01-04.17; # UTC -+scriptversion=2022-01-26.05; # UTC - - # Bootstrap this package from checked-out sources. - --# Copyright (C) 2003-2019 Free Software Foundation, Inc. -+# Copyright (C) 2003-2022 Free Software Foundation, Inc. - - # 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 -@@ -47,7 +47,7 @@ PERL="${PERL-perl}" - - me=$0 - --default_gnulib_url=git://git.sv.gnu.org/gnulib -+default_gnulib_url=https://git.savannah.gnu.org/git/gnulib.git - - usage() { - cat </dev/null) -+if test -z "$package"; then -+ package=$(sed -n "$extract_package_name" configure.ac) \ -+ || die 'cannot find package name in configure.ac' -+fi - gnulib_name=lib$package - - build_aux=build-aux -@@ -290,6 +313,116 @@ find_tool () - eval "export $find_tool_envvar" - } - -+# Strip blank and comment lines to leave significant entries. -+gitignore_entries() { -+ sed '/^#/d; /^$/d' "$@" -+} -+ -+# If $STR is not already on a line by itself in $FILE, insert it at the start. -+# Entries are inserted at the start of the ignore list to ensure existing -+# entries starting with ! are not overridden. Such entries support -+# whitelisting exceptions after a more generic blacklist pattern. -+insert_if_absent() { -+ file=$1 -+ str=$2 -+ test -f $file || touch $file -+ test -r $file || die "Error: failed to read ignore file: $file" -+ duplicate_entries=$(gitignore_entries $file | sort | uniq -d) -+ if [ "$duplicate_entries" ] ; then -+ die "Error: Duplicate entries in $file: " $duplicate_entries -+ fi -+ linesold=$(gitignore_entries $file | wc -l) -+ linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l) -+ if [ $linesold != $linesnew ] ; then -+ { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \ -+ || die "insert_if_absent $file $str: failed" -+ fi -+} -+ -+# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with -+# insert_if_absent. -+insert_vc_ignore() { -+ vc_ignore_file="$1" -+ pattern="$2" -+ case $vc_ignore_file in -+ *.gitignore) -+ # A .gitignore entry that does not start with '/' applies -+ # recursively to subdirectories, so prepend '/' to every -+ # .gitignore entry. -+ pattern=$(echo "$pattern" | sed s,^,/,);; -+ esac -+ insert_if_absent "$vc_ignore_file" "$pattern" -+} -+ -+symlink_to_dir() -+{ -+ src=$1/$2 -+ dst=${3-$2} -+ -+ test -f "$src" && { -+ -+ # If the destination directory doesn't exist, create it. -+ # This is required at least for "lib/uniwidth/cjk.h". -+ dst_dir=$(dirname "$dst") -+ if ! test -d "$dst_dir"; then -+ mkdir -p "$dst_dir" -+ -+ # If we've just created a directory like lib/uniwidth, -+ # tell version control system(s) it's ignorable. -+ # FIXME: for now, this does only one level -+ parent=$(dirname "$dst_dir") -+ for dot_ig in x $vc_ignore; do -+ test $dot_ig = x && continue -+ ig=$parent/$dot_ig -+ insert_vc_ignore $ig "${dst_dir##*/}" -+ done -+ fi -+ -+ if $copy; then -+ { -+ test ! -h "$dst" || { -+ echo "$me: rm -f $dst" && -+ rm -f "$dst" -+ } -+ } && -+ test -f "$dst" && -+ cmp -s "$src" "$dst" || { -+ echo "$me: cp -fp $src $dst" && -+ cp -fp "$src" "$dst" -+ } -+ else -+ # Leave any existing symlink alone, if it already points to the source, -+ # so that broken build tools that care about symlink times -+ # aren't confused into doing unnecessary builds. Conversely, if the -+ # existing symlink's timestamp is older than the source, make it afresh, -+ # so that broken tools aren't confused into skipping needed builds. See -+ # . -+ test -h "$dst" && -+ src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 && -+ dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 && -+ test "$src_i" = "$dst_i" && -+ both_ls=$(ls -dt "$src" "$dst") && -+ test "X$both_ls" = "X$dst$nl$src" || { -+ dot_dots= -+ case $src in -+ /*) ;; -+ *) -+ case /$dst/ in -+ *//* | */../* | */./* | /*/*/*/*/*/) -+ die "invalid symlink calculation: $src -> $dst";; -+ /*/*/*/*/) dot_dots=../../../;; -+ /*/*/*/) dot_dots=../../;; -+ /*/*/) dot_dots=../;; -+ esac;; -+ esac -+ -+ echo "$me: ln -fs $dot_dots$src $dst" && -+ ln -fs "$dot_dots$src" "$dst" -+ } -+ fi -+ } -+} -+ - # Override the default configuration, if necessary. - # Make sure that bootstrap.conf is sourced from the current directory - # if we were invoked as "sh bootstrap". -@@ -320,6 +453,12 @@ do - --help) - usage - exit;; -+ --version) -+ set -e -+ echo "bootstrap $scriptversion" -+ echo "$copyright" -+ exit 0 -+ ;; - --gnulib-srcdir=*) - GNULIB_SRCDIR=${option#--gnulib-srcdir=};; - --skip-po) -@@ -335,7 +474,7 @@ do - --no-git) - use_git=false;; - *) -- die "$option: unknown option";; -+ bootstrap_option_hook $option || die "$option: unknown option";; - esac - done - -@@ -346,47 +485,6 @@ if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then - die "Bootstrapping from a non-checked-out distribution is risky." - fi - --# Strip blank and comment lines to leave significant entries. --gitignore_entries() { -- sed '/^#/d; /^$/d' "$@" --} -- --# If $STR is not already on a line by itself in $FILE, insert it at the start. --# Entries are inserted at the start of the ignore list to ensure existing --# entries starting with ! are not overridden. Such entries support --# whitelisting exceptions after a more generic blacklist pattern. --insert_if_absent() { -- file=$1 -- str=$2 -- test -f $file || touch $file -- test -r $file || die "Error: failed to read ignore file: $file" -- duplicate_entries=$(gitignore_entries $file | sort | uniq -d) -- if [ "$duplicate_entries" ] ; then -- die "Error: Duplicate entries in $file: " $duplicate_entries -- fi -- linesold=$(gitignore_entries $file | wc -l) -- linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l) -- if [ $linesold != $linesnew ] ; then -- { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \ -- || die "insert_if_absent $file $str: failed" -- fi --} -- --# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with --# insert_if_absent. --insert_vc_ignore() { -- vc_ignore_file="$1" -- pattern="$2" -- case $vc_ignore_file in -- *.gitignore) -- # A .gitignore entry that does not start with '/' applies -- # recursively to subdirectories, so prepend '/' to every -- # .gitignore entry. -- pattern=$(echo "$pattern" | sed s,^,/,);; -- esac -- insert_if_absent "$vc_ignore_file" "$pattern" --} -- - # Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac. - found_aux_dir=no - grep '^[ ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \ -@@ -665,9 +763,25 @@ if $use_gnulib; then - shallow= - if test -z "$GNULIB_REVISION"; then - git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' -+ git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \ -+ || cleanup_gnulib -+ else -+ git fetch -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' -+ mkdir -p "$gnulib_path" -+ # Only want a shallow checkout of $GNULIB_REVISION, but git does not -+ # support cloning by commit hash. So attempt a shallow fetch by commit -+ # hash to minimize the amount of data downloaded and changes needed to -+ # be processed, which can drastically reduce download and processing -+ # time for checkout. If the fetch by commit fails, a shallow fetch can -+ # not be performed because we do not know what the depth of the commit -+ # is without fetching all commits. So fallback to fetching all commits. -+ git -C "$gnulib_path" init -+ git -C "$gnulib_path" remote add origin ${GNULIB_URL:-$default_gnulib_url} -+ git -C "$gnulib_path" fetch $shallow origin "$GNULIB_REVISION" \ -+ || git -C "$gnulib_path" fetch origin \ -+ || cleanup_gnulib -+ git -C "$gnulib_path" reset --hard FETCH_HEAD - fi -- git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \ -- || cleanup_gnulib - - trap - 1 2 13 15 - fi -@@ -784,75 +898,6 @@ case $SKIP_PO in - fi;; - esac - --symlink_to_dir() --{ -- src=$1/$2 -- dst=${3-$2} -- -- test -f "$src" && { -- -- # If the destination directory doesn't exist, create it. -- # This is required at least for "lib/uniwidth/cjk.h". -- dst_dir=$(dirname "$dst") -- if ! test -d "$dst_dir"; then -- mkdir -p "$dst_dir" -- -- # If we've just created a directory like lib/uniwidth, -- # tell version control system(s) it's ignorable. -- # FIXME: for now, this does only one level -- parent=$(dirname "$dst_dir") -- for dot_ig in x $vc_ignore; do -- test $dot_ig = x && continue -- ig=$parent/$dot_ig -- insert_vc_ignore $ig "${dst_dir##*/}" -- done -- fi -- -- if $copy; then -- { -- test ! -h "$dst" || { -- echo "$me: rm -f $dst" && -- rm -f "$dst" -- } -- } && -- test -f "$dst" && -- cmp -s "$src" "$dst" || { -- echo "$me: cp -fp $src $dst" && -- cp -fp "$src" "$dst" -- } -- else -- # Leave any existing symlink alone, if it already points to the source, -- # so that broken build tools that care about symlink times -- # aren't confused into doing unnecessary builds. Conversely, if the -- # existing symlink's timestamp is older than the source, make it afresh, -- # so that broken tools aren't confused into skipping needed builds. See -- # . -- test -h "$dst" && -- src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 && -- dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 && -- test "$src_i" = "$dst_i" && -- both_ls=$(ls -dt "$src" "$dst") && -- test "X$both_ls" = "X$dst$nl$src" || { -- dot_dots= -- case $src in -- /*) ;; -- *) -- case /$dst/ in -- *//* | */../* | */./* | /*/*/*/*/*/) -- die "invalid symlink calculation: $src -> $dst";; -- /*/*/*/*/) dot_dots=../../../;; -- /*/*/*/) dot_dots=../../;; -- /*/*/) dot_dots=../;; -- esac;; -- esac -- -- echo "$me: ln -fs $dot_dots$src $dst" && -- ln -fs "$dot_dots$src" "$dst" -- } -- fi -- } --} -- - version_controlled_file() { - parent=$1 - file=$2 -@@ -970,7 +1015,7 @@ bootstrap_post_import_hook \ - # Uninitialized submodules are listed with an initial dash. - if $use_git && git submodule | grep '^-' >/dev/null; then - die "some git submodules are not initialized. " \ -- "Run 'git submodule init' and bootstrap again." -+ "Run 'git submodule update --init' and bootstrap again." - fi - - # Remove any dangling symlink matching "*.m4" or "*.[ch]" in some -@@ -1064,7 +1109,7 @@ bootstrap_epilogue - - echo "$0: done. Now you can run './configure'." - --# Local variables: -+# Local Variables: - # eval: (add-hook 'before-save-hook 'time-stamp) - # time-stamp-start: "scriptversion=" - # time-stamp-format: "%:y-%02m-%02d.%02H" -diff --git a/bootstrap.conf b/bootstrap.conf -index 71ce943c7d..e4e5f3750a 100644 ---- a/bootstrap.conf -+++ b/bootstrap.conf -@@ -1,6 +1,6 @@ - # Bootstrap configuration. - --# Copyright (C) 2006-2019 Free Software Foundation, Inc. -+# Copyright (C) 2006-2022 Free Software Foundation, Inc. - - # 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 -@@ -16,11 +16,10 @@ - # along with this program. If not, see . - - --GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263 -+GNULIB_REVISION=9f48fb992a3d7e96610c4ce8be969cff2d61a01b - - # gnulib modules used by this package. --# mbswidth is used by gnulib-fix-width.diff's changes to argp rather than --# directly. -+# mbswidth is used by fix-width.diff's changes to argp rather than directly. - gnulib_modules=" - argp - base64 -@@ -67,8 +66,8 @@ SKIP_PO=t - - # Build prerequisites - buildreq="\ --autoconf 2.63 --automake 1.11 -+autoconf 2.64 -+automake 1.14 - gettext 0.18.3 - git 1.5.5 - tar - -@@ -80,11 +79,12 @@ cp -a INSTALL INSTALL.grub - - bootstrap_post_import_hook () { - set -e -- for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ -- fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do -- patch -d grub-core/lib/gnulib -p2 \ -- < "grub-core/lib/gnulib-patches/$patchname.patch" -- done -+ -+ # Instead of patching our gnulib and therefore maintaining a fork, submit -+ # changes to gnulib and update the hash above when they've merged. Do not -+ # add new patches here. -+ patch -d grub-core/lib/gnulib -p2 < grub-core/lib/gnulib-patches/fix-width.patch -+ - for patchname in \ - 0001-Support-POTFILES-shell \ - 0002-Handle-gettext_printf-shell-function \ -diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist -index 5eef708338..26ac8765e3 100644 ---- a/conf/Makefile.extra-dist -+++ b/conf/Makefile.extra-dist -@@ -31,12 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh - EXTRA_DIST += grub-core/genemuinit.sh - EXTRA_DIST += grub-core/genemuinitheader.sh - --EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch --EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch --EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch --EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch --EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch --EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch - EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch - - EXTRA_DIST += grub-core/lib/libgcrypt -diff --git a/config.h.in b/config.h.in -index c3134309c6..512d1bbe13 100644 ---- a/config.h.in -+++ b/config.h.in -@@ -67,10 +67,78 @@ - # define _GNU_SOURCE 1 - - # ifndef _GL_INLINE_HEADER_BEGIN -+/* gnulib gets configured against the host, not the target, and the rest of -+ * our buildsystem works around that. This is difficult to avoid as gnulib's -+ * detection requires a more capable system than our target. Instead, we -+ * reach in and set values appropriately - intentionally setting more than the -+ * bare minimum. If, when updating gnulib, something breaks, there's probably -+ * a change needed here or in grub-core/Makefile.core.def. */ -+# define SIZE_MAX ((size_t) -1) -+# define _GL_ATTRIBUTE_ALLOC_SIZE(args) \ -+ __attribute__ ((__alloc_size__ args)) -+# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__)) -+# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__)) -+# define _GL_ATTRIBUTE_COLD __attribute__ ((cold)) - # define _GL_ATTRIBUTE_CONST __attribute__ ((const)) -+# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute ((__malloc__ (f, i))) -+# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1) -+# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__)) -+# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg))) -+# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE \ -+ __attribute__ ((externally_visible)) -+# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) -+# define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__)) -+# define _GL_ATTRIBUTE_MALLOC __attribute__ ((malloc)) -+# define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED -+# define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__)) -+# define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__)) -+# define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__)) -+# define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args)) -+# define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__)) -+# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__)) -+# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) -+# define _GL_ATTRIBUTE_RETURNS_NONNULL \ -+ __attribute__ ((__returns_nonnull__)) -+# define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos)) -+# define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -+# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg))) -+# define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2))) -+# define _GL_GNUC_PREREQ GNUC_PREREQ -+# define _GL_INLINE inline -+# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED -+ -+/* We can't use __has_attribute for these because gcc-5.1 is too old for -+ * that. Everything above is present in that version, though. */ -+# if __GNUC__ >= 7 -+# define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((fallthrough)) -+# else -+# define _GL_ATTRIBUTE_FALLTHROUGH /* empty */ -+# endif -+ -+# ifndef ASM_FILE -+typedef __INT_FAST32_TYPE__ int_fast32_t; -+typedef __UINT_FAST32_TYPE__ uint_fast32_t; -+# endif -+ -+/* Ensure ialloc nests static/non-static inline properly. */ -+# define IALLOC_INLINE static inline -+ -+/* gnulib uses these for blocking out warnings they can't/won't fix. gnulib -+ * also makes the decision about whether to provide a declaration for -+ * reallocarray() at compile-time, so this is a convenient place to override - -+ * it's used by the ialloc module, which is used by base64. */ -+# define _GL_INLINE_HEADER_BEGIN _Pragma ("GCC diagnostic push") \ -+ void * \ -+ reallocarray (void *ptr, unsigned int nmemb, unsigned int size); -+# define _GL_INLINE_HEADER_END _Pragma ("GCC diagnostic pop") - - /* We don't have an abort() for gnulib to call in regexp. */ - # define abort __builtin_unreachable - # endif /* !_GL_INLINE_HEADER_BEGIN */ - -+/* gnulib doesn't build cleanly with older compilers. */ -+# if __GNUC__ < 11 -+_Pragma ("GCC diagnostic ignored \"-Wtype-limits\"") -+# endif -+ - #endif -diff --git a/grub-core/lib/gnulib-patches/fix-null-deref.patch b/grub-core/lib/gnulib-patches/fix-null-deref.patch -deleted file mode 100644 -index 8fafa153a4..0000000000 ---- a/grub-core/lib/gnulib-patches/fix-null-deref.patch -+++ /dev/null -@@ -1,13 +0,0 @@ --diff --git a/lib/argp-parse.c b/lib/argp-parse.c --index 6dec57310..900adad54 100644 ----- a/lib/argp-parse.c --+++ b/lib/argp-parse.c --@@ -940,7 +940,7 @@ weak_alias (__argp_parse, argp_parse) -- void * -- __argp_input (const struct argp *argp, const struct argp_state *state) -- { --- if (state) --+ if (state && state->pstate) -- { -- struct group *group; -- struct parser *parser = state->pstate; -diff --git a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch b/grub-core/lib/gnulib-patches/fix-null-state-deref.patch -deleted file mode 100644 -index 813ec09c8a..0000000000 ---- a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch -+++ /dev/null -@@ -1,12 +0,0 @@ ----- 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/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch b/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch -deleted file mode 100644 -index 02e06315df..0000000000 ---- a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch -+++ /dev/null -@@ -1,15 +0,0 @@ ----- a/lib/regcomp.c 2020-11-24 17:06:08.159223858 +0000 --+++ b/lib/regcomp.c 2020-11-24 17:06:15.630253923 +0000 --@@ -3808,11 +3808,7 @@ -- create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, -- re_token_type_t type) -- { --- re_token_t t; ---#if defined GCC_LINT || defined lint --- memset (&t, 0, sizeof t); ---#endif --- t.type = type; --+ re_token_t t = { .type = type }; -- return create_token_tree (dfa, left, right, &t); -- } -- -diff --git a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch b/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch -deleted file mode 100644 -index db6dac9c9e..0000000000 ---- a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch -+++ /dev/null -@@ -1,12 +0,0 @@ ----- 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/grub-core/lib/gnulib-patches/fix-uninit-structure.patch b/grub-core/lib/gnulib-patches/fix-uninit-structure.patch -deleted file mode 100644 -index 7b4d9f67af..0000000000 ---- a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch -+++ /dev/null -@@ -1,11 +0,0 @@ ----- 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/grub-core/lib/gnulib-patches/fix-unused-value.patch b/grub-core/lib/gnulib-patches/fix-unused-value.patch -deleted file mode 100644 -index ba51f1bf22..0000000000 ---- a/grub-core/lib/gnulib-patches/fix-unused-value.patch -+++ /dev/null -@@ -1,14 +0,0 @@ ----- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000 --+++ b/lib/regexec.c 2020-10-21 14:32:07.961765604 +0000 --@@ -828,7 +828,11 @@ -- break; -- if (__glibc_unlikely (err != REG_NOMATCH)) -- 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 = -1; --+#endif -- } -- else -- break; /* We found a match. */ diff --git a/0207-commands-search-Fix-bug-stopping-iteration-when-no-f.patch b/0207-commands-search-Fix-bug-stopping-iteration-when-no-f.patch new file mode 100644 index 0000000..4f7feb9 --- /dev/null +++ b/0207-commands-search-Fix-bug-stopping-iteration-when-no-f.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Tue, 8 Feb 2022 08:39:10 +0100 +Subject: [PATCH] commands/search: Fix bug stopping iteration when --no-floppy + is used +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When using --no-floppy and a floppy was encountered, iterate_device() +was returning 1, causing the iteration to stop instead of continuing. + +Signed-off-by: Renaud Métrich +Reviewed-by: Daniel Kiper +(cherry picked from commit 68ba54c2298604146be83cae144dafd1cfd1fe2d) +Signed-off-by: Robbie Harwood +--- + grub-core/commands/search.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index ed090b3af8..51656e361c 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -64,7 +64,7 @@ iterate_device (const char *name, void *data) + /* Skip floppy drives when requested. */ + if (ctx->no_floppy && + name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') +- return 1; ++ return 0; + + #ifdef DO_SEARCH_FS_UUID + #define compare_fn grub_strcasecmp diff --git a/0208-commands-search-Fix-bug-stopping-iteration-when-no-f.patch b/0208-commands-search-Fix-bug-stopping-iteration-when-no-f.patch deleted file mode 100644 index 4f7feb9..0000000 --- a/0208-commands-search-Fix-bug-stopping-iteration-when-no-f.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Renaud=20M=C3=A9trich?= -Date: Tue, 8 Feb 2022 08:39:10 +0100 -Subject: [PATCH] commands/search: Fix bug stopping iteration when --no-floppy - is used -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When using --no-floppy and a floppy was encountered, iterate_device() -was returning 1, causing the iteration to stop instead of continuing. - -Signed-off-by: Renaud Métrich -Reviewed-by: Daniel Kiper -(cherry picked from commit 68ba54c2298604146be83cae144dafd1cfd1fe2d) -Signed-off-by: Robbie Harwood ---- - grub-core/commands/search.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c -index ed090b3af8..51656e361c 100644 ---- a/grub-core/commands/search.c -+++ b/grub-core/commands/search.c -@@ -64,7 +64,7 @@ iterate_device (const char *name, void *data) - /* Skip floppy drives when requested. */ - if (ctx->no_floppy && - name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') -- return 1; -+ return 0; - - #ifdef DO_SEARCH_FS_UUID - #define compare_fn grub_strcasecmp diff --git a/0208-search-new-efidisk-only-option-on-EFI-systems.patch b/0208-search-new-efidisk-only-option-on-EFI-systems.patch new file mode 100644 index 0000000..3f6194a --- /dev/null +++ b/0208-search-new-efidisk-only-option-on-EFI-systems.patch @@ -0,0 +1,168 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Tue, 8 Feb 2022 08:39:11 +0100 +Subject: [PATCH] search: new --efidisk-only option on EFI systems +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When using 'search' on EFI systems, we sometimes want to exclude devices +that are not EFI disks (e.g. md, lvm). +This is typically used when wanting to chainload when having a software +raid (md) for EFI partition: +with no option, 'search --file /EFI/redhat/shimx64.efi' sets root envvar +to 'md/boot_efi' which cannot be used for chainloading since there is no +effective EFI device behind. + +This commit also refactors handling of --no-floppy option. + +Signed-off-by: Renaud Métrich +[rharwood: apply rmetrich's flags initialization fix] +Signed-off-by: Robbie Harwood +--- + grub-core/commands/search.c | 27 +++++++++++++++++++++++---- + grub-core/commands/search_wrap.c | 18 ++++++++++++------ + include/grub/search.h | 15 ++++++++++++--- + 3 files changed, 47 insertions(+), 13 deletions(-) + +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index 51656e361c..57d26ced8a 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -47,7 +47,7 @@ struct search_ctx + { + const char *key; + const char *var; +- int no_floppy; ++ enum search_flags flags; + char **hints; + unsigned nhints; + int count; +@@ -62,10 +62,29 @@ iterate_device (const char *name, void *data) + int found = 0; + + /* Skip floppy drives when requested. */ +- if (ctx->no_floppy && ++ if (ctx->flags & SEARCH_FLAGS_NO_FLOPPY && + name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') + return 0; + ++ /* Limit to EFI disks when requested. */ ++ if (ctx->flags & SEARCH_FLAGS_EFIDISK_ONLY) ++ { ++ grub_device_t dev; ++ dev = grub_device_open (name); ++ if (! dev) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (! dev->disk || dev->disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID) ++ { ++ grub_device_close (dev); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ grub_device_close (dev); ++ } ++ + #ifdef DO_SEARCH_FS_UUID + #define compare_fn grub_strcasecmp + #else +@@ -261,13 +280,13 @@ try (struct search_ctx *ctx) + } + + void +-FUNC_NAME (const char *key, const char *var, int no_floppy, ++FUNC_NAME (const char *key, const char *var, enum search_flags flags, + char **hints, unsigned nhints) + { + struct search_ctx ctx = { + .key = key, + .var = var, +- .no_floppy = no_floppy, ++ .flags = flags, + .hints = hints, + .nhints = nhints, + .count = 0, +diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c +index 47fc8eb996..0b62acf853 100644 +--- a/grub-core/commands/search_wrap.c ++++ b/grub-core/commands/search_wrap.c +@@ -40,6 +40,7 @@ static const struct grub_arg_option options[] = + N_("Set a variable to the first device found."), N_("VARNAME"), + ARG_TYPE_STRING}, + {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, ++ {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0}, + {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, +@@ -73,6 +74,7 @@ enum options + SEARCH_FS_UUID, + SEARCH_SET, + SEARCH_NO_FLOPPY, ++ SEARCH_EFIDISK_ONLY, + SEARCH_HINT, + SEARCH_HINT_IEEE1275, + SEARCH_HINT_BIOS, +@@ -89,6 +91,7 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) + const char *id = 0; + int i = 0, j = 0, nhints = 0; + char **hints = NULL; ++ enum search_flags flags = 0; + + if (state[SEARCH_HINT].set) + for (i = 0; state[SEARCH_HINT].args[i]; i++) +@@ -180,15 +183,18 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) + goto out; + } + ++ if (state[SEARCH_NO_FLOPPY].set) ++ flags |= SEARCH_FLAGS_NO_FLOPPY; ++ ++ if (state[SEARCH_EFIDISK_ONLY].set) ++ flags |= SEARCH_FLAGS_EFIDISK_ONLY; ++ + if (state[SEARCH_LABEL].set) +- grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, +- hints, nhints); ++ grub_search_label (id, var, flags, hints, nhints); + else if (state[SEARCH_FS_UUID].set) +- grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set, +- hints, nhints); ++ grub_search_fs_uuid (id, var, flags, hints, nhints); + else if (state[SEARCH_FILE].set) +- grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, +- hints, nhints); ++ grub_search_fs_file (id, var, flags, hints, nhints); + else + grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); + +diff --git a/include/grub/search.h b/include/grub/search.h +index d80347df34..4190aeb2cb 100644 +--- a/include/grub/search.h ++++ b/include/grub/search.h +@@ -19,11 +19,20 @@ + #ifndef GRUB_SEARCH_HEADER + #define GRUB_SEARCH_HEADER 1 + +-void grub_search_fs_file (const char *key, const char *var, int no_floppy, ++enum search_flags ++ { ++ SEARCH_FLAGS_NO_FLOPPY = 1, ++ SEARCH_FLAGS_EFIDISK_ONLY = 2 ++ }; ++ ++void grub_search_fs_file (const char *key, const char *var, ++ enum search_flags flags, + char **hints, unsigned nhints); +-void grub_search_fs_uuid (const char *key, const char *var, int no_floppy, ++void grub_search_fs_uuid (const char *key, const char *var, ++ enum search_flags flags, + char **hints, unsigned nhints); +-void grub_search_label (const char *key, const char *var, int no_floppy, ++void grub_search_label (const char *key, const char *var, ++ enum search_flags flags, + char **hints, unsigned nhints); + + #endif diff --git a/0209-efi-new-connectefi-command.patch b/0209-efi-new-connectefi-command.patch new file mode 100644 index 0000000..55a49fd --- /dev/null +++ b/0209-efi-new-connectefi-command.patch @@ -0,0 +1,395 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Tue, 15 Feb 2022 14:05:22 +0100 +Subject: [PATCH] efi: new 'connectefi' command +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When efi.quickboot is enabled on VMWare (which is the default for +hardware release 16 and later), it may happen that not all EFI devices +are connected. Due to this, browsing the devices in make_devices() just +fails to find devices, in particular disks or partitions for a given +disk. +This typically happens when network booting, then trying to chainload to +local disk (this is used in deployment tools such as Red Hat Satellite), +which is done through using the following grub.cfg snippet: +-------- 8< ---------------- 8< ---------------- 8< -------- +unset prefix +search --file --set=prefix /EFI/redhat/grubx64.efi +if [ -n "$prefix" ]; then + chainloader ($prefix)/EFI/redhat/grubx64/efi +... +-------- 8< ---------------- 8< ---------------- 8< -------- + +With efi.quickboot, none of the devices are connected, causing "search" +to fail. Sometimes devices are connected but not the partition of the +disk matching $prefix, causing partition to not be found by +"chainloader". + +This patch introduces a new "connectefi pciroot|scsi" command which +recursively connects all EFI devices starting from a given controller +type: +- if 'pciroot' is specified, recursion is performed for all PCI root + handles +- if 'scsi' is specified, recursion is performed for all SCSI I/O + handles (recommended usage to avoid connecting unwanted handles which + may impact Grub performances) + +Typical grub.cfg snippet would then be: +-------- 8< ---------------- 8< ---------------- 8< -------- +connectefi scsi +unset prefix +search --file --set=prefix /EFI/redhat/grubx64.efi +if [ -n "$prefix" ]; then + chainloader ($prefix)/EFI/redhat/grubx64/efi +... +-------- 8< ---------------- 8< ---------------- 8< -------- + +The code is easily extensible to handle other arguments in the future if +needed. + +Signed-off-by: Renaud Métrich +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 6 ++ + grub-core/commands/efi/connectefi.c | 205 ++++++++++++++++++++++++++++++++++++ + grub-core/commands/efi/lsefi.c | 1 + + grub-core/disk/efi/efidisk.c | 13 +++ + grub-core/kern/efi/efi.c | 13 +++ + include/grub/efi/disk.h | 2 + + include/grub/efi/efi.h | 5 + + NEWS | 2 +- + 8 files changed, 246 insertions(+), 1 deletion(-) + create mode 100644 grub-core/commands/efi/connectefi.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 39233096f2..3c0ac3b7bd 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -836,6 +836,12 @@ module = { + enable = efi; + }; + ++module = { ++ name = connectefi; ++ common = commands/efi/connectefi.c; ++ enable = efi; ++}; ++ + module = { + name = blocklist; + common = commands/blocklist.c; +diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c +new file mode 100644 +index 0000000000..8ab75bd51b +--- /dev/null ++++ b/grub-core/commands/efi/connectefi.c +@@ -0,0 +1,205 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef struct handle_list ++{ ++ grub_efi_handle_t handle; ++ struct handle_list *next; ++} handle_list_t; ++ ++static handle_list_t *already_handled = NULL; ++ ++static grub_err_t ++add_handle (grub_efi_handle_t handle) ++{ ++ handle_list_t *e; ++ e = grub_malloc (sizeof (*e)); ++ if (! e) ++ return grub_errno; ++ e->handle = handle; ++ e->next = already_handled; ++ already_handled = e; ++ return GRUB_ERR_NONE; ++} ++ ++static int ++is_in_list (grub_efi_handle_t handle) ++{ ++ handle_list_t *e; ++ for (e = already_handled; e != NULL; e = e->next) ++ if (e->handle == handle) ++ return 1; ++ return 0; ++} ++ ++static void ++free_handle_list (void) ++{ ++ handle_list_t *e; ++ while ((e = already_handled) != NULL) ++ { ++ already_handled = already_handled->next; ++ grub_free (e); ++ } ++} ++ ++typedef enum searched_item_flag ++{ ++ SEARCHED_ITEM_FLAG_LOOP = 1, ++ SEARCHED_ITEM_FLAG_RECURSIVE = 2 ++} searched_item_flags; ++ ++typedef struct searched_item ++{ ++ grub_efi_guid_t guid; ++ const char *name; ++ searched_item_flags flags; ++} searched_items; ++ ++static grub_err_t ++grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ unsigned s; ++ searched_items pciroot_items[] = ++ { ++ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE } ++ }; ++ searched_items scsi_items[] = ++ { ++ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", 0 }, ++ { GRUB_EFI_PCI_IO_GUID, "PCI", SEARCHED_ITEM_FLAG_LOOP }, ++ { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE } ++ }; ++ searched_items *items = NULL; ++ unsigned nitems = 0; ++ grub_err_t grub_err = GRUB_ERR_NONE; ++ unsigned total_connected = 0; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ if (grub_strcmp(args[0], N_("pciroot")) == 0) ++ { ++ items = pciroot_items; ++ nitems = ARRAY_SIZE (pciroot_items); ++ } ++ else if (grub_strcmp(args[0], N_("scsi")) == 0) ++ { ++ items = scsi_items; ++ nitems = ARRAY_SIZE (scsi_items); ++ } ++ else ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("unexpected argument `%s'"), args[0]); ++ ++ for (s = 0; s < nitems; s++) ++ { ++ grub_efi_handle_t *handles; ++ grub_efi_uintn_t num_handles; ++ unsigned i, connected = 0, loop = 0; ++ ++loop: ++ loop++; ++ grub_dprintf ("efi", "step '%s' loop %d:\n", items[s].name, loop); ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, ++ &items[s].guid, 0, &num_handles); ++ ++ if (!handles) ++ continue; ++ ++ for (i = 0; i < num_handles; i++) ++ { ++ grub_efi_handle_t handle = handles[i]; ++ grub_efi_status_t status; ++ unsigned j; ++ ++ /* Skip already handled handles */ ++ if (is_in_list (handle)) ++ { ++ grub_dprintf ("efi", " handle %p: already processed\n", ++ handle); ++ continue; ++ } ++ ++ status = grub_efi_connect_controller(handle, NULL, NULL, ++ items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0); ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ connected++; ++ total_connected++; ++ grub_dprintf ("efi", " handle %p: connected\n", handle); ++ } ++ else ++ grub_dprintf ("efi", " handle %p: failed to connect (%d)\n", ++ handle, (grub_efi_int8_t) status); ++ ++ if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE) ++ break; /* fatal */ ++ } ++ ++ grub_free (handles); ++ if (grub_err != GRUB_ERR_NONE) ++ break; /* fatal */ ++ ++ if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected) ++ { ++ connected = 0; ++ goto loop; ++ } ++ ++ free_handle_list (); ++ } ++ ++ free_handle_list (); ++ ++ if (total_connected) ++ grub_efidisk_reenumerate_disks (); ++ ++ return grub_err; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(connectefi) ++{ ++ cmd = grub_register_command ("connectefi", grub_cmd_connectefi, ++ N_("pciroot|scsi"), ++ N_("Connect EFI handles." ++ " If 'pciroot' is specified, connect PCI" ++ " root EFI handles recursively." ++ " If 'scsi' is specified, connect SCSI" ++ " I/O EFI handles recursively.")); ++} ++ ++GRUB_MOD_FINI(connectefi) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c +index d1ce99af43..f2d2430e66 100644 +--- a/grub-core/commands/efi/lsefi.c ++++ b/grub-core/commands/efi/lsefi.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c +index fe8ba6e6c9..062143dfff 100644 +--- a/grub-core/disk/efi/efidisk.c ++++ b/grub-core/disk/efi/efidisk.c +@@ -396,6 +396,19 @@ enumerate_disks (void) + free_devices (devices); + } + ++void ++grub_efidisk_reenumerate_disks (void) ++{ ++ free_devices (fd_devices); ++ free_devices (hd_devices); ++ free_devices (cd_devices); ++ fd_devices = 0; ++ hd_devices = 0; ++ cd_devices = 0; ++ ++ enumerate_disks (); ++} ++ + static int + grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 14bc10eb56..7fcca69c17 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -95,6 +95,19 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, + return buffer; + } + ++grub_efi_status_t ++grub_efi_connect_controller (grub_efi_handle_t controller_handle, ++ grub_efi_handle_t *driver_image_handle, ++ grub_efi_device_path_protocol_t *remaining_device_path, ++ grub_efi_boolean_t recursive) ++{ ++ grub_efi_boot_services_t *b; ++ ++ b = grub_efi_system_table->boot_services; ++ return efi_call_4 (b->connect_controller, controller_handle, ++ driver_image_handle, remaining_device_path, recursive); ++} ++ + void * + grub_efi_open_protocol (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, +diff --git a/include/grub/efi/disk.h b/include/grub/efi/disk.h +index 254475c842..6845c2f1fd 100644 +--- a/include/grub/efi/disk.h ++++ b/include/grub/efi/disk.h +@@ -27,6 +27,8 @@ grub_efi_handle_t + EXPORT_FUNC(grub_efidisk_get_device_handle) (grub_disk_t disk); + char *EXPORT_FUNC(grub_efidisk_get_device_name) (grub_efi_handle_t *handle); + ++void EXPORT_FUNC(grub_efidisk_reenumerate_disks) (void); ++ + void grub_efidisk_init (void); + void grub_efidisk_fini (void); + +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 8dfc89a33b..ec52083c49 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -41,6 +41,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type, + grub_efi_guid_t *protocol, + void *search_key, + grub_efi_uintn_t *num_handles); ++grub_efi_status_t ++EXPORT_FUNC(grub_efi_connect_controller) (grub_efi_handle_t controller_handle, ++ grub_efi_handle_t *driver_image_handle, ++ grub_efi_device_path_protocol_t *remaining_device_path, ++ grub_efi_boolean_t recursive); + void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + grub_efi_uint32_t attributes); +diff --git a/NEWS b/NEWS +index 73b8492bc4..d7c1d23aed 100644 +--- a/NEWS ++++ b/NEWS +@@ -98,7 +98,7 @@ New in 2.02: + * Prefer pmtimer for TSC calibration. + + * New/improved platform support: +- * New `efifwsetup' and `lsefi' commands on EFI platforms. ++ * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms. + * New `cmosdump' and `cmosset' commands on platforms with CMOS support. + * New command `pcidump' for PCI platforms. + * Improve opcode parsing in ACPI halt implementation. diff --git a/0209-search-new-efidisk-only-option-on-EFI-systems.patch b/0209-search-new-efidisk-only-option-on-EFI-systems.patch deleted file mode 100644 index 3f6194a..0000000 --- a/0209-search-new-efidisk-only-option-on-EFI-systems.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Renaud=20M=C3=A9trich?= -Date: Tue, 8 Feb 2022 08:39:11 +0100 -Subject: [PATCH] search: new --efidisk-only option on EFI systems -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When using 'search' on EFI systems, we sometimes want to exclude devices -that are not EFI disks (e.g. md, lvm). -This is typically used when wanting to chainload when having a software -raid (md) for EFI partition: -with no option, 'search --file /EFI/redhat/shimx64.efi' sets root envvar -to 'md/boot_efi' which cannot be used for chainloading since there is no -effective EFI device behind. - -This commit also refactors handling of --no-floppy option. - -Signed-off-by: Renaud Métrich -[rharwood: apply rmetrich's flags initialization fix] -Signed-off-by: Robbie Harwood ---- - grub-core/commands/search.c | 27 +++++++++++++++++++++++---- - grub-core/commands/search_wrap.c | 18 ++++++++++++------ - include/grub/search.h | 15 ++++++++++++--- - 3 files changed, 47 insertions(+), 13 deletions(-) - -diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c -index 51656e361c..57d26ced8a 100644 ---- a/grub-core/commands/search.c -+++ b/grub-core/commands/search.c -@@ -47,7 +47,7 @@ struct search_ctx - { - const char *key; - const char *var; -- int no_floppy; -+ enum search_flags flags; - char **hints; - unsigned nhints; - int count; -@@ -62,10 +62,29 @@ iterate_device (const char *name, void *data) - int found = 0; - - /* Skip floppy drives when requested. */ -- if (ctx->no_floppy && -+ if (ctx->flags & SEARCH_FLAGS_NO_FLOPPY && - name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') - return 0; - -+ /* Limit to EFI disks when requested. */ -+ if (ctx->flags & SEARCH_FLAGS_EFIDISK_ONLY) -+ { -+ grub_device_t dev; -+ dev = grub_device_open (name); -+ if (! dev) -+ { -+ grub_errno = GRUB_ERR_NONE; -+ return 0; -+ } -+ if (! dev->disk || dev->disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID) -+ { -+ grub_device_close (dev); -+ grub_errno = GRUB_ERR_NONE; -+ return 0; -+ } -+ grub_device_close (dev); -+ } -+ - #ifdef DO_SEARCH_FS_UUID - #define compare_fn grub_strcasecmp - #else -@@ -261,13 +280,13 @@ try (struct search_ctx *ctx) - } - - void --FUNC_NAME (const char *key, const char *var, int no_floppy, -+FUNC_NAME (const char *key, const char *var, enum search_flags flags, - char **hints, unsigned nhints) - { - struct search_ctx ctx = { - .key = key, - .var = var, -- .no_floppy = no_floppy, -+ .flags = flags, - .hints = hints, - .nhints = nhints, - .count = 0, -diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c -index 47fc8eb996..0b62acf853 100644 ---- a/grub-core/commands/search_wrap.c -+++ b/grub-core/commands/search_wrap.c -@@ -40,6 +40,7 @@ static const struct grub_arg_option options[] = - N_("Set a variable to the first device found."), N_("VARNAME"), - ARG_TYPE_STRING}, - {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, -+ {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0}, - {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, - N_("First try the device HINT. If HINT ends in comma, " - "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, -@@ -73,6 +74,7 @@ enum options - SEARCH_FS_UUID, - SEARCH_SET, - SEARCH_NO_FLOPPY, -+ SEARCH_EFIDISK_ONLY, - SEARCH_HINT, - SEARCH_HINT_IEEE1275, - SEARCH_HINT_BIOS, -@@ -89,6 +91,7 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) - const char *id = 0; - int i = 0, j = 0, nhints = 0; - char **hints = NULL; -+ enum search_flags flags = 0; - - if (state[SEARCH_HINT].set) - for (i = 0; state[SEARCH_HINT].args[i]; i++) -@@ -180,15 +183,18 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) - goto out; - } - -+ if (state[SEARCH_NO_FLOPPY].set) -+ flags |= SEARCH_FLAGS_NO_FLOPPY; -+ -+ if (state[SEARCH_EFIDISK_ONLY].set) -+ flags |= SEARCH_FLAGS_EFIDISK_ONLY; -+ - if (state[SEARCH_LABEL].set) -- grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, -- hints, nhints); -+ grub_search_label (id, var, flags, hints, nhints); - else if (state[SEARCH_FS_UUID].set) -- grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set, -- hints, nhints); -+ grub_search_fs_uuid (id, var, flags, hints, nhints); - else if (state[SEARCH_FILE].set) -- grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, -- hints, nhints); -+ grub_search_fs_file (id, var, flags, hints, nhints); - else - grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); - -diff --git a/include/grub/search.h b/include/grub/search.h -index d80347df34..4190aeb2cb 100644 ---- a/include/grub/search.h -+++ b/include/grub/search.h -@@ -19,11 +19,20 @@ - #ifndef GRUB_SEARCH_HEADER - #define GRUB_SEARCH_HEADER 1 - --void grub_search_fs_file (const char *key, const char *var, int no_floppy, -+enum search_flags -+ { -+ SEARCH_FLAGS_NO_FLOPPY = 1, -+ SEARCH_FLAGS_EFIDISK_ONLY = 2 -+ }; -+ -+void grub_search_fs_file (const char *key, const char *var, -+ enum search_flags flags, - char **hints, unsigned nhints); --void grub_search_fs_uuid (const char *key, const char *var, int no_floppy, -+void grub_search_fs_uuid (const char *key, const char *var, -+ enum search_flags flags, - char **hints, unsigned nhints); --void grub_search_label (const char *key, const char *var, int no_floppy, -+void grub_search_label (const char *key, const char *var, -+ enum search_flags flags, - char **hints, unsigned nhints); - - #endif diff --git a/0210-efi-new-connectefi-command.patch b/0210-efi-new-connectefi-command.patch deleted file mode 100644 index 55a49fd..0000000 --- a/0210-efi-new-connectefi-command.patch +++ /dev/null @@ -1,395 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Renaud=20M=C3=A9trich?= -Date: Tue, 15 Feb 2022 14:05:22 +0100 -Subject: [PATCH] efi: new 'connectefi' command -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When efi.quickboot is enabled on VMWare (which is the default for -hardware release 16 and later), it may happen that not all EFI devices -are connected. Due to this, browsing the devices in make_devices() just -fails to find devices, in particular disks or partitions for a given -disk. -This typically happens when network booting, then trying to chainload to -local disk (this is used in deployment tools such as Red Hat Satellite), -which is done through using the following grub.cfg snippet: --------- 8< ---------------- 8< ---------------- 8< -------- -unset prefix -search --file --set=prefix /EFI/redhat/grubx64.efi -if [ -n "$prefix" ]; then - chainloader ($prefix)/EFI/redhat/grubx64/efi -... --------- 8< ---------------- 8< ---------------- 8< -------- - -With efi.quickboot, none of the devices are connected, causing "search" -to fail. Sometimes devices are connected but not the partition of the -disk matching $prefix, causing partition to not be found by -"chainloader". - -This patch introduces a new "connectefi pciroot|scsi" command which -recursively connects all EFI devices starting from a given controller -type: -- if 'pciroot' is specified, recursion is performed for all PCI root - handles -- if 'scsi' is specified, recursion is performed for all SCSI I/O - handles (recommended usage to avoid connecting unwanted handles which - may impact Grub performances) - -Typical grub.cfg snippet would then be: --------- 8< ---------------- 8< ---------------- 8< -------- -connectefi scsi -unset prefix -search --file --set=prefix /EFI/redhat/grubx64.efi -if [ -n "$prefix" ]; then - chainloader ($prefix)/EFI/redhat/grubx64/efi -... --------- 8< ---------------- 8< ---------------- 8< -------- - -The code is easily extensible to handle other arguments in the future if -needed. - -Signed-off-by: Renaud Métrich -Signed-off-by: Robbie Harwood ---- - grub-core/Makefile.core.def | 6 ++ - grub-core/commands/efi/connectefi.c | 205 ++++++++++++++++++++++++++++++++++++ - grub-core/commands/efi/lsefi.c | 1 + - grub-core/disk/efi/efidisk.c | 13 +++ - grub-core/kern/efi/efi.c | 13 +++ - include/grub/efi/disk.h | 2 + - include/grub/efi/efi.h | 5 + - NEWS | 2 +- - 8 files changed, 246 insertions(+), 1 deletion(-) - create mode 100644 grub-core/commands/efi/connectefi.c - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 39233096f2..3c0ac3b7bd 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -836,6 +836,12 @@ module = { - enable = efi; - }; - -+module = { -+ name = connectefi; -+ common = commands/efi/connectefi.c; -+ enable = efi; -+}; -+ - module = { - name = blocklist; - common = commands/blocklist.c; -diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c -new file mode 100644 -index 0000000000..8ab75bd51b ---- /dev/null -+++ b/grub-core/commands/efi/connectefi.c -@@ -0,0 +1,205 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2022 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+typedef struct handle_list -+{ -+ grub_efi_handle_t handle; -+ struct handle_list *next; -+} handle_list_t; -+ -+static handle_list_t *already_handled = NULL; -+ -+static grub_err_t -+add_handle (grub_efi_handle_t handle) -+{ -+ handle_list_t *e; -+ e = grub_malloc (sizeof (*e)); -+ if (! e) -+ return grub_errno; -+ e->handle = handle; -+ e->next = already_handled; -+ already_handled = e; -+ return GRUB_ERR_NONE; -+} -+ -+static int -+is_in_list (grub_efi_handle_t handle) -+{ -+ handle_list_t *e; -+ for (e = already_handled; e != NULL; e = e->next) -+ if (e->handle == handle) -+ return 1; -+ return 0; -+} -+ -+static void -+free_handle_list (void) -+{ -+ handle_list_t *e; -+ while ((e = already_handled) != NULL) -+ { -+ already_handled = already_handled->next; -+ grub_free (e); -+ } -+} -+ -+typedef enum searched_item_flag -+{ -+ SEARCHED_ITEM_FLAG_LOOP = 1, -+ SEARCHED_ITEM_FLAG_RECURSIVE = 2 -+} searched_item_flags; -+ -+typedef struct searched_item -+{ -+ grub_efi_guid_t guid; -+ const char *name; -+ searched_item_flags flags; -+} searched_items; -+ -+static grub_err_t -+grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)), -+ int argc, char **args) -+{ -+ unsigned s; -+ searched_items pciroot_items[] = -+ { -+ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE } -+ }; -+ searched_items scsi_items[] = -+ { -+ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", 0 }, -+ { GRUB_EFI_PCI_IO_GUID, "PCI", SEARCHED_ITEM_FLAG_LOOP }, -+ { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE } -+ }; -+ searched_items *items = NULL; -+ unsigned nitems = 0; -+ grub_err_t grub_err = GRUB_ERR_NONE; -+ unsigned total_connected = 0; -+ -+ if (argc != 1) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); -+ -+ if (grub_strcmp(args[0], N_("pciroot")) == 0) -+ { -+ items = pciroot_items; -+ nitems = ARRAY_SIZE (pciroot_items); -+ } -+ else if (grub_strcmp(args[0], N_("scsi")) == 0) -+ { -+ items = scsi_items; -+ nitems = ARRAY_SIZE (scsi_items); -+ } -+ else -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, -+ N_("unexpected argument `%s'"), args[0]); -+ -+ for (s = 0; s < nitems; s++) -+ { -+ grub_efi_handle_t *handles; -+ grub_efi_uintn_t num_handles; -+ unsigned i, connected = 0, loop = 0; -+ -+loop: -+ loop++; -+ grub_dprintf ("efi", "step '%s' loop %d:\n", items[s].name, loop); -+ -+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, -+ &items[s].guid, 0, &num_handles); -+ -+ if (!handles) -+ continue; -+ -+ for (i = 0; i < num_handles; i++) -+ { -+ grub_efi_handle_t handle = handles[i]; -+ grub_efi_status_t status; -+ unsigned j; -+ -+ /* Skip already handled handles */ -+ if (is_in_list (handle)) -+ { -+ grub_dprintf ("efi", " handle %p: already processed\n", -+ handle); -+ continue; -+ } -+ -+ status = grub_efi_connect_controller(handle, NULL, NULL, -+ items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0); -+ if (status == GRUB_EFI_SUCCESS) -+ { -+ connected++; -+ total_connected++; -+ grub_dprintf ("efi", " handle %p: connected\n", handle); -+ } -+ else -+ grub_dprintf ("efi", " handle %p: failed to connect (%d)\n", -+ handle, (grub_efi_int8_t) status); -+ -+ if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE) -+ break; /* fatal */ -+ } -+ -+ grub_free (handles); -+ if (grub_err != GRUB_ERR_NONE) -+ break; /* fatal */ -+ -+ if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected) -+ { -+ connected = 0; -+ goto loop; -+ } -+ -+ free_handle_list (); -+ } -+ -+ free_handle_list (); -+ -+ if (total_connected) -+ grub_efidisk_reenumerate_disks (); -+ -+ return grub_err; -+} -+ -+static grub_command_t cmd; -+ -+GRUB_MOD_INIT(connectefi) -+{ -+ cmd = grub_register_command ("connectefi", grub_cmd_connectefi, -+ N_("pciroot|scsi"), -+ N_("Connect EFI handles." -+ " If 'pciroot' is specified, connect PCI" -+ " root EFI handles recursively." -+ " If 'scsi' is specified, connect SCSI" -+ " I/O EFI handles recursively.")); -+} -+ -+GRUB_MOD_FINI(connectefi) -+{ -+ grub_unregister_command (cmd); -+} -diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c -index d1ce99af43..f2d2430e66 100644 ---- a/grub-core/commands/efi/lsefi.c -+++ b/grub-core/commands/efi/lsefi.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - #include - #include -diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c -index fe8ba6e6c9..062143dfff 100644 ---- a/grub-core/disk/efi/efidisk.c -+++ b/grub-core/disk/efi/efidisk.c -@@ -396,6 +396,19 @@ enumerate_disks (void) - free_devices (devices); - } - -+void -+grub_efidisk_reenumerate_disks (void) -+{ -+ free_devices (fd_devices); -+ free_devices (hd_devices); -+ free_devices (cd_devices); -+ fd_devices = 0; -+ hd_devices = 0; -+ cd_devices = 0; -+ -+ enumerate_disks (); -+} -+ - static int - grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, - grub_disk_pull_t pull) -diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c -index 14bc10eb56..7fcca69c17 100644 ---- a/grub-core/kern/efi/efi.c -+++ b/grub-core/kern/efi/efi.c -@@ -95,6 +95,19 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, - return buffer; - } - -+grub_efi_status_t -+grub_efi_connect_controller (grub_efi_handle_t controller_handle, -+ grub_efi_handle_t *driver_image_handle, -+ grub_efi_device_path_protocol_t *remaining_device_path, -+ grub_efi_boolean_t recursive) -+{ -+ grub_efi_boot_services_t *b; -+ -+ b = grub_efi_system_table->boot_services; -+ return efi_call_4 (b->connect_controller, controller_handle, -+ driver_image_handle, remaining_device_path, recursive); -+} -+ - void * - grub_efi_open_protocol (grub_efi_handle_t handle, - grub_efi_guid_t *protocol, -diff --git a/include/grub/efi/disk.h b/include/grub/efi/disk.h -index 254475c842..6845c2f1fd 100644 ---- a/include/grub/efi/disk.h -+++ b/include/grub/efi/disk.h -@@ -27,6 +27,8 @@ grub_efi_handle_t - EXPORT_FUNC(grub_efidisk_get_device_handle) (grub_disk_t disk); - char *EXPORT_FUNC(grub_efidisk_get_device_name) (grub_efi_handle_t *handle); - -+void EXPORT_FUNC(grub_efidisk_reenumerate_disks) (void); -+ - void grub_efidisk_init (void); - void grub_efidisk_fini (void); - -diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h -index 8dfc89a33b..ec52083c49 100644 ---- a/include/grub/efi/efi.h -+++ b/include/grub/efi/efi.h -@@ -41,6 +41,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type, - grub_efi_guid_t *protocol, - void *search_key, - grub_efi_uintn_t *num_handles); -+grub_efi_status_t -+EXPORT_FUNC(grub_efi_connect_controller) (grub_efi_handle_t controller_handle, -+ grub_efi_handle_t *driver_image_handle, -+ grub_efi_device_path_protocol_t *remaining_device_path, -+ grub_efi_boolean_t recursive); - void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle, - grub_efi_guid_t *protocol, - grub_efi_uint32_t attributes); -diff --git a/NEWS b/NEWS -index 73b8492bc4..d7c1d23aed 100644 ---- a/NEWS -+++ b/NEWS -@@ -98,7 +98,7 @@ New in 2.02: - * Prefer pmtimer for TSC calibration. - - * New/improved platform support: -- * New `efifwsetup' and `lsefi' commands on EFI platforms. -+ * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms. - * New `cmosdump' and `cmosset' commands on platforms with CMOS support. - * New command `pcidump' for PCI platforms. - * Improve opcode parsing in ACPI halt implementation. diff --git a/0210-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch b/0210-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch new file mode 100644 index 0000000..4fe8adf --- /dev/null +++ b/0210-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Thu, 3 Mar 2022 13:10:56 +0100 +Subject: [PATCH] grub-core/loader/i386/efi/linux.c: do not validate kernels + twice + +On codebases that have shim-lock-verifier built into the grub core +(like 2.06 upstream), shim-lock-verifier is in enforcing mode when +booted with secureboot. It means that grub_cmd_linux() command +attempts to perform shim validate upon opening linux kernel image, +including kernel measurement. And the verifier correctly returns file +open error when shim validate protocol is not present or shim fails to +validate the kernel. + +This makes the call to grub_linuxefi_secure_validate() redundant, but +also harmful. As validating the kernel image twice, extends the PCRs +with the same measurement twice. Which breaks existing sealing +policies when upgrading from grub2.04+rhboot+sb+linuxefi to +grub2.06+rhboot+sb+linuxefi builds. It is also incorrect to measure +the kernel twice. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +This patch is tested to ensure that unsigned kernels are not possible +to boot in secureboot mode when shim rejects kernel, or shim protocol +is missing, and that the measurements become stable once again. The +above also ensures that CVE-2020-15705 is not reintroduced. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/i386/efi/linux.c | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 3cf0f9b330..941df6400b 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -30,7 +30,6 @@ + #include + #include + #include +-#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -278,7 +277,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_ssize_t start, filelen; + void *kernel = NULL; + int setup_header_end_offset; +- int rc; + + grub_dl_ref (my_mod); + +@@ -308,17 +306,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) +- { +- rc = grub_linuxefi_secure_validate (kernel, filelen); +- if (rc <= 0) +- { +- grub_error (GRUB_ERR_INVALID_COMMAND, +- N_("%s has invalid signature"), argv[0]); +- goto fail; +- } +- } +- + lh = (struct linux_i386_kernel_header *)kernel; + grub_dprintf ("linux", "original lh is at %p\n", kernel); + diff --git a/0211-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch b/0211-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch new file mode 100644 index 0000000..5b450f9 --- /dev/null +++ b/0211-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 4 Mar 2022 11:29:31 +0100 +Subject: [PATCH] grub-core/loader/arm64/linux.c: do not validate kernel twice + +Call to grub_file_open(, GRUB_FILE_TYPE_LINUX_KERNEL) already passes +the kernel file through shim-lock verifier when secureboot is on. Thus +there is no need to validate the kernel image again. And when doing so +again, duplicate PCR measurement is performed, breaking measurements +compatibility with 2.04+linuxefi. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/arm64/linux.c | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index f18d90bd74..d2af47c2c0 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -341,7 +340,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_off_t filelen; + grub_uint32_t align; + void *kernel = NULL; +- int rc; + + grub_dl_ref (my_mod); + +@@ -370,17 +368,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) +- { +- rc = grub_linuxefi_secure_validate (kernel, filelen); +- if (rc <= 0) +- { +- grub_error (GRUB_ERR_INVALID_COMMAND, +- N_("%s has invalid signature"), argv[0]); +- goto fail; +- } +- } +- + if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) + goto fail; + if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) diff --git a/0211-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch b/0211-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch deleted file mode 100644 index 4fe8adf..0000000 --- a/0211-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dimitri John Ledkov -Date: Thu, 3 Mar 2022 13:10:56 +0100 -Subject: [PATCH] grub-core/loader/i386/efi/linux.c: do not validate kernels - twice - -On codebases that have shim-lock-verifier built into the grub core -(like 2.06 upstream), shim-lock-verifier is in enforcing mode when -booted with secureboot. It means that grub_cmd_linux() command -attempts to perform shim validate upon opening linux kernel image, -including kernel measurement. And the verifier correctly returns file -open error when shim validate protocol is not present or shim fails to -validate the kernel. - -This makes the call to grub_linuxefi_secure_validate() redundant, but -also harmful. As validating the kernel image twice, extends the PCRs -with the same measurement twice. Which breaks existing sealing -policies when upgrading from grub2.04+rhboot+sb+linuxefi to -grub2.06+rhboot+sb+linuxefi builds. It is also incorrect to measure -the kernel twice. - -This patch must not be ported to older editions of grub code bases -that do not have verifiers framework, or it is not builtin, or -shim-lock-verifier is an optional module. - -This patch is tested to ensure that unsigned kernels are not possible -to boot in secureboot mode when shim rejects kernel, or shim protocol -is missing, and that the measurements become stable once again. The -above also ensures that CVE-2020-15705 is not reintroduced. - -Signed-off-by: Dimitri John Ledkov ---- - grub-core/loader/i386/efi/linux.c | 13 ------------- - 1 file changed, 13 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 3cf0f9b330..941df6400b 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -30,7 +30,6 @@ - #include - #include - #include --#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -278,7 +277,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_ssize_t start, filelen; - void *kernel = NULL; - int setup_header_end_offset; -- int rc; - - grub_dl_ref (my_mod); - -@@ -308,17 +306,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -- if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) -- { -- rc = grub_linuxefi_secure_validate (kernel, filelen); -- if (rc <= 0) -- { -- grub_error (GRUB_ERR_INVALID_COMMAND, -- N_("%s has invalid signature"), argv[0]); -- goto fail; -- } -- } -- - lh = (struct linux_i386_kernel_header *)kernel; - grub_dprintf ("linux", "original lh is at %p\n", kernel); - diff --git a/0212-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch b/0212-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch deleted file mode 100644 index 5b450f9..0000000 --- a/0212-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dimitri John Ledkov -Date: Fri, 4 Mar 2022 11:29:31 +0100 -Subject: [PATCH] grub-core/loader/arm64/linux.c: do not validate kernel twice - -Call to grub_file_open(, GRUB_FILE_TYPE_LINUX_KERNEL) already passes -the kernel file through shim-lock verifier when secureboot is on. Thus -there is no need to validate the kernel image again. And when doing so -again, duplicate PCR measurement is performed, breaking measurements -compatibility with 2.04+linuxefi. - -This patch must not be ported to older editions of grub code bases -that do not have verifiers framework, or it is not builtin, or -shim-lock-verifier is an optional module. - -Signed-off-by: Dimitri John Ledkov ---- - grub-core/loader/arm64/linux.c | 13 ------------- - 1 file changed, 13 deletions(-) - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index f18d90bd74..d2af47c2c0 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -34,7 +34,6 @@ - #include - #include - #include --#include - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -341,7 +340,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_off_t filelen; - grub_uint32_t align; - void *kernel = NULL; -- int rc; - - grub_dl_ref (my_mod); - -@@ -370,17 +368,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -- if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) -- { -- rc = grub_linuxefi_secure_validate (kernel, filelen); -- if (rc <= 0) -- { -- grub_error (GRUB_ERR_INVALID_COMMAND, -- N_("%s has invalid signature"), argv[0]); -- goto fail; -- } -- } -- - if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) - goto fail; - if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) diff --git a/0212-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch b/0212-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch new file mode 100644 index 0000000..4c56d60 --- /dev/null +++ b/0212-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 4 Mar 2022 09:31:43 +0100 +Subject: [PATCH] grub-core/loader/efi/chainloader.c: do not validate + chainloader twice + +On secureboot systems, with shimlock verifier, call to +grub_file_open(, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE) will already +pass the chainloader target through shim-lock protocol verify +call. And create a TPM measurement. If verification fails, +grub_cmd_chainloader will fail at file open time. + +This makes previous code paths for negative, and zero return codes +from grub_linuxefi_secure_validate unreachable under secureboot. But +also breaking measurements compatibility with 2.04+linuxefi codebases, +as the chainloader file is passed through shim_lock->verify() twice +(via verifier & direct call to grub_linuxefi_secure_validate) +extending the PCRs twice. + +This reduces grub_loader options to perform +grub_secureboot_chainloader when secureboot is on, and otherwise +attempt grub_chainloader_boot. + +It means that booting with secureboot off, yet still with shim (which +always verifies things successfully), will stop choosing +grub_secureboot_chainloader, and opting for a more regular +loadimage/startimage codepath. If we want to use the +grub_secureboot_chainloader codepath in such scenarios we should adapt +the code to simply check for shim_lock protocol presence / +shim_lock->context() success?! But I am not sure if that is necessary. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/efi/chainloader.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 3af6b12292..644cd2e56f 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -906,7 +906,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_device_path_t *dp = 0; + char *filename; + void *boot_image = 0; +- int rc; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -1082,9 +1081,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + orig_dev = 0; + } + +- rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize); +- grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); +- if (rc > 0) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { + grub_file_close (file); + grub_device_close (dev); +@@ -1092,7 +1089,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_secureboot_chainloader_unload, 0); + return 0; + } +- else if (rc == 0) ++ else + { + grub_load_and_start_image(boot_image); + grub_file_close (file); +@@ -1101,7 +1098,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + return 0; + } +- // -1 fall-through to fail + + fail: + if (orig_dev) diff --git a/0213-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch b/0213-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch deleted file mode 100644 index 4c56d60..0000000 --- a/0213-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dimitri John Ledkov -Date: Fri, 4 Mar 2022 09:31:43 +0100 -Subject: [PATCH] grub-core/loader/efi/chainloader.c: do not validate - chainloader twice - -On secureboot systems, with shimlock verifier, call to -grub_file_open(, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE) will already -pass the chainloader target through shim-lock protocol verify -call. And create a TPM measurement. If verification fails, -grub_cmd_chainloader will fail at file open time. - -This makes previous code paths for negative, and zero return codes -from grub_linuxefi_secure_validate unreachable under secureboot. But -also breaking measurements compatibility with 2.04+linuxefi codebases, -as the chainloader file is passed through shim_lock->verify() twice -(via verifier & direct call to grub_linuxefi_secure_validate) -extending the PCRs twice. - -This reduces grub_loader options to perform -grub_secureboot_chainloader when secureboot is on, and otherwise -attempt grub_chainloader_boot. - -It means that booting with secureboot off, yet still with shim (which -always verifies things successfully), will stop choosing -grub_secureboot_chainloader, and opting for a more regular -loadimage/startimage codepath. If we want to use the -grub_secureboot_chainloader codepath in such scenarios we should adapt -the code to simply check for shim_lock protocol presence / -shim_lock->context() success?! But I am not sure if that is necessary. - -This patch must not be ported to older editions of grub code bases -that do not have verifiers framework, or it is not builtin, or -shim-lock-verifier is an optional module. - -Signed-off-by: Dimitri John Ledkov ---- - grub-core/loader/efi/chainloader.c | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index 3af6b12292..644cd2e56f 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -906,7 +906,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - grub_efi_device_path_t *dp = 0; - char *filename; - void *boot_image = 0; -- int rc; - - if (argc == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); -@@ -1082,9 +1081,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - orig_dev = 0; - } - -- rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize); -- grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); -- if (rc > 0) -+ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) - { - grub_file_close (file); - grub_device_close (dev); -@@ -1092,7 +1089,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - grub_secureboot_chainloader_unload, 0); - return 0; - } -- else if (rc == 0) -+ else - { - grub_load_and_start_image(boot_image); - grub_file_close (file); -@@ -1101,7 +1098,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - - return 0; - } -- // -1 fall-through to fail - - fail: - if (orig_dev) diff --git a/0213-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch b/0213-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch new file mode 100644 index 0000000..c683fcb --- /dev/null +++ b/0213-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 4 Mar 2022 11:36:09 +0100 +Subject: [PATCH] grub-core/loader/efi/linux.c: drop now unused + grub_linuxefi_secure_validate + +Drop the now unused grub_linuxefi_secure_validate() as all prior users +of this API now rely on the shim-lock-verifier codepath instead. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/efi/linux.c | 40 ---------------------------------------- + include/grub/efi/linux.h | 2 -- + 2 files changed, 42 deletions(-) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 9260731c10..9265cf4200 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -24,46 +24,6 @@ + #include + #include + +-#define SHIM_LOCK_GUID \ +- { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } +- +-struct grub_efi_shim_lock +-{ +- grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size); +-}; +-typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; +- +-// Returns 1 on success, -1 on error, 0 when not available +-int +-grub_linuxefi_secure_validate (void *data, grub_uint32_t size) +-{ +- grub_efi_guid_t guid = SHIM_LOCK_GUID; +- grub_efi_shim_lock_t *shim_lock; +- grub_efi_status_t status; +- +- shim_lock = grub_efi_locate_protocol(&guid, NULL); +- grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock); +- if (!shim_lock) +- { +- grub_dprintf ("secureboot", "shim not available\n"); +- return 0; +- } +- +- grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n"); +- status = shim_lock->verify (data, size); +- grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status); +- if (status == GRUB_EFI_SUCCESS) +- { +- grub_dprintf ("secureboot", "Kernel signature verification passed\n"); +- return 1; +- } +- +- grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n", +- (unsigned long) status); +- +- return -1; +-} +- + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +index 0033d9305a..887b02fd9f 100644 +--- a/include/grub/efi/linux.h ++++ b/include/grub/efi/linux.h +@@ -22,8 +22,6 @@ + #include + #include + +-int +-EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size); + grub_err_t + EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, + void *kernel_param); diff --git a/0214-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch b/0214-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch deleted file mode 100644 index c683fcb..0000000 --- a/0214-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dimitri John Ledkov -Date: Fri, 4 Mar 2022 11:36:09 +0100 -Subject: [PATCH] grub-core/loader/efi/linux.c: drop now unused - grub_linuxefi_secure_validate - -Drop the now unused grub_linuxefi_secure_validate() as all prior users -of this API now rely on the shim-lock-verifier codepath instead. - -This patch must not be ported to older editions of grub code bases -that do not have verifiers framework, or it is not builtin, or -shim-lock-verifier is an optional module. - -Signed-off-by: Dimitri John Ledkov ---- - grub-core/loader/efi/linux.c | 40 ---------------------------------------- - include/grub/efi/linux.h | 2 -- - 2 files changed, 42 deletions(-) - -diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c -index 9260731c10..9265cf4200 100644 ---- a/grub-core/loader/efi/linux.c -+++ b/grub-core/loader/efi/linux.c -@@ -24,46 +24,6 @@ - #include - #include - --#define SHIM_LOCK_GUID \ -- { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } -- --struct grub_efi_shim_lock --{ -- grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size); --}; --typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; -- --// Returns 1 on success, -1 on error, 0 when not available --int --grub_linuxefi_secure_validate (void *data, grub_uint32_t size) --{ -- grub_efi_guid_t guid = SHIM_LOCK_GUID; -- grub_efi_shim_lock_t *shim_lock; -- grub_efi_status_t status; -- -- shim_lock = grub_efi_locate_protocol(&guid, NULL); -- grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock); -- if (!shim_lock) -- { -- grub_dprintf ("secureboot", "shim not available\n"); -- return 0; -- } -- -- grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n"); -- status = shim_lock->verify (data, size); -- grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status); -- if (status == GRUB_EFI_SUCCESS) -- { -- grub_dprintf ("secureboot", "Kernel signature verification passed\n"); -- return 1; -- } -- -- grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n", -- (unsigned long) status); -- -- return -1; --} -- - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - -diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h -index 0033d9305a..887b02fd9f 100644 ---- a/include/grub/efi/linux.h -+++ b/include/grub/efi/linux.h -@@ -22,8 +22,6 @@ - #include - #include - --int --EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size); - grub_err_t - EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, - void *kernel_param); diff --git a/0214-powerpc-do-CAS-in-a-more-compatible-way.patch b/0214-powerpc-do-CAS-in-a-more-compatible-way.patch new file mode 100644 index 0000000..20b95f7 --- /dev/null +++ b/0214-powerpc-do-CAS-in-a-more-compatible-way.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 8 Apr 2022 12:35:28 +1000 +Subject: [PATCH] powerpc: do CAS in a more compatible way + +I wrongly assumed that the most compatible way to perform CAS +negotiation was to only set the minimum number of vectors required +to ask for more memory. It turns out that this messes up booting +if the minimum VP capacity would be less than the default 10% in +vector 4. + +Linux configures the minimum capacity to be 1%, so copy it for that +and for vector 3 which we now need to specify as well. + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/ieee1275/init.c | 54 ++++++++++++++++++++++++------------------ + 1 file changed, 31 insertions(+), 23 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 9704715c83..ef55107467 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -298,33 +298,37 @@ grub_ieee1275_total_mem (grub_uint64_t *total) + + /* Based on linux - arch/powerpc/kernel/prom_init.c */ + struct option_vector2 { +- grub_uint8_t byte1; +- grub_uint16_t reserved; +- grub_uint32_t real_base; +- grub_uint32_t real_size; +- grub_uint32_t virt_base; +- grub_uint32_t virt_size; +- grub_uint32_t load_base; +- grub_uint32_t min_rma; +- grub_uint32_t min_load; +- grub_uint8_t min_rma_percent; +- grub_uint8_t max_pft_size; ++ grub_uint8_t byte1; ++ grub_uint16_t reserved; ++ grub_uint32_t real_base; ++ grub_uint32_t real_size; ++ grub_uint32_t virt_base; ++ grub_uint32_t virt_size; ++ grub_uint32_t load_base; ++ grub_uint32_t min_rma; ++ grub_uint32_t min_load; ++ grub_uint8_t min_rma_percent; ++ grub_uint8_t max_pft_size; + } __attribute__((packed)); + + struct pvr_entry { +- grub_uint32_t mask; +- grub_uint32_t entry; ++ grub_uint32_t mask; ++ grub_uint32_t entry; + }; + + struct cas_vector { +- struct { +- struct pvr_entry terminal; +- } pvr_list; +- grub_uint8_t num_vecs; +- grub_uint8_t vec1_size; +- grub_uint8_t vec1; +- grub_uint8_t vec2_size; +- struct option_vector2 vec2; ++ struct { ++ struct pvr_entry terminal; ++ } pvr_list; ++ grub_uint8_t num_vecs; ++ grub_uint8_t vec1_size; ++ grub_uint8_t vec1; ++ grub_uint8_t vec2_size; ++ struct option_vector2 vec2; ++ grub_uint8_t vec3_size; ++ grub_uint16_t vec3; ++ grub_uint8_t vec4_size; ++ grub_uint16_t vec4; + } __attribute__((packed)); + + /* Call ibm,client-architecture-support to try to get more RMA. +@@ -345,13 +349,17 @@ grub_ieee1275_ibm_cas (void) + } args; + struct cas_vector vector = { + .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +- .num_vecs = 2 - 1, ++ .num_vecs = 4 - 1, + .vec1_size = 0, + .vec1 = 0x80, /* ignore */ + .vec2_size = 1 + sizeof(struct option_vector2) - 2, + .vec2 = { + 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 + }, ++ .vec3_size = 2 - 1, ++ .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied ++ .vec4_size = 2 - 1, ++ .vec4 = 0x0001, // set required minimum capacity % to the lowest value + }; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); +@@ -364,7 +372,7 @@ grub_ieee1275_ibm_cas (void) + args.ihandle = root; + args.cas_addr = (grub_ieee1275_cell_t)&vector; + +- grub_printf("Calling ibm,client-architecture-support..."); ++ grub_printf("Calling ibm,client-architecture-support from grub..."); + IEEE1275_CALL_ENTRY_FN (&args); + grub_printf("done\n"); + diff --git a/0215-powerpc-do-CAS-in-a-more-compatible-way.patch b/0215-powerpc-do-CAS-in-a-more-compatible-way.patch deleted file mode 100644 index 20b95f7..0000000 --- a/0215-powerpc-do-CAS-in-a-more-compatible-way.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 8 Apr 2022 12:35:28 +1000 -Subject: [PATCH] powerpc: do CAS in a more compatible way - -I wrongly assumed that the most compatible way to perform CAS -negotiation was to only set the minimum number of vectors required -to ask for more memory. It turns out that this messes up booting -if the minimum VP capacity would be less than the default 10% in -vector 4. - -Linux configures the minimum capacity to be 1%, so copy it for that -and for vector 3 which we now need to specify as well. - -Signed-off-by: Daniel Axtens ---- - grub-core/kern/ieee1275/init.c | 54 ++++++++++++++++++++++++------------------ - 1 file changed, 31 insertions(+), 23 deletions(-) - -diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index 9704715c83..ef55107467 100644 ---- a/grub-core/kern/ieee1275/init.c -+++ b/grub-core/kern/ieee1275/init.c -@@ -298,33 +298,37 @@ grub_ieee1275_total_mem (grub_uint64_t *total) - - /* Based on linux - arch/powerpc/kernel/prom_init.c */ - struct option_vector2 { -- grub_uint8_t byte1; -- grub_uint16_t reserved; -- grub_uint32_t real_base; -- grub_uint32_t real_size; -- grub_uint32_t virt_base; -- grub_uint32_t virt_size; -- grub_uint32_t load_base; -- grub_uint32_t min_rma; -- grub_uint32_t min_load; -- grub_uint8_t min_rma_percent; -- grub_uint8_t max_pft_size; -+ grub_uint8_t byte1; -+ grub_uint16_t reserved; -+ grub_uint32_t real_base; -+ grub_uint32_t real_size; -+ grub_uint32_t virt_base; -+ grub_uint32_t virt_size; -+ grub_uint32_t load_base; -+ grub_uint32_t min_rma; -+ grub_uint32_t min_load; -+ grub_uint8_t min_rma_percent; -+ grub_uint8_t max_pft_size; - } __attribute__((packed)); - - struct pvr_entry { -- grub_uint32_t mask; -- grub_uint32_t entry; -+ grub_uint32_t mask; -+ grub_uint32_t entry; - }; - - struct cas_vector { -- struct { -- struct pvr_entry terminal; -- } pvr_list; -- grub_uint8_t num_vecs; -- grub_uint8_t vec1_size; -- grub_uint8_t vec1; -- grub_uint8_t vec2_size; -- struct option_vector2 vec2; -+ struct { -+ struct pvr_entry terminal; -+ } pvr_list; -+ grub_uint8_t num_vecs; -+ grub_uint8_t vec1_size; -+ grub_uint8_t vec1; -+ grub_uint8_t vec2_size; -+ struct option_vector2 vec2; -+ grub_uint8_t vec3_size; -+ grub_uint16_t vec3; -+ grub_uint8_t vec4_size; -+ grub_uint16_t vec4; - } __attribute__((packed)); - - /* Call ibm,client-architecture-support to try to get more RMA. -@@ -345,13 +349,17 @@ grub_ieee1275_ibm_cas (void) - } args; - struct cas_vector vector = { - .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ -- .num_vecs = 2 - 1, -+ .num_vecs = 4 - 1, - .vec1_size = 0, - .vec1 = 0x80, /* ignore */ - .vec2_size = 1 + sizeof(struct option_vector2) - 2, - .vec2 = { - 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 - }, -+ .vec3_size = 2 - 1, -+ .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied -+ .vec4_size = 2 - 1, -+ .vec4 = 0x0001, // set required minimum capacity % to the lowest value - }; - - INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); -@@ -364,7 +372,7 @@ grub_ieee1275_ibm_cas (void) - args.ihandle = root; - args.cas_addr = (grub_ieee1275_cell_t)&vector; - -- grub_printf("Calling ibm,client-architecture-support..."); -+ grub_printf("Calling ibm,client-architecture-support from grub..."); - IEEE1275_CALL_ENTRY_FN (&args); - grub_printf("done\n"); - diff --git a/0215-powerpc-prefix-detection-support-device-names-with-c.patch b/0215-powerpc-prefix-detection-support-device-names-with-c.patch new file mode 100644 index 0000000..1c16fd3 --- /dev/null +++ b/0215-powerpc-prefix-detection-support-device-names-with-c.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 24 Mar 2022 14:34:32 +1100 +Subject: [PATCH] powerpc: prefix detection: support device names with commas + +Frustratingly, the device name itself can contain an embedded comma: +e.g /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b + +So my previous approach was wrong: we cannot rely upon the presence +of a comma to say that a partition has been specified! + +It turns out for prefixes like (,gpt2)/grub2 we really want to make +up a full (device,partition)/patch prefix, because root discovery code +in 10_linux will reset the root variable and use search to fill it again. +If you have run grub-install, you probably don't have search built in, +and if you don't have prefix containing (device,partition), grub will +construct ($root)$prefix/powerpc-ieee1275/search.mod - but because $root +has just been changed, this will no longer work, and the boot will fail! + +Retain the gist of the logic, but instead of looking for a comma, look for +a leading '('. This matches the earlier code better anyway. + +There's certainly a better fix to be had. But any time you chose to build +with a bare prefix like '/grub2', you're almost certainly going to build in +search anyway, so this will do. + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/main.c | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 993b8a8598..e94a2f78fb 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -242,14 +242,29 @@ grub_set_prefix_and_root (void) + what sorts of paths represent disks with partition tables and those + without partition tables. + +- So we act unless there is a comma in the device, which would indicate +- a partition has already been specified. ++ - Frustratingly, the device name itself can contain an embedded comma: ++ /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b ++ So we cannot even rely upon the presence of a comma to say that a ++ partition has been specified! + +- (If we only have a path, the code in normal to discover config files +- will try both without partitions and then with any partitions so we +- will cover both CDs and HDs.) ++ If we only have a path in $prefix, the code in normal to discover ++ config files will try all disks, both without partitions and then with ++ any partitions so we will cover both CDs and HDs. ++ ++ However, it doesn't then set the prefix to be something like ++ (discovered partition)/path, and so it is fragile against runtime ++ changes to $root. For example some of the stuff done in 10_linux to ++ reload $root sets root differently and then uses search to find it ++ again. If the search module is not built in, when we change root, grub ++ will look in (new root)/path/powerpc-ieee1275, that won't work, and we ++ will not be able to load the search module and the boot will fail. ++ ++ This is particularly likely to hit us in the grub-install ++ (,msdos2)/grub2 case, so we act unless the supplied prefix starts with ++ '(', which would likely indicate a partition has already been ++ specified. + */ +- if (grub_strchr (device, ',') == NULL) ++ if (prefix && prefix[0] != '(') + grub_env_set ("prefix", path); + else + #endif diff --git a/0216-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch b/0216-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch new file mode 100644 index 0000000..3c73469 --- /dev/null +++ b/0216-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch @@ -0,0 +1,236 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Sun, 15 Mar 2020 12:37:10 -0400 +Subject: [PATCH] ibmvtpm: Add support for trusted boot using a vTPM 2.0 + +Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275 +PowerPC platform. With this patch grub now measures text and binary data +into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform +does. + +This patch requires Daniel Axtens's patches for claiming more memory. + +For vTPM support to work on PowerVM, system driver levels 1010.30 +or 1020.00 are required. + +Note: Previous versions of firmware levels with the 2hash-ext-log +API call have a bug that, once this API call is invoked, has the +effect of disabling the vTPM driver under Linux causing an error +message to be displayed in the Linux kernel log. Those users will +have to update their machines to the firmware levels mentioned +above. + +Cc: Eric Snowberg +Signed-off-by: Stefan Berger +--- + grub-core/Makefile.core.def | 7 ++ + grub-core/commands/ieee1275/ibmvtpm.c | 152 ++++++++++++++++++++++++++++++++++ + include/grub/ieee1275/ieee1275.h | 3 + + docs/grub.texi | 3 +- + 4 files changed, 164 insertions(+), 1 deletion(-) + create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 3c0ac3b7bd..2c1608bca4 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1175,6 +1175,13 @@ module = { + enable = powerpc_ieee1275; + }; + ++module = { ++ name = tpm; ++ common = commands/tpm.c; ++ ieee1275 = commands/ieee1275/ibmvtpm.c; ++ enable = powerpc_ieee1275; ++}; ++ + module = { + name = terminal; + common = commands/terminal.c; +diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c +new file mode 100644 +index 0000000000..e68b8448bc +--- /dev/null ++++ b/grub-core/commands/ieee1275/ibmvtpm.c +@@ -0,0 +1,152 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 Free Software Foundation, Inc. ++ * Copyright (C) 2021 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ * ++ * IBM vTPM support code. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static grub_ieee1275_ihandle_t tpm_ihandle; ++static grub_uint8_t tpm_version; ++ ++#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0) ++ ++static void ++tpm_get_tpm_version (void) ++{ ++ grub_ieee1275_phandle_t vtpm; ++ char buffer[20]; ++ ++ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) && ++ !grub_ieee1275_get_property (vtpm, "compatible", buffer, ++ sizeof (buffer), NULL) && ++ !grub_strcmp (buffer, "IBM,vtpm20")) ++ tpm_version = 2; ++} ++ ++static grub_err_t ++tpm_init (void) ++{ ++ static int init_success = 0; ++ ++ if (!init_success) ++ { ++ if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) { ++ tpm_ihandle = IEEE1275_IHANDLE_INVALID; ++ return GRUB_ERR_UNKNOWN_DEVICE; ++ } ++ ++ init_success = 1; ++ ++ tpm_get_tpm_version (); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static int ++ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex, ++ grub_uint32_t eventtype, ++ const char *description, ++ grub_size_t description_size, ++ void *buf, grub_size_t size) ++{ ++ struct tpm_2hash_ext_log ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t size; ++ grub_ieee1275_cell_t buf; ++ grub_ieee1275_cell_t description_size; ++ grub_ieee1275_cell_t description; ++ grub_ieee1275_cell_t eventtype; ++ grub_ieee1275_cell_t pcrindex; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t rc; ++ } ++ args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2); ++ args.method = (grub_ieee1275_cell_t) "2hash-ext-log"; ++ args.ihandle = tpm_ihandle; ++ args.pcrindex = pcrindex; ++ args.eventtype = eventtype; ++ args.description = (grub_ieee1275_cell_t) description; ++ args.description_size = description_size; ++ args.buf = (grub_ieee1275_cell_t) buf; ++ args.size = (grub_ieee1275_cell_t) size; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ /* ++ * catch_result is set if firmware does not support 2hash-ext-log ++ * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure ++ */ ++ if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE) ++ return -1; ++ ++ return 0; ++} ++ ++static grub_err_t ++tpm2_log_event (unsigned char *buf, ++ grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ static int error_displayed = 0; ++ int err; ++ ++ err = ibmvtpm_2hash_ext_log (pcr, EV_IPL, ++ description, ++ grub_strlen(description) + 1, ++ buf, size); ++ if (err && !error_displayed) ++ { ++ error_displayed++; ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ "2HASH-EXT-LOG failed: Firmware is likely too old.\n"); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ grub_err_t err = tpm_init(); ++ ++ /* Absence of a TPM isn't a failure. */ ++ if (err != GRUB_ERR_NONE) ++ return GRUB_ERR_NONE; ++ ++ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n", ++ pcr, size, description); ++ ++ if (tpm_version == 2) ++ return tpm2_log_event (buf, size, pcr, description); ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index e0a6c2ce1e..f4c85265fe 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -24,6 +24,9 @@ + #include + #include + ++#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0) ++#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1) ++ + struct grub_ieee1275_mem_region + { + unsigned int start; +diff --git a/docs/grub.texi b/docs/grub.texi +index a4da9c2a1b..c433240f34 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6221,7 +6221,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built + into @file{core.img} in order to avoid a potential gap in measurement between + @file{core.img} being loaded and the tpm module being loaded. + +-Measured boot is currently only supported on EFI platforms. ++Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC ++platforms. + + @node Lockdown + @section Lockdown when booting on a secure setup diff --git a/0216-powerpc-prefix-detection-support-device-names-with-c.patch b/0216-powerpc-prefix-detection-support-device-names-with-c.patch deleted file mode 100644 index 1c16fd3..0000000 --- a/0216-powerpc-prefix-detection-support-device-names-with-c.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 24 Mar 2022 14:34:32 +1100 -Subject: [PATCH] powerpc: prefix detection: support device names with commas - -Frustratingly, the device name itself can contain an embedded comma: -e.g /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b - -So my previous approach was wrong: we cannot rely upon the presence -of a comma to say that a partition has been specified! - -It turns out for prefixes like (,gpt2)/grub2 we really want to make -up a full (device,partition)/patch prefix, because root discovery code -in 10_linux will reset the root variable and use search to fill it again. -If you have run grub-install, you probably don't have search built in, -and if you don't have prefix containing (device,partition), grub will -construct ($root)$prefix/powerpc-ieee1275/search.mod - but because $root -has just been changed, this will no longer work, and the boot will fail! - -Retain the gist of the logic, but instead of looking for a comma, look for -a leading '('. This matches the earlier code better anyway. - -There's certainly a better fix to be had. But any time you chose to build -with a bare prefix like '/grub2', you're almost certainly going to build in -search anyway, so this will do. - -Signed-off-by: Daniel Axtens ---- - grub-core/kern/main.c | 27 +++++++++++++++++++++------ - 1 file changed, 21 insertions(+), 6 deletions(-) - -diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c -index 993b8a8598..e94a2f78fb 100644 ---- a/grub-core/kern/main.c -+++ b/grub-core/kern/main.c -@@ -242,14 +242,29 @@ grub_set_prefix_and_root (void) - what sorts of paths represent disks with partition tables and those - without partition tables. - -- So we act unless there is a comma in the device, which would indicate -- a partition has already been specified. -+ - Frustratingly, the device name itself can contain an embedded comma: -+ /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b -+ So we cannot even rely upon the presence of a comma to say that a -+ partition has been specified! - -- (If we only have a path, the code in normal to discover config files -- will try both without partitions and then with any partitions so we -- will cover both CDs and HDs.) -+ If we only have a path in $prefix, the code in normal to discover -+ config files will try all disks, both without partitions and then with -+ any partitions so we will cover both CDs and HDs. -+ -+ However, it doesn't then set the prefix to be something like -+ (discovered partition)/path, and so it is fragile against runtime -+ changes to $root. For example some of the stuff done in 10_linux to -+ reload $root sets root differently and then uses search to find it -+ again. If the search module is not built in, when we change root, grub -+ will look in (new root)/path/powerpc-ieee1275, that won't work, and we -+ will not be able to load the search module and the boot will fail. -+ -+ This is particularly likely to hit us in the grub-install -+ (,msdos2)/grub2 case, so we act unless the supplied prefix starts with -+ '(', which would likely indicate a partition has already been -+ specified. - */ -- if (grub_strchr (device, ',') == NULL) -+ if (prefix && prefix[0] != '(') - grub_env_set ("prefix", path); - else - #endif diff --git a/0217-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch b/0217-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch deleted file mode 100644 index 3c73469..0000000 --- a/0217-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch +++ /dev/null @@ -1,236 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Stefan Berger -Date: Sun, 15 Mar 2020 12:37:10 -0400 -Subject: [PATCH] ibmvtpm: Add support for trusted boot using a vTPM 2.0 - -Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275 -PowerPC platform. With this patch grub now measures text and binary data -into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform -does. - -This patch requires Daniel Axtens's patches for claiming more memory. - -For vTPM support to work on PowerVM, system driver levels 1010.30 -or 1020.00 are required. - -Note: Previous versions of firmware levels with the 2hash-ext-log -API call have a bug that, once this API call is invoked, has the -effect of disabling the vTPM driver under Linux causing an error -message to be displayed in the Linux kernel log. Those users will -have to update their machines to the firmware levels mentioned -above. - -Cc: Eric Snowberg -Signed-off-by: Stefan Berger ---- - grub-core/Makefile.core.def | 7 ++ - grub-core/commands/ieee1275/ibmvtpm.c | 152 ++++++++++++++++++++++++++++++++++ - include/grub/ieee1275/ieee1275.h | 3 + - docs/grub.texi | 3 +- - 4 files changed, 164 insertions(+), 1 deletion(-) - create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c - -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 3c0ac3b7bd..2c1608bca4 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1175,6 +1175,13 @@ module = { - enable = powerpc_ieee1275; - }; - -+module = { -+ name = tpm; -+ common = commands/tpm.c; -+ ieee1275 = commands/ieee1275/ibmvtpm.c; -+ enable = powerpc_ieee1275; -+}; -+ - module = { - name = terminal; - common = commands/terminal.c; -diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c -new file mode 100644 -index 0000000000..e68b8448bc ---- /dev/null -+++ b/grub-core/commands/ieee1275/ibmvtpm.c -@@ -0,0 +1,152 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2021 Free Software Foundation, Inc. -+ * Copyright (C) 2021 IBM Corporation -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ * -+ * IBM vTPM support code. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static grub_ieee1275_ihandle_t tpm_ihandle; -+static grub_uint8_t tpm_version; -+ -+#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0) -+ -+static void -+tpm_get_tpm_version (void) -+{ -+ grub_ieee1275_phandle_t vtpm; -+ char buffer[20]; -+ -+ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) && -+ !grub_ieee1275_get_property (vtpm, "compatible", buffer, -+ sizeof (buffer), NULL) && -+ !grub_strcmp (buffer, "IBM,vtpm20")) -+ tpm_version = 2; -+} -+ -+static grub_err_t -+tpm_init (void) -+{ -+ static int init_success = 0; -+ -+ if (!init_success) -+ { -+ if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) { -+ tpm_ihandle = IEEE1275_IHANDLE_INVALID; -+ return GRUB_ERR_UNKNOWN_DEVICE; -+ } -+ -+ init_success = 1; -+ -+ tpm_get_tpm_version (); -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+static int -+ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex, -+ grub_uint32_t eventtype, -+ const char *description, -+ grub_size_t description_size, -+ void *buf, grub_size_t size) -+{ -+ struct tpm_2hash_ext_log -+ { -+ struct grub_ieee1275_common_hdr common; -+ grub_ieee1275_cell_t method; -+ grub_ieee1275_cell_t ihandle; -+ grub_ieee1275_cell_t size; -+ grub_ieee1275_cell_t buf; -+ grub_ieee1275_cell_t description_size; -+ grub_ieee1275_cell_t description; -+ grub_ieee1275_cell_t eventtype; -+ grub_ieee1275_cell_t pcrindex; -+ grub_ieee1275_cell_t catch_result; -+ grub_ieee1275_cell_t rc; -+ } -+ args; -+ -+ INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2); -+ args.method = (grub_ieee1275_cell_t) "2hash-ext-log"; -+ args.ihandle = tpm_ihandle; -+ args.pcrindex = pcrindex; -+ args.eventtype = eventtype; -+ args.description = (grub_ieee1275_cell_t) description; -+ args.description_size = description_size; -+ args.buf = (grub_ieee1275_cell_t) buf; -+ args.size = (grub_ieee1275_cell_t) size; -+ -+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) -+ return -1; -+ -+ /* -+ * catch_result is set if firmware does not support 2hash-ext-log -+ * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure -+ */ -+ if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE) -+ return -1; -+ -+ return 0; -+} -+ -+static grub_err_t -+tpm2_log_event (unsigned char *buf, -+ grub_size_t size, grub_uint8_t pcr, -+ const char *description) -+{ -+ static int error_displayed = 0; -+ int err; -+ -+ err = ibmvtpm_2hash_ext_log (pcr, EV_IPL, -+ description, -+ grub_strlen(description) + 1, -+ buf, size); -+ if (err && !error_displayed) -+ { -+ error_displayed++; -+ return grub_error (GRUB_ERR_BAD_DEVICE, -+ "2HASH-EXT-LOG failed: Firmware is likely too old.\n"); -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+grub_err_t -+grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, -+ const char *description) -+{ -+ grub_err_t err = tpm_init(); -+ -+ /* Absence of a TPM isn't a failure. */ -+ if (err != GRUB_ERR_NONE) -+ return GRUB_ERR_NONE; -+ -+ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n", -+ pcr, size, description); -+ -+ if (tpm_version == 2) -+ return tpm2_log_event (buf, size, pcr, description); -+ -+ return GRUB_ERR_NONE; -+} -diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h -index e0a6c2ce1e..f4c85265fe 100644 ---- a/include/grub/ieee1275/ieee1275.h -+++ b/include/grub/ieee1275/ieee1275.h -@@ -24,6 +24,9 @@ - #include - #include - -+#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0) -+#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1) -+ - struct grub_ieee1275_mem_region - { - unsigned int start; -diff --git a/docs/grub.texi b/docs/grub.texi -index a4da9c2a1b..c433240f34 100644 ---- a/docs/grub.texi -+++ b/docs/grub.texi -@@ -6221,7 +6221,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built - into @file{core.img} in order to avoid a potential gap in measurement between - @file{core.img} being loaded and the tpm module being loaded. - --Measured boot is currently only supported on EFI platforms. -+Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC -+platforms. - - @node Lockdown - @section Lockdown when booting on a secure setup diff --git a/0217-make-ofdisk_retries-optional.patch b/0217-make-ofdisk_retries-optional.patch new file mode 100644 index 0000000..fce9702 --- /dev/null +++ b/0217-make-ofdisk_retries-optional.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Thu, 24 Mar 2022 13:14:42 -0400 +Subject: [PATCH] make ofdisk_retries optional + +The feature Retry on Fail added to GRUB can cause a LPM to take +longer if the SAN is slow. + +When a LPM to external site occur, the path of the disk can change +and thus the disk search function on grub can take some time since +it is used as a hint. This can cause the Retry on Fail feature to +try to access the disk 20x times (since this is hardcoded number) +and, if the SAN is slow, the boot time can increase a lot. +In some situations not acceptable. + +The following patch enables a configuration at user space of the +maximum number of retries we want for this feature. + +The variable ofdisk_retries should be set using grub2-editenv +and will be checked by retry function. If the variable is not set, +so the default number of retries will be used instead. +--- + include/grub/ieee1275/ofdisk.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h +index 7d2d540930..0074d55eee 100644 +--- a/include/grub/ieee1275/ofdisk.h ++++ b/include/grub/ieee1275/ofdisk.h +@@ -25,7 +25,12 @@ extern void grub_ofdisk_fini (void); + #define MAX_RETRIES 20 + + +-#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \ ++#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) \ ++ unsigned max_retries = MAX_RETRIES; \ ++ if(grub_env_get("ofdisk_retries") != NULL) \ ++ max_retries = grub_strtoul(grub_env_get("ofdisk_retries"), 0, 10)+1; \ ++ grub_dprintf("ofdisk","MAX_RETRIES set to %u\n",max_retries); \ ++ unsigned retry_i=0;for(retry_i=0; retry_i < max_retries; retry_i++){ \ + if(!grub_ieee1275_open(device, last_ihandle)) \ + break; \ + grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); } diff --git a/0218-loader-efi-chainloader-grub_load_and_start_image-doe.patch b/0218-loader-efi-chainloader-grub_load_and_start_image-doe.patch new file mode 100644 index 0000000..f61ed28 --- /dev/null +++ b/0218-loader-efi-chainloader-grub_load_and_start_image-doe.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 28 Apr 2022 21:53:36 +0100 +Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't + load and start + +grub_load_and_start_image only loads an image - it still requires the +caller to start it. This renames it to grub_load_image. + +It's called from 2 places: +- grub_cmd_chainloader when not using the shim protocol. +- grub_secureboot_chainloader_boot if handle_image returns an error. +In this case, the image is loaded and then nothing else happens which +seems strange. I assume the intention is that it falls back to LoadImage +and StartImage if handle_image fails, so I've made it do that. + +Signed-off-by: Chris Coulson +(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6) +--- + grub-core/loader/efi/chainloader.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 644cd2e56f..d3bf02ed8a 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -841,7 +841,7 @@ grub_secureboot_chainloader_unload (void) + } + + static grub_err_t +-grub_load_and_start_image(void *boot_image) ++grub_load_image(void *boot_image) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -883,13 +883,23 @@ grub_load_and_start_image(void *boot_image) + static grub_err_t + grub_secureboot_chainloader_boot (void) + { ++ grub_efi_boot_services_t *b; + int rc; ++ + rc = handle_image ((void *)(unsigned long)address, fsize); + if (rc == 0) + { +- grub_load_and_start_image((void *)(unsigned long)address); ++ /* We weren't able to attempt to execute the image, so fall back ++ * to LoadImage / StartImage. ++ */ ++ rc = grub_load_image((void *)(unsigned long)address); ++ if (rc == 0) ++ grub_chainloader_boot (); + } + ++ b = grub_efi_system_table->boot_services; ++ efi_call_1 (b->unload_image, image_handle); ++ + grub_loader_unset (); + return grub_errno; + } +@@ -1091,7 +1101,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + else + { +- grub_load_and_start_image(boot_image); ++ grub_load_image(boot_image); + grub_file_close (file); + grub_device_close (dev); + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); diff --git a/0218-rpm-sort-add-prereqs-for-declaration-of-strchrnul.patch b/0218-rpm-sort-add-prereqs-for-declaration-of-strchrnul.patch deleted file mode 100644 index d2458d0..0000000 --- a/0218-rpm-sort-add-prereqs-for-declaration-of-strchrnul.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Thu, 5 May 2022 18:01:05 -0400 -Subject: [PATCH] rpm-sort: add prereqs for declaration of strchrnul() - -Signed-off-by: Robbie Harwood ---- - util/grub-rpm-sort.c | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/util/grub-rpm-sort.c b/util/grub-rpm-sort.c -index 8345944105..71d038bb69 100644 ---- a/util/grub-rpm-sort.c -+++ b/util/grub-rpm-sort.c -@@ -1,13 +1,17 @@ -+#define _GNU_SOURCE 1 -+ - #include -+ -+#include -+#include -+#include - #include - #include -+#include - #include - #include -+#include - #include --#include --#include --#include --#include - - static size_t - read_file (const char *input, char **ret) diff --git a/0219-loader-efi-chainloader-simplify-the-loader-state.patch b/0219-loader-efi-chainloader-simplify-the-loader-state.patch new file mode 100644 index 0000000..205124e --- /dev/null +++ b/0219-loader-efi-chainloader-simplify-the-loader-state.patch @@ -0,0 +1,330 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:13:08 +0100 +Subject: [PATCH] loader/efi/chainloader: simplify the loader state + +When not using the shim lock protocol, the chainloader command retains +the source buffer and device path passed to LoadImage, requiring the +unload hook passed to grub_loader_set to free them. It isn't required +to retain this state though - they aren't required by StartImage or +anything else in the boot hook, so clean them up before +grub_cmd_chainloader finishes. + +This also wraps the loader state when using the shim lock protocol +inside a struct. + +Signed-off-by: Chris Coulson +(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046) +[rharwood: fix unitialized handle and double-frees of file/dev] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++-------------- + 1 file changed, 102 insertions(+), 58 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index d3bf02ed8a..3342492ff1 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -48,38 +48,21 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_physical_address_t address; +-static grub_efi_uintn_t pages; +-static grub_ssize_t fsize; +-static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; +-static grub_efi_char16_t *cmdline; +-static grub_ssize_t cmdline_len; +-static grub_efi_handle_t dev_handle; + +-static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); ++struct grub_secureboot_chainloader_context { ++ grub_efi_physical_address_t address; ++ grub_efi_uintn_t pages; ++ grub_ssize_t fsize; ++ grub_efi_device_path_t *file_path; ++ grub_efi_char16_t *cmdline; ++ grub_ssize_t cmdline_len; ++ grub_efi_handle_t dev_handle; ++}; ++static struct grub_secureboot_chainloader_context *sb_context; + + static grub_err_t +-grub_chainloader_unload (void) +-{ +- grub_efi_boot_services_t *b; +- +- b = grub_efi_system_table->boot_services; +- efi_call_1 (b->unload_image, image_handle); +- grub_efi_free_pages (address, pages); +- +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; +- dev_handle = 0; +- +- grub_dl_unref (my_mod); +- return GRUB_ERR_NONE; +-} +- +-static grub_err_t +-grub_chainloader_boot (void) ++grub_start_image (grub_efi_handle_t handle) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -87,7 +70,7 @@ grub_chainloader_boot (void) + grub_efi_char16_t *exit_data = NULL; + + b = grub_efi_system_table->boot_services; +- status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data); ++ status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data); + if (status != GRUB_EFI_SUCCESS) + { + if (exit_data) +@@ -111,11 +94,37 @@ grub_chainloader_boot (void) + if (exit_data) + grub_efi_free_pool (exit_data); + +- grub_loader_unset (); +- + return grub_errno; + } + ++static grub_err_t ++grub_chainloader_unload (void) ++{ ++ grub_efi_loaded_image_t *loaded_image; ++ grub_efi_boot_services_t *b; ++ ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ if (loaded_image != NULL) ++ grub_free (loaded_image->load_options); ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_1 (b->unload_image, image_handle); ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_chainloader_boot (void) ++{ ++ grub_err_t err; ++ ++ err = grub_start_image (image_handle); ++ ++ grub_loader_unset (); ++ return err; ++} ++ + static grub_err_t + copy_file_path (grub_efi_file_path_device_path_t *fp, + const char *str, grub_efi_uint16_t len) +@@ -150,7 +159,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + char *dir_start; + char *dir_end; + grub_size_t size; +- grub_efi_device_path_t *d; ++ grub_efi_device_path_t *d, *file_path; + + dir_start = grub_strchr (filename, ')'); + if (! dir_start) +@@ -526,10 +535,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) + } + + static grub_efi_boolean_t +-handle_image (void *data, grub_efi_uint32_t datasize) ++handle_image (struct grub_secureboot_chainloader_context *load_context) + { + grub_efi_loaded_image_t *li, li_bak; + grub_efi_status_t efi_status; ++ void *data = (void *)(unsigned long)load_context->address; ++ grub_efi_uint32_t datasize = load_context->fsize; + void *buffer = NULL; + char *buffer_aligned = NULL; + grub_efi_uint32_t i; +@@ -540,6 +551,7 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_uint32_t buffer_size; + int found_entry_point = 0; + int rc; ++ grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); + + rc = read_header (data, datasize, &context); + if (rc < 0) +@@ -797,10 +809,10 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); + li->image_base = buffer_aligned; + li->image_size = context.image_size; +- li->load_options = cmdline; +- li->load_options_size = cmdline_len; +- li->file_path = grub_efi_get_media_file_path (file_path); +- li->device_handle = dev_handle; ++ li->load_options = load_context->cmdline; ++ li->load_options_size = load_context->cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (load_context->file_path); ++ li->device_handle = load_context->dev_handle; + if (!li->file_path) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); +@@ -829,19 +841,22 @@ error_exit: + static grub_err_t + grub_secureboot_chainloader_unload (void) + { +- grub_efi_free_pages (address, pages); +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; +- dev_handle = 0; ++ grub_efi_free_pages (sb_context->address, sb_context->pages); ++ grub_free (sb_context->file_path); ++ grub_free (sb_context->cmdline); ++ grub_free (sb_context); ++ ++ sb_context = 0; + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } + + static grub_err_t +-grub_load_image(void *boot_image) ++grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, ++ grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle, ++ grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len, ++ grub_efi_handle_t *image_handle_out) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -850,7 +865,7 @@ grub_load_image(void *boot_image) + b = grub_efi_system_table->boot_services; + + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, +- boot_image, fsize, &image_handle); ++ boot_image, image_size, image_handle_out); + if (status != GRUB_EFI_SUCCESS) + { + if (status == GRUB_EFI_OUT_OF_RESOURCES) +@@ -863,7 +878,7 @@ grub_load_image(void *boot_image) + /* LoadImage does not set a device handler when the image is + loaded from memory, so it is necessary to set it explicitly here. + This is a mess. */ +- loaded_image = grub_efi_get_loaded_image (image_handle); ++ loaded_image = grub_efi_get_loaded_image (*image_handle_out); + if (! loaded_image) + { + grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); +@@ -885,20 +900,25 @@ grub_secureboot_chainloader_boot (void) + { + grub_efi_boot_services_t *b; + int rc; ++ grub_efi_handle_t handle = 0; + +- rc = handle_image ((void *)(unsigned long)address, fsize); ++ rc = handle_image (sb_context); + if (rc == 0) + { + /* We weren't able to attempt to execute the image, so fall back + * to LoadImage / StartImage. + */ +- rc = grub_load_image((void *)(unsigned long)address); ++ rc = grub_load_image(sb_context->file_path, ++ (void *)(unsigned long)sb_context->address, ++ sb_context->fsize, sb_context->dev_handle, ++ sb_context->cmdline, sb_context->cmdline_len, ++ &handle); + if (rc == 0) +- grub_chainloader_boot (); ++ grub_start_image (handle); + } + + b = grub_efi_system_table->boot_services; +- efi_call_1 (b->unload_image, image_handle); ++ efi_call_1 (b->unload_image, handle); + + grub_loader_unset (); + return grub_errno; +@@ -913,9 +933,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_boot_services_t *b; + grub_device_t dev = 0; + grub_device_t orig_dev = 0; +- grub_efi_device_path_t *dp = 0; ++ grub_efi_device_path_t *dp = 0, *file_path = 0; + char *filename; + void *boot_image = 0; ++ grub_efi_physical_address_t address = 0; ++ grub_ssize_t fsize; ++ grub_efi_uintn_t pages = 0; ++ grub_efi_char16_t *cmdline = 0; ++ grub_ssize_t cmdline_len = 0; ++ grub_efi_handle_t dev_handle = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -923,12 +949,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + +- /* Initialize some global variables. */ +- address = 0; +- image_handle = 0; +- file_path = 0; +- dev_handle = 0; +- + b = grub_efi_system_table->boot_services; + + if (argc > 1) +@@ -1093,17 +1113,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { ++ sb_context = grub_malloc (sizeof (*sb_context)); ++ if (sb_context == NULL) ++ goto fail; ++ sb_context->address = address; ++ sb_context->fsize = fsize; ++ sb_context->pages = pages; ++ sb_context->file_path = file_path; ++ sb_context->cmdline = cmdline; ++ sb_context->cmdline_len = cmdline_len; ++ sb_context->dev_handle = dev_handle; ++ + grub_file_close (file); + grub_device_close (dev); ++ + grub_loader_set (grub_secureboot_chainloader_boot, + grub_secureboot_chainloader_unload, 0); + return 0; + } + else + { +- grub_load_image(boot_image); ++ grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline, ++ cmdline_len, &image_handle); + grub_file_close (file); + grub_device_close (dev); ++ ++ /* We're finished with the source image buffer and file path now */ ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); + + return 0; +@@ -1130,6 +1168,12 @@ fail: + if (cmdline) + grub_free (cmdline); + ++ if (image_handle != 0) ++ { ++ efi_call_1 (b->unload_image, image_handle); ++ image_handle = 0; ++ } ++ + grub_dl_unref (my_mod); + + return grub_errno; diff --git a/0219-make-ofdisk_retries-optional.patch b/0219-make-ofdisk_retries-optional.patch deleted file mode 100644 index fce9702..0000000 --- a/0219-make-ofdisk_retries-optional.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Diego Domingos -Date: Thu, 24 Mar 2022 13:14:42 -0400 -Subject: [PATCH] make ofdisk_retries optional - -The feature Retry on Fail added to GRUB can cause a LPM to take -longer if the SAN is slow. - -When a LPM to external site occur, the path of the disk can change -and thus the disk search function on grub can take some time since -it is used as a hint. This can cause the Retry on Fail feature to -try to access the disk 20x times (since this is hardcoded number) -and, if the SAN is slow, the boot time can increase a lot. -In some situations not acceptable. - -The following patch enables a configuration at user space of the -maximum number of retries we want for this feature. - -The variable ofdisk_retries should be set using grub2-editenv -and will be checked by retry function. If the variable is not set, -so the default number of retries will be used instead. ---- - include/grub/ieee1275/ofdisk.h | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h -index 7d2d540930..0074d55eee 100644 ---- a/include/grub/ieee1275/ofdisk.h -+++ b/include/grub/ieee1275/ofdisk.h -@@ -25,7 +25,12 @@ extern void grub_ofdisk_fini (void); - #define MAX_RETRIES 20 - - --#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \ -+#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) \ -+ unsigned max_retries = MAX_RETRIES; \ -+ if(grub_env_get("ofdisk_retries") != NULL) \ -+ max_retries = grub_strtoul(grub_env_get("ofdisk_retries"), 0, 10)+1; \ -+ grub_dprintf("ofdisk","MAX_RETRIES set to %u\n",max_retries); \ -+ unsigned retry_i=0;for(retry_i=0; retry_i < max_retries; retry_i++){ \ - if(!grub_ieee1275_open(device, last_ihandle)) \ - break; \ - grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); } diff --git a/0220-commands-boot-Add-API-to-pass-context-to-loader.patch b/0220-commands-boot-Add-API-to-pass-context-to-loader.patch new file mode 100644 index 0000000..63a2d76 --- /dev/null +++ b/0220-commands-boot-Add-API-to-pass-context-to-loader.patch @@ -0,0 +1,158 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:16:02 +0100 +Subject: [PATCH] commands/boot: Add API to pass context to loader + +Loaders rely on global variables for saving context which is consumed +in the boot hook and freed in the unload hook. In the case where a loader +command is executed twice, calling grub_loader_set a second time executes +the unload hook, but in some cases this runs when the loader's global +context has already been updated, resulting in the updated context being +freed and potential use-after-free bugs when the boot hook is subsequently +called. + +This adds a new API (grub_loader_set_ex) which allows a loader to specify +context that is passed to its boot and unload hooks. This is an alternative +to requiring that loaders call grub_loader_unset before mutating their +global context. + +Signed-off-by: Chris Coulson +(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3) +--- + grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------ + include/grub/loader.h | 5 ++++ + 2 files changed, 63 insertions(+), 8 deletions(-) + +diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c +index bbca81e947..53691a62d9 100644 +--- a/grub-core/commands/boot.c ++++ b/grub-core/commands/boot.c +@@ -27,10 +27,20 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-static grub_err_t (*grub_loader_boot_func) (void); +-static grub_err_t (*grub_loader_unload_func) (void); ++static grub_err_t (*grub_loader_boot_func) (void *); ++static grub_err_t (*grub_loader_unload_func) (void *); ++static void *grub_loader_context; + static int grub_loader_flags; + ++struct grub_simple_loader_hooks ++{ ++ grub_err_t (*boot) (void); ++ grub_err_t (*unload) (void); ++}; ++ ++/* Don't heap allocate this to avoid making grub_loader_set fallible. */ ++static struct grub_simple_loader_hooks simple_loader_hooks; ++ + struct grub_preboot + { + grub_err_t (*preboot_func) (int); +@@ -44,6 +54,29 @@ static int grub_loader_loaded; + static struct grub_preboot *preboots_head = 0, + *preboots_tail = 0; + ++static grub_err_t ++grub_simple_boot_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ return hooks->boot (); ++} ++ ++static grub_err_t ++grub_simple_unload_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ grub_err_t ret; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ ++ ret = hooks->unload (); ++ grub_memset (hooks, 0, sizeof (*hooks)); ++ ++ return ret; ++} ++ + int + grub_loader_is_loaded (void) + { +@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) + } + + void +-grub_loader_set (grub_err_t (*boot) (void), +- grub_err_t (*unload) (void), +- int flags) ++grub_loader_set_ex (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = boot; + grub_loader_unload_func = unload; ++ grub_loader_context = context; + grub_loader_flags = flags; + + grub_loader_loaded = 1; + } + ++void ++grub_loader_set (grub_err_t (*boot) (void), ++ grub_err_t (*unload) (void), ++ int flags) ++{ ++ grub_loader_set_ex (grub_simple_boot_hook, ++ grub_simple_unload_hook, ++ &simple_loader_hooks, ++ flags); ++ ++ simple_loader_hooks.boot = boot; ++ simple_loader_hooks.unload = unload; ++} ++ + void + grub_loader_unset(void) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = 0; + grub_loader_unload_func = 0; ++ grub_loader_context = 0; + + grub_loader_loaded = 0; + } +@@ -158,7 +208,7 @@ grub_loader_boot (void) + return err; + } + } +- err = (grub_loader_boot_func) (); ++ err = (grub_loader_boot_func) (grub_loader_context); + + for (cur = preboots_tail; cur; cur = cur->prev) + if (! err) +diff --git a/include/grub/loader.h b/include/grub/loader.h +index b208642821..1846fa6c5f 100644 +--- a/include/grub/loader.h ++++ b/include/grub/loader.h +@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), + grub_err_t (*unload) (void), + int flags); + ++void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags); ++ + /* Unset current loader, if any. */ + void EXPORT_FUNC (grub_loader_unset) (void); + diff --git a/0220-loader-efi-chainloader-grub_load_and_start_image-doe.patch b/0220-loader-efi-chainloader-grub_load_and_start_image-doe.patch deleted file mode 100644 index f61ed28..0000000 --- a/0220-loader-efi-chainloader-grub_load_and_start_image-doe.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Thu, 28 Apr 2022 21:53:36 +0100 -Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't - load and start - -grub_load_and_start_image only loads an image - it still requires the -caller to start it. This renames it to grub_load_image. - -It's called from 2 places: -- grub_cmd_chainloader when not using the shim protocol. -- grub_secureboot_chainloader_boot if handle_image returns an error. -In this case, the image is loaded and then nothing else happens which -seems strange. I assume the intention is that it falls back to LoadImage -and StartImage if handle_image fails, so I've made it do that. - -Signed-off-by: Chris Coulson -(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6) ---- - grub-core/loader/efi/chainloader.c | 16 +++++++++++++--- - 1 file changed, 13 insertions(+), 3 deletions(-) - -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index 644cd2e56f..d3bf02ed8a 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -841,7 +841,7 @@ grub_secureboot_chainloader_unload (void) - } - - static grub_err_t --grub_load_and_start_image(void *boot_image) -+grub_load_image(void *boot_image) - { - grub_efi_boot_services_t *b; - grub_efi_status_t status; -@@ -883,13 +883,23 @@ grub_load_and_start_image(void *boot_image) - static grub_err_t - grub_secureboot_chainloader_boot (void) - { -+ grub_efi_boot_services_t *b; - int rc; -+ - rc = handle_image ((void *)(unsigned long)address, fsize); - if (rc == 0) - { -- grub_load_and_start_image((void *)(unsigned long)address); -+ /* We weren't able to attempt to execute the image, so fall back -+ * to LoadImage / StartImage. -+ */ -+ rc = grub_load_image((void *)(unsigned long)address); -+ if (rc == 0) -+ grub_chainloader_boot (); - } - -+ b = grub_efi_system_table->boot_services; -+ efi_call_1 (b->unload_image, image_handle); -+ - grub_loader_unset (); - return grub_errno; - } -@@ -1091,7 +1101,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - } - else - { -- grub_load_and_start_image(boot_image); -+ grub_load_image(boot_image); - grub_file_close (file); - grub_device_close (dev); - grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); diff --git a/0221-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/0221-loader-efi-chainloader-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..fc15b84 --- /dev/null +++ b/0221-loader-efi-chainloader-Use-grub_loader_set_ex.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:30:56 +0100 +Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex + +This ports the EFI chainloader to use grub_loader_set_ex in order to fix +a use-after-free bug that occurs when grub_cmd_chainloader is executed +more than once before a boot attempt is performed. + +Signed-off-by: Chris Coulson +(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9) +[rharwood: context sludge from other change] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++---------------- + 1 file changed, 22 insertions(+), 16 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 3342492ff1..fb874f1855 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -48,8 +48,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_handle_t image_handle; +- + struct grub_secureboot_chainloader_context { + grub_efi_physical_address_t address; + grub_efi_uintn_t pages; +@@ -59,7 +57,6 @@ struct grub_secureboot_chainloader_context { + grub_ssize_t cmdline_len; + grub_efi_handle_t dev_handle; + }; +-static struct grub_secureboot_chainloader_context *sb_context; + + static grub_err_t + grub_start_image (grub_efi_handle_t handle) +@@ -98,11 +95,14 @@ grub_start_image (grub_efi_handle_t handle) + } + + static grub_err_t +-grub_chainloader_unload (void) ++grub_chainloader_unload (void *context) + { ++ grub_efi_handle_t image_handle; + grub_efi_loaded_image_t *loaded_image; + grub_efi_boot_services_t *b; + ++ image_handle = (grub_efi_handle_t) context; ++ + loaded_image = grub_efi_get_loaded_image (image_handle); + if (loaded_image != NULL) + grub_free (loaded_image->load_options); +@@ -115,10 +115,12 @@ grub_chainloader_unload (void) + } + + static grub_err_t +-grub_chainloader_boot (void) ++grub_chainloader_boot (void *context) + { ++ grub_efi_handle_t image_handle; + grub_err_t err; + ++ image_handle = (grub_efi_handle_t) context; + err = grub_start_image (image_handle); + + grub_loader_unset (); +@@ -839,15 +841,17 @@ error_exit: + } + + static grub_err_t +-grub_secureboot_chainloader_unload (void) ++grub_secureboot_chainloader_unload (void *context) + { ++ struct grub_secureboot_chainloader_context *sb_context; ++ ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ + grub_efi_free_pages (sb_context->address, sb_context->pages); + grub_free (sb_context->file_path); + grub_free (sb_context->cmdline); + grub_free (sb_context); + +- sb_context = 0; +- + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } +@@ -896,12 +900,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, + } + + static grub_err_t +-grub_secureboot_chainloader_boot (void) ++grub_secureboot_chainloader_boot (void *context) + { ++ struct grub_secureboot_chainloader_context *sb_context; + grub_efi_boot_services_t *b; + int rc; + grub_efi_handle_t handle = 0; + ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ + rc = handle_image (sb_context); + if (rc == 0) + { +@@ -942,6 +949,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_char16_t *cmdline = 0; + grub_ssize_t cmdline_len = 0; + grub_efi_handle_t dev_handle = 0; ++ grub_efi_handle_t image_handle = 0; ++ struct grub_secureboot_chainloader_context *sb_context = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -1127,8 +1136,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (file); + grub_device_close (dev); + +- grub_loader_set (grub_secureboot_chainloader_boot, +- grub_secureboot_chainloader_unload, 0); ++ grub_loader_set_ex (grub_secureboot_chainloader_boot, ++ grub_secureboot_chainloader_unload, sb_context, 0); + return 0; + } + else +@@ -1142,7 +1151,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + efi_call_2 (b->free_pages, address, pages); + grub_free (file_path); + +- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); ++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); + + return 0; + } +@@ -1169,10 +1178,7 @@ fail: + grub_free (cmdline); + + if (image_handle != 0) +- { +- efi_call_1 (b->unload_image, image_handle); +- image_handle = 0; +- } ++ efi_call_1 (b->unload_image, image_handle); + + grub_dl_unref (my_mod); + diff --git a/0221-loader-efi-chainloader-simplify-the-loader-state.patch b/0221-loader-efi-chainloader-simplify-the-loader-state.patch deleted file mode 100644 index 205124e..0000000 --- a/0221-loader-efi-chainloader-simplify-the-loader-state.patch +++ /dev/null @@ -1,330 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Fri, 29 Apr 2022 21:13:08 +0100 -Subject: [PATCH] loader/efi/chainloader: simplify the loader state - -When not using the shim lock protocol, the chainloader command retains -the source buffer and device path passed to LoadImage, requiring the -unload hook passed to grub_loader_set to free them. It isn't required -to retain this state though - they aren't required by StartImage or -anything else in the boot hook, so clean them up before -grub_cmd_chainloader finishes. - -This also wraps the loader state when using the shim lock protocol -inside a struct. - -Signed-off-by: Chris Coulson -(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046) -[rharwood: fix unitialized handle and double-frees of file/dev] -Signed-off-by: Robbie Harwood ---- - grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++-------------- - 1 file changed, 102 insertions(+), 58 deletions(-) - -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index d3bf02ed8a..3342492ff1 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -48,38 +48,21 @@ GRUB_MOD_LICENSE ("GPLv3+"); - - static grub_dl_t my_mod; - --static grub_efi_physical_address_t address; --static grub_efi_uintn_t pages; --static grub_ssize_t fsize; --static grub_efi_device_path_t *file_path; - static grub_efi_handle_t image_handle; --static grub_efi_char16_t *cmdline; --static grub_ssize_t cmdline_len; --static grub_efi_handle_t dev_handle; - --static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); -+struct grub_secureboot_chainloader_context { -+ grub_efi_physical_address_t address; -+ grub_efi_uintn_t pages; -+ grub_ssize_t fsize; -+ grub_efi_device_path_t *file_path; -+ grub_efi_char16_t *cmdline; -+ grub_ssize_t cmdline_len; -+ grub_efi_handle_t dev_handle; -+}; -+static struct grub_secureboot_chainloader_context *sb_context; - - static grub_err_t --grub_chainloader_unload (void) --{ -- grub_efi_boot_services_t *b; -- -- b = grub_efi_system_table->boot_services; -- efi_call_1 (b->unload_image, image_handle); -- grub_efi_free_pages (address, pages); -- -- grub_free (file_path); -- grub_free (cmdline); -- cmdline = 0; -- file_path = 0; -- dev_handle = 0; -- -- grub_dl_unref (my_mod); -- return GRUB_ERR_NONE; --} -- --static grub_err_t --grub_chainloader_boot (void) -+grub_start_image (grub_efi_handle_t handle) - { - grub_efi_boot_services_t *b; - grub_efi_status_t status; -@@ -87,7 +70,7 @@ grub_chainloader_boot (void) - grub_efi_char16_t *exit_data = NULL; - - b = grub_efi_system_table->boot_services; -- status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data); -+ status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data); - if (status != GRUB_EFI_SUCCESS) - { - if (exit_data) -@@ -111,11 +94,37 @@ grub_chainloader_boot (void) - if (exit_data) - grub_efi_free_pool (exit_data); - -- grub_loader_unset (); -- - return grub_errno; - } - -+static grub_err_t -+grub_chainloader_unload (void) -+{ -+ grub_efi_loaded_image_t *loaded_image; -+ grub_efi_boot_services_t *b; -+ -+ loaded_image = grub_efi_get_loaded_image (image_handle); -+ if (loaded_image != NULL) -+ grub_free (loaded_image->load_options); -+ -+ b = grub_efi_system_table->boot_services; -+ efi_call_1 (b->unload_image, image_handle); -+ -+ grub_dl_unref (my_mod); -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_chainloader_boot (void) -+{ -+ grub_err_t err; -+ -+ err = grub_start_image (image_handle); -+ -+ grub_loader_unset (); -+ return err; -+} -+ - static grub_err_t - copy_file_path (grub_efi_file_path_device_path_t *fp, - const char *str, grub_efi_uint16_t len) -@@ -150,7 +159,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) - char *dir_start; - char *dir_end; - grub_size_t size; -- grub_efi_device_path_t *d; -+ grub_efi_device_path_t *d, *file_path; - - dir_start = grub_strchr (filename, ')'); - if (! dir_start) -@@ -526,10 +535,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) - } - - static grub_efi_boolean_t --handle_image (void *data, grub_efi_uint32_t datasize) -+handle_image (struct grub_secureboot_chainloader_context *load_context) - { - grub_efi_loaded_image_t *li, li_bak; - grub_efi_status_t efi_status; -+ void *data = (void *)(unsigned long)load_context->address; -+ grub_efi_uint32_t datasize = load_context->fsize; - void *buffer = NULL; - char *buffer_aligned = NULL; - grub_efi_uint32_t i; -@@ -540,6 +551,7 @@ handle_image (void *data, grub_efi_uint32_t datasize) - grub_uint32_t buffer_size; - int found_entry_point = 0; - int rc; -+ grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); - - rc = read_header (data, datasize, &context); - if (rc < 0) -@@ -797,10 +809,10 @@ handle_image (void *data, grub_efi_uint32_t datasize) - grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); - li->image_base = buffer_aligned; - li->image_size = context.image_size; -- li->load_options = cmdline; -- li->load_options_size = cmdline_len; -- li->file_path = grub_efi_get_media_file_path (file_path); -- li->device_handle = dev_handle; -+ li->load_options = load_context->cmdline; -+ li->load_options_size = load_context->cmdline_len; -+ li->file_path = grub_efi_get_media_file_path (load_context->file_path); -+ li->device_handle = load_context->dev_handle; - if (!li->file_path) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); -@@ -829,19 +841,22 @@ error_exit: - static grub_err_t - grub_secureboot_chainloader_unload (void) - { -- grub_efi_free_pages (address, pages); -- grub_free (file_path); -- grub_free (cmdline); -- cmdline = 0; -- file_path = 0; -- dev_handle = 0; -+ grub_efi_free_pages (sb_context->address, sb_context->pages); -+ grub_free (sb_context->file_path); -+ grub_free (sb_context->cmdline); -+ grub_free (sb_context); -+ -+ sb_context = 0; - - grub_dl_unref (my_mod); - return GRUB_ERR_NONE; - } - - static grub_err_t --grub_load_image(void *boot_image) -+grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, -+ grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle, -+ grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len, -+ grub_efi_handle_t *image_handle_out) - { - grub_efi_boot_services_t *b; - grub_efi_status_t status; -@@ -850,7 +865,7 @@ grub_load_image(void *boot_image) - b = grub_efi_system_table->boot_services; - - status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, -- boot_image, fsize, &image_handle); -+ boot_image, image_size, image_handle_out); - if (status != GRUB_EFI_SUCCESS) - { - if (status == GRUB_EFI_OUT_OF_RESOURCES) -@@ -863,7 +878,7 @@ grub_load_image(void *boot_image) - /* LoadImage does not set a device handler when the image is - loaded from memory, so it is necessary to set it explicitly here. - This is a mess. */ -- loaded_image = grub_efi_get_loaded_image (image_handle); -+ loaded_image = grub_efi_get_loaded_image (*image_handle_out); - if (! loaded_image) - { - grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); -@@ -885,20 +900,25 @@ grub_secureboot_chainloader_boot (void) - { - grub_efi_boot_services_t *b; - int rc; -+ grub_efi_handle_t handle = 0; - -- rc = handle_image ((void *)(unsigned long)address, fsize); -+ rc = handle_image (sb_context); - if (rc == 0) - { - /* We weren't able to attempt to execute the image, so fall back - * to LoadImage / StartImage. - */ -- rc = grub_load_image((void *)(unsigned long)address); -+ rc = grub_load_image(sb_context->file_path, -+ (void *)(unsigned long)sb_context->address, -+ sb_context->fsize, sb_context->dev_handle, -+ sb_context->cmdline, sb_context->cmdline_len, -+ &handle); - if (rc == 0) -- grub_chainloader_boot (); -+ grub_start_image (handle); - } - - b = grub_efi_system_table->boot_services; -- efi_call_1 (b->unload_image, image_handle); -+ efi_call_1 (b->unload_image, handle); - - grub_loader_unset (); - return grub_errno; -@@ -913,9 +933,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - grub_efi_boot_services_t *b; - grub_device_t dev = 0; - grub_device_t orig_dev = 0; -- grub_efi_device_path_t *dp = 0; -+ grub_efi_device_path_t *dp = 0, *file_path = 0; - char *filename; - void *boot_image = 0; -+ grub_efi_physical_address_t address = 0; -+ grub_ssize_t fsize; -+ grub_efi_uintn_t pages = 0; -+ grub_efi_char16_t *cmdline = 0; -+ grub_ssize_t cmdline_len = 0; -+ grub_efi_handle_t dev_handle = 0; - - if (argc == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); -@@ -923,12 +949,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - - grub_dl_ref (my_mod); - -- /* Initialize some global variables. */ -- address = 0; -- image_handle = 0; -- file_path = 0; -- dev_handle = 0; -- - b = grub_efi_system_table->boot_services; - - if (argc > 1) -@@ -1093,17 +1113,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - - if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) - { -+ sb_context = grub_malloc (sizeof (*sb_context)); -+ if (sb_context == NULL) -+ goto fail; -+ sb_context->address = address; -+ sb_context->fsize = fsize; -+ sb_context->pages = pages; -+ sb_context->file_path = file_path; -+ sb_context->cmdline = cmdline; -+ sb_context->cmdline_len = cmdline_len; -+ sb_context->dev_handle = dev_handle; -+ - grub_file_close (file); - grub_device_close (dev); -+ - grub_loader_set (grub_secureboot_chainloader_boot, - grub_secureboot_chainloader_unload, 0); - return 0; - } - else - { -- grub_load_image(boot_image); -+ grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline, -+ cmdline_len, &image_handle); - grub_file_close (file); - grub_device_close (dev); -+ -+ /* We're finished with the source image buffer and file path now */ -+ efi_call_2 (b->free_pages, address, pages); -+ grub_free (file_path); -+ - grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); - - return 0; -@@ -1130,6 +1168,12 @@ fail: - if (cmdline) - grub_free (cmdline); - -+ if (image_handle != 0) -+ { -+ efi_call_1 (b->unload_image, image_handle); -+ image_handle = 0; -+ } -+ - grub_dl_unref (my_mod); - - return grub_errno; diff --git a/0222-commands-boot-Add-API-to-pass-context-to-loader.patch b/0222-commands-boot-Add-API-to-pass-context-to-loader.patch deleted file mode 100644 index 63a2d76..0000000 --- a/0222-commands-boot-Add-API-to-pass-context-to-loader.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Fri, 29 Apr 2022 21:16:02 +0100 -Subject: [PATCH] commands/boot: Add API to pass context to loader - -Loaders rely on global variables for saving context which is consumed -in the boot hook and freed in the unload hook. In the case where a loader -command is executed twice, calling grub_loader_set a second time executes -the unload hook, but in some cases this runs when the loader's global -context has already been updated, resulting in the updated context being -freed and potential use-after-free bugs when the boot hook is subsequently -called. - -This adds a new API (grub_loader_set_ex) which allows a loader to specify -context that is passed to its boot and unload hooks. This is an alternative -to requiring that loaders call grub_loader_unset before mutating their -global context. - -Signed-off-by: Chris Coulson -(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3) ---- - grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------ - include/grub/loader.h | 5 ++++ - 2 files changed, 63 insertions(+), 8 deletions(-) - -diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c -index bbca81e947..53691a62d9 100644 ---- a/grub-core/commands/boot.c -+++ b/grub-core/commands/boot.c -@@ -27,10 +27,20 @@ - - GRUB_MOD_LICENSE ("GPLv3+"); - --static grub_err_t (*grub_loader_boot_func) (void); --static grub_err_t (*grub_loader_unload_func) (void); -+static grub_err_t (*grub_loader_boot_func) (void *); -+static grub_err_t (*grub_loader_unload_func) (void *); -+static void *grub_loader_context; - static int grub_loader_flags; - -+struct grub_simple_loader_hooks -+{ -+ grub_err_t (*boot) (void); -+ grub_err_t (*unload) (void); -+}; -+ -+/* Don't heap allocate this to avoid making grub_loader_set fallible. */ -+static struct grub_simple_loader_hooks simple_loader_hooks; -+ - struct grub_preboot - { - grub_err_t (*preboot_func) (int); -@@ -44,6 +54,29 @@ static int grub_loader_loaded; - static struct grub_preboot *preboots_head = 0, - *preboots_tail = 0; - -+static grub_err_t -+grub_simple_boot_hook (void *context) -+{ -+ struct grub_simple_loader_hooks *hooks; -+ -+ hooks = (struct grub_simple_loader_hooks *) context; -+ return hooks->boot (); -+} -+ -+static grub_err_t -+grub_simple_unload_hook (void *context) -+{ -+ struct grub_simple_loader_hooks *hooks; -+ grub_err_t ret; -+ -+ hooks = (struct grub_simple_loader_hooks *) context; -+ -+ ret = hooks->unload (); -+ grub_memset (hooks, 0, sizeof (*hooks)); -+ -+ return ret; -+} -+ - int - grub_loader_is_loaded (void) - { -@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) - } - - void --grub_loader_set (grub_err_t (*boot) (void), -- grub_err_t (*unload) (void), -- int flags) -+grub_loader_set_ex (grub_err_t (*boot) (void *), -+ grub_err_t (*unload) (void *), -+ void *context, -+ int flags) - { - if (grub_loader_loaded && grub_loader_unload_func) -- grub_loader_unload_func (); -+ grub_loader_unload_func (grub_loader_context); - - grub_loader_boot_func = boot; - grub_loader_unload_func = unload; -+ grub_loader_context = context; - grub_loader_flags = flags; - - grub_loader_loaded = 1; - } - -+void -+grub_loader_set (grub_err_t (*boot) (void), -+ grub_err_t (*unload) (void), -+ int flags) -+{ -+ grub_loader_set_ex (grub_simple_boot_hook, -+ grub_simple_unload_hook, -+ &simple_loader_hooks, -+ flags); -+ -+ simple_loader_hooks.boot = boot; -+ simple_loader_hooks.unload = unload; -+} -+ - void - grub_loader_unset(void) - { - if (grub_loader_loaded && grub_loader_unload_func) -- grub_loader_unload_func (); -+ grub_loader_unload_func (grub_loader_context); - - grub_loader_boot_func = 0; - grub_loader_unload_func = 0; -+ grub_loader_context = 0; - - grub_loader_loaded = 0; - } -@@ -158,7 +208,7 @@ grub_loader_boot (void) - return err; - } - } -- err = (grub_loader_boot_func) (); -+ err = (grub_loader_boot_func) (grub_loader_context); - - for (cur = preboots_tail; cur; cur = cur->prev) - if (! err) -diff --git a/include/grub/loader.h b/include/grub/loader.h -index b208642821..1846fa6c5f 100644 ---- a/include/grub/loader.h -+++ b/include/grub/loader.h -@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), - grub_err_t (*unload) (void), - int flags); - -+void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *), -+ grub_err_t (*unload) (void *), -+ void *context, -+ int flags); -+ - /* Unset current loader, if any. */ - void EXPORT_FUNC (grub_loader_unset) (void); - diff --git a/0222-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch b/0222-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch new file mode 100644 index 0000000..b79c78c --- /dev/null +++ b/0222-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Mon, 2 May 2022 14:39:31 +0200 +Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi + loader + +In some error paths in grub_cmd_linux, the pointer to lh may be +dereferenced after the buffer it points to has been freed. There aren't +any security implications from this because nothing else uses the +allocator after the buffer is freed and before the pointer is +dereferenced, but fix it anyway. + +Signed-off-by: Chris Coulson +(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2) +--- + grub-core/loader/i386/efi/linux.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 941df6400b..27bc2aa161 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -465,9 +465,6 @@ fail: + if (file) + grub_file_close (file); + +- if (kernel) +- grub_free (kernel); +- + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); +@@ -483,6 +480,8 @@ fail: + kernel_free (params, sizeof(*params)); + } + ++ grub_free (kernel); ++ + return grub_errno; + } + diff --git a/0223-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/0223-loader-efi-chainloader-Use-grub_loader_set_ex.patch deleted file mode 100644 index fc15b84..0000000 --- a/0223-loader-efi-chainloader-Use-grub_loader_set_ex.patch +++ /dev/null @@ -1,147 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Fri, 29 Apr 2022 21:30:56 +0100 -Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex - -This ports the EFI chainloader to use grub_loader_set_ex in order to fix -a use-after-free bug that occurs when grub_cmd_chainloader is executed -more than once before a boot attempt is performed. - -Signed-off-by: Chris Coulson -(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9) -[rharwood: context sludge from other change] -Signed-off-by: Robbie Harwood ---- - grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++---------------- - 1 file changed, 22 insertions(+), 16 deletions(-) - -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index 3342492ff1..fb874f1855 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -48,8 +48,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); - - static grub_dl_t my_mod; - --static grub_efi_handle_t image_handle; -- - struct grub_secureboot_chainloader_context { - grub_efi_physical_address_t address; - grub_efi_uintn_t pages; -@@ -59,7 +57,6 @@ struct grub_secureboot_chainloader_context { - grub_ssize_t cmdline_len; - grub_efi_handle_t dev_handle; - }; --static struct grub_secureboot_chainloader_context *sb_context; - - static grub_err_t - grub_start_image (grub_efi_handle_t handle) -@@ -98,11 +95,14 @@ grub_start_image (grub_efi_handle_t handle) - } - - static grub_err_t --grub_chainloader_unload (void) -+grub_chainloader_unload (void *context) - { -+ grub_efi_handle_t image_handle; - grub_efi_loaded_image_t *loaded_image; - grub_efi_boot_services_t *b; - -+ image_handle = (grub_efi_handle_t) context; -+ - loaded_image = grub_efi_get_loaded_image (image_handle); - if (loaded_image != NULL) - grub_free (loaded_image->load_options); -@@ -115,10 +115,12 @@ grub_chainloader_unload (void) - } - - static grub_err_t --grub_chainloader_boot (void) -+grub_chainloader_boot (void *context) - { -+ grub_efi_handle_t image_handle; - grub_err_t err; - -+ image_handle = (grub_efi_handle_t) context; - err = grub_start_image (image_handle); - - grub_loader_unset (); -@@ -839,15 +841,17 @@ error_exit: - } - - static grub_err_t --grub_secureboot_chainloader_unload (void) -+grub_secureboot_chainloader_unload (void *context) - { -+ struct grub_secureboot_chainloader_context *sb_context; -+ -+ sb_context = (struct grub_secureboot_chainloader_context *) context; -+ - grub_efi_free_pages (sb_context->address, sb_context->pages); - grub_free (sb_context->file_path); - grub_free (sb_context->cmdline); - grub_free (sb_context); - -- sb_context = 0; -- - grub_dl_unref (my_mod); - return GRUB_ERR_NONE; - } -@@ -896,12 +900,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, - } - - static grub_err_t --grub_secureboot_chainloader_boot (void) -+grub_secureboot_chainloader_boot (void *context) - { -+ struct grub_secureboot_chainloader_context *sb_context; - grub_efi_boot_services_t *b; - int rc; - grub_efi_handle_t handle = 0; - -+ sb_context = (struct grub_secureboot_chainloader_context *) context; -+ - rc = handle_image (sb_context); - if (rc == 0) - { -@@ -942,6 +949,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - grub_efi_char16_t *cmdline = 0; - grub_ssize_t cmdline_len = 0; - grub_efi_handle_t dev_handle = 0; -+ grub_efi_handle_t image_handle = 0; -+ struct grub_secureboot_chainloader_context *sb_context = 0; - - if (argc == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); -@@ -1127,8 +1136,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - grub_file_close (file); - grub_device_close (dev); - -- grub_loader_set (grub_secureboot_chainloader_boot, -- grub_secureboot_chainloader_unload, 0); -+ grub_loader_set_ex (grub_secureboot_chainloader_boot, -+ grub_secureboot_chainloader_unload, sb_context, 0); - return 0; - } - else -@@ -1142,7 +1151,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - efi_call_2 (b->free_pages, address, pages); - grub_free (file_path); - -- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); -+ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); - - return 0; - } -@@ -1169,10 +1178,7 @@ fail: - grub_free (cmdline); - - if (image_handle != 0) -- { -- efi_call_1 (b->unload_image, image_handle); -- image_handle = 0; -- } -+ efi_call_1 (b->unload_image, image_handle); - - grub_dl_unref (my_mod); - diff --git a/0223-loader-i386-efi-linux-Use-grub_loader_set_ex.patch b/0223-loader-i386-efi-linux-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..1a129db --- /dev/null +++ b/0223-loader-i386-efi-linux-Use-grub_loader_set_ex.patch @@ -0,0 +1,296 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Mon, 2 May 2022 17:04:23 +0200 +Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex + +This ports the linuxefi loader to use grub_loader_set_ex in order to fix +a use-after-fre bug that occurs when grub_cmd_linux is executed more than +once before a boot attempt is performed. + +This is more complicated than for the chainloader command, as the initrd +command needs access to the loader state. To solve this, the linuxefi +module registers a dummy initrd command at startup that returns an error. +The linuxefi command then registers a proper initrd command with a higher +priority that is passed the loader state. + +Signed-off-by: Chris Coulson +(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc) +[rharwood/pjones: set kernel_size in context] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++--------------- + 1 file changed, 87 insertions(+), 59 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 27bc2aa161..e3c2d6fe0b 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -34,13 +34,19 @@ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; +-static int loaded; +-static void *kernel_mem; +-static grub_uint64_t kernel_size; +-static void *initrd_mem; +-static grub_uint32_t handover_offset; +-struct linux_kernel_params *params; +-static char *linux_cmdline; ++ ++static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linuxefi, cmd_initrdefi; ++ ++struct grub_linuxefi_context { ++ void *kernel_mem; ++ grub_uint64_t kernel_size; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params; ++ char *cmdline; ++ ++ void *initrd_mem; ++}; + + #define MIN(a, b) \ + ({ typeof (a) _a = (a); \ +@@ -123,25 +129,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + } + + static grub_err_t +-grub_linuxefi_boot (void) ++grub_linuxefi_boot (void *data) + { ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)kernel_mem, +- handover_offset, +- params); ++ return grub_efi_linux_boot ((char *)context->kernel_mem, ++ context->handover_offset, ++ context->params); + } + + static grub_err_t +-grub_linuxefi_unload (void) ++grub_linuxefi_unload (void *data) + { ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ struct linux_kernel_params *params = context->params; ++ + grub_dl_unref (my_mod); +- loaded = 0; + +- kernel_free(initrd_mem, params->ramdisk_size); +- kernel_free(linux_cmdline, params->cmdline_size + 1); +- kernel_free(kernel_mem, kernel_size); +- kernel_free(params, sizeof(*params)); ++ kernel_free (context->initrd_mem, params->ramdisk_size); ++ kernel_free (context->cmdline, params->cmdline_size + 1); ++ kernel_free (context->kernel_mem, context->kernel_size); ++ kernel_free (params, sizeof(*params)); ++ cmd_initrd->data = 0; ++ cmd_initrdefi->data = 0; ++ grub_free (context); + + return GRUB_ERR_NONE; + } +@@ -188,13 +201,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) + #define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) + + static grub_err_t +-grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), +- int argc, char *argv[]) ++grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + { + grub_file_t *files = 0; + int i, nfiles = 0; + grub_size_t size = 0; + grub_uint8_t *ptr; ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; ++ struct linux_kernel_params *params; + + if (argc == 0) + { +@@ -202,12 +216,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (!loaded) ++ if (!context) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); + goto fail; + } + ++ params = context->params; ++ + files = grub_calloc (argc, sizeof (files[0])); + if (!files) + goto fail; +@@ -225,19 +241,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + } + } + +- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +- if (initrd_mem == NULL) ++ context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (context->initrd_mem == NULL) + goto fail; +- grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); ++ grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); + + params->ramdisk_size = LOW_U32(size); +- params->ramdisk_image = LOW_U32(initrd_mem); ++ params->ramdisk_image = LOW_U32(context->initrd_mem); + #if defined(__x86_64__) + params->ext_ramdisk_size = HIGH_U32(size); +- params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++ params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); + #endif + +- ptr = initrd_mem; ++ ptr = context->initrd_mem; + + for (i = 0; i < nfiles; i++) + { +@@ -261,8 +277,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (files[i]); + grub_free (files); + +- if (initrd_mem && grub_errno) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, ++ if (context->initrd_mem && grub_errno) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, + BYTES_TO_PAGES(size)); + + return grub_errno; +@@ -277,6 +293,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_ssize_t start, filelen; + void *kernel = NULL; + int setup_header_end_offset; ++ void *kernel_mem = 0; ++ grub_uint64_t kernel_size = 0; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params = 0; ++ char *cmdline = 0; ++ struct grub_linuxefi_context *context = 0; + + grub_dl_ref (my_mod); + +@@ -390,27 +412,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); +- if (!linux_cmdline) ++ cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); ++ if (!cmdline) + goto fail; +- grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); ++ grub_dprintf ("linux", "cmdline = %p\n", cmdline); + +- grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, +- linux_cmdline + sizeof (LINUX_IMAGE) - 1, ++ cmdline + 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", "cmdline:%s\n", cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", +- LOW_U32(linux_cmdline)); +- lh->cmd_line_ptr = LOW_U32(linux_cmdline); ++ LOW_U32(cmdline)); ++ lh->cmd_line_ptr = LOW_U32(cmdline); + #if defined(__x86_64__) +- if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) ++ if ((grub_efi_uintn_t)cmdline > 0xffffffffull) + { + grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", +- HIGH_U32(linux_cmdline)); +- params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); ++ HIGH_U32(cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(cmdline); + } + #endif + +@@ -435,16 +457,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; +- kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ kernel_size = lh->init_size; ++ kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) + goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + +- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- +- loaded = 1; +- + grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", + LOW_U32(kernel_mem)); + lh->code32_start = LOW_U32(kernel_mem); +@@ -461,33 +480,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", + params->ext_loader_type, params->ext_loader_ver); + ++ context = grub_zalloc (sizeof (*context)); ++ if (!context) ++ goto fail; ++ context->kernel_mem = kernel_mem; ++ context->kernel_size = kernel_size; ++ context->handover_offset = handover_offset; ++ context->params = params; ++ context->cmdline = cmdline; ++ ++ grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); ++ ++ cmd_initrd->data = context; ++ cmd_initrdefi->data = context; ++ ++ grub_file_close (file); ++ grub_free (kernel); ++ return 0; ++ + fail: + if (file) + grub_file_close (file); + +- if (grub_errno != GRUB_ERR_NONE) +- { +- grub_dl_unref (my_mod); +- loaded = 0; +- } ++ grub_dl_unref (my_mod); + +- if (!loaded) +- { +- if (lh) +- kernel_free (linux_cmdline, lh->cmdline_size + 1); ++ if (lh) ++ kernel_free (cmdline, lh->cmdline_size + 1); + +- kernel_free (kernel_mem, kernel_size); +- kernel_free (params, sizeof(*params)); +- } ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); + ++ grub_free (context); + grub_free (kernel); + + return grub_errno; + } + +-static grub_command_t cmd_linux, cmd_initrd; +-static grub_command_t cmd_linuxefi, cmd_initrdefi; +- + GRUB_MOD_INIT(linux) + { + cmd_linux = diff --git a/0224-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch b/0224-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch deleted file mode 100644 index b79c78c..0000000 --- a/0224-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Mon, 2 May 2022 14:39:31 +0200 -Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi - loader - -In some error paths in grub_cmd_linux, the pointer to lh may be -dereferenced after the buffer it points to has been freed. There aren't -any security implications from this because nothing else uses the -allocator after the buffer is freed and before the pointer is -dereferenced, but fix it anyway. - -Signed-off-by: Chris Coulson -(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2) ---- - grub-core/loader/i386/efi/linux.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 941df6400b..27bc2aa161 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -465,9 +465,6 @@ fail: - if (file) - grub_file_close (file); - -- if (kernel) -- grub_free (kernel); -- - if (grub_errno != GRUB_ERR_NONE) - { - grub_dl_unref (my_mod); -@@ -483,6 +480,8 @@ fail: - kernel_free (params, sizeof(*params)); - } - -+ grub_free (kernel); -+ - return grub_errno; - } - diff --git a/0224-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch b/0224-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch new file mode 100644 index 0000000..51953fd --- /dev/null +++ b/0224-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 3 May 2022 09:47:35 +0200 +Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd + command + +Subsequent invocations of the initrd command result in the previous +initrd being leaked, so fix that. + +Signed-off-by: Chris Coulson +(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0) +--- + grub-core/loader/i386/efi/linux.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index e3c2d6fe0b..9e5c11ac69 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -209,6 +209,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + grub_uint8_t *ptr; + struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; + struct linux_kernel_params *params; ++ void *initrd_mem = 0; + + if (argc == 0) + { +@@ -241,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +- if (context->initrd_mem == NULL) ++ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (initrd_mem == NULL) + goto fail; +- grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + + params->ramdisk_size = LOW_U32(size); +- params->ramdisk_image = LOW_U32(context->initrd_mem); ++ params->ramdisk_image = LOW_U32(initrd_mem); + #if defined(__x86_64__) + params->ext_ramdisk_size = HIGH_U32(size); +- params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); + #endif + +- ptr = context->initrd_mem; ++ ptr = initrd_mem; + + for (i = 0; i < nfiles; i++) + { +@@ -270,6 +271,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + ptr += ALIGN_UP_OVERHEAD (cursize, 4); + } + ++ kernel_free(context->initrd_mem, params->ramdisk_size); ++ ++ context->initrd_mem = initrd_mem; + params->ramdisk_size = size; + + fail: +@@ -277,9 +281,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + grub_file_close (files[i]); + grub_free (files); + +- if (context->initrd_mem && grub_errno) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, +- BYTES_TO_PAGES(size)); ++ if (initrd_mem && grub_errno) ++ kernel_free (initrd_mem, size); + + return grub_errno; + } diff --git a/0225-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/0225-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch new file mode 100644 index 0000000..715e6e1 --- /dev/null +++ b/0225-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Julian Andres Klode +Date: Thu, 2 Dec 2021 15:03:53 +0100 +Subject: [PATCH] kern/efi/sb: Reject non-kernel files in the shim_lock + verifier + +We must not allow other verifiers to pass things like the GRUB modules. +Instead of maintaining a blocklist, maintain an allowlist of things +that we do not care about. + +This allowlist really should be made reusable, and shared by the +lockdown verifier, but this is the minimal patch addressing +security concerns where the TPM verifier was able to mark modules +as verified (or the OpenPGP verifier for that matter), when it +should not do so on shim-powered secure boot systems. + +Fixes: CVE-2022-28735 + +Signed-off-by: Julian Andres Klode +Reviewed-by: Daniel Kiper +(cherry picked from commit fa61ad69861c1cb3f68bf853d78fae7fd93986a0) +--- + grub-core/kern/efi/sb.c | 39 ++++++++++++++++++++++++++++++++++++--- + include/grub/verify.h | 1 + + 2 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index c52ec6226a..89c4bb3fd1 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + void **context __attribute__ ((unused)), + enum grub_verify_flags *flags) + { +- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ *flags = GRUB_VERIFY_FLAGS_NONE; + + switch (type & GRUB_FILE_TYPE_MASK) + { ++ /* Files we check. */ + case GRUB_FILE_TYPE_LINUX_KERNEL: + case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: + case GRUB_FILE_TYPE_BSD_KERNEL: +@@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_PLAN9_KERNEL: + case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: + *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; + +- /* Fall through. */ ++ /* Files that do not affect secureboot state. */ ++ case GRUB_FILE_TYPE_NONE: ++ case GRUB_FILE_TYPE_LOOPBACK: ++ case GRUB_FILE_TYPE_LINUX_INITRD: ++ case GRUB_FILE_TYPE_OPENBSD_RAMDISK: ++ case GRUB_FILE_TYPE_XNU_RAMDISK: ++ case GRUB_FILE_TYPE_SIGNATURE: ++ case GRUB_FILE_TYPE_PUBLIC_KEY: ++ case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST: ++ case GRUB_FILE_TYPE_PRINT_BLOCKLIST: ++ case GRUB_FILE_TYPE_TESTLOAD: ++ case GRUB_FILE_TYPE_GET_SIZE: ++ case GRUB_FILE_TYPE_FONT: ++ case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: ++ case GRUB_FILE_TYPE_CAT: ++ case GRUB_FILE_TYPE_HEXCAT: ++ case GRUB_FILE_TYPE_CMP: ++ case GRUB_FILE_TYPE_HASHLIST: ++ case GRUB_FILE_TYPE_TO_HASH: ++ case GRUB_FILE_TYPE_KEYBOARD_LAYOUT: ++ case GRUB_FILE_TYPE_PIXMAP: ++ case GRUB_FILE_TYPE_GRUB_MODULE_LIST: ++ case GRUB_FILE_TYPE_CONFIG: ++ case GRUB_FILE_TYPE_THEME: ++ case GRUB_FILE_TYPE_GETTEXT_CATALOG: ++ case GRUB_FILE_TYPE_FS_SEARCH: ++ case GRUB_FILE_TYPE_LOADENV: ++ case GRUB_FILE_TYPE_SAVEENV: ++ case GRUB_FILE_TYPE_VERIFY_SIGNATURE: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; + ++ /* Other files. */ + default: +- return GRUB_ERR_NONE; ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy")); + } + } + +diff --git a/include/grub/verify.h b/include/grub/verify.h +index cd129c398f..672ae16924 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -24,6 +24,7 @@ + + enum grub_verify_flags + { ++ GRUB_VERIFY_FLAGS_NONE = 0, + GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, + GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, + /* Defer verification to another authority. */ diff --git a/0225-loader-i386-efi-linux-Use-grub_loader_set_ex.patch b/0225-loader-i386-efi-linux-Use-grub_loader_set_ex.patch deleted file mode 100644 index 1a129db..0000000 --- a/0225-loader-i386-efi-linux-Use-grub_loader_set_ex.patch +++ /dev/null @@ -1,296 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Mon, 2 May 2022 17:04:23 +0200 -Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex - -This ports the linuxefi loader to use grub_loader_set_ex in order to fix -a use-after-fre bug that occurs when grub_cmd_linux is executed more than -once before a boot attempt is performed. - -This is more complicated than for the chainloader command, as the initrd -command needs access to the loader state. To solve this, the linuxefi -module registers a dummy initrd command at startup that returns an error. -The linuxefi command then registers a proper initrd command with a higher -priority that is passed the loader state. - -Signed-off-by: Chris Coulson -(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc) -[rharwood/pjones: set kernel_size in context] -Signed-off-by: Robbie Harwood ---- - grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++--------------- - 1 file changed, 87 insertions(+), 59 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 27bc2aa161..e3c2d6fe0b 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -34,13 +34,19 @@ - GRUB_MOD_LICENSE ("GPLv3+"); - - static grub_dl_t my_mod; --static int loaded; --static void *kernel_mem; --static grub_uint64_t kernel_size; --static void *initrd_mem; --static grub_uint32_t handover_offset; --struct linux_kernel_params *params; --static char *linux_cmdline; -+ -+static grub_command_t cmd_linux, cmd_initrd; -+static grub_command_t cmd_linuxefi, cmd_initrdefi; -+ -+struct grub_linuxefi_context { -+ void *kernel_mem; -+ grub_uint64_t kernel_size; -+ grub_uint32_t handover_offset; -+ struct linux_kernel_params *params; -+ char *cmdline; -+ -+ void *initrd_mem; -+}; - - #define MIN(a, b) \ - ({ typeof (a) _a = (a); \ -@@ -123,25 +129,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) - } - - static grub_err_t --grub_linuxefi_boot (void) -+grub_linuxefi_boot (void *data) - { -+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; -+ - asm volatile ("cli"); - -- return grub_efi_linux_boot ((char *)kernel_mem, -- handover_offset, -- params); -+ return grub_efi_linux_boot ((char *)context->kernel_mem, -+ context->handover_offset, -+ context->params); - } - - static grub_err_t --grub_linuxefi_unload (void) -+grub_linuxefi_unload (void *data) - { -+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; -+ struct linux_kernel_params *params = context->params; -+ - grub_dl_unref (my_mod); -- loaded = 0; - -- kernel_free(initrd_mem, params->ramdisk_size); -- kernel_free(linux_cmdline, params->cmdline_size + 1); -- kernel_free(kernel_mem, kernel_size); -- kernel_free(params, sizeof(*params)); -+ kernel_free (context->initrd_mem, params->ramdisk_size); -+ kernel_free (context->cmdline, params->cmdline_size + 1); -+ kernel_free (context->kernel_mem, context->kernel_size); -+ kernel_free (params, sizeof(*params)); -+ cmd_initrd->data = 0; -+ cmd_initrdefi->data = 0; -+ grub_free (context); - - return GRUB_ERR_NONE; - } -@@ -188,13 +201,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) - #define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) - - static grub_err_t --grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), -- int argc, char *argv[]) -+grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - { - grub_file_t *files = 0; - int i, nfiles = 0; - grub_size_t size = 0; - grub_uint8_t *ptr; -+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; -+ struct linux_kernel_params *params; - - if (argc == 0) - { -@@ -202,12 +216,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -- if (!loaded) -+ if (!context) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); - goto fail; - } - -+ params = context->params; -+ - files = grub_calloc (argc, sizeof (files[0])); - if (!files) - goto fail; -@@ -225,19 +241,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - } - } - -- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); -- if (initrd_mem == NULL) -+ context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); -+ if (context->initrd_mem == NULL) - goto fail; -- grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); -+ grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); - - params->ramdisk_size = LOW_U32(size); -- params->ramdisk_image = LOW_U32(initrd_mem); -+ params->ramdisk_image = LOW_U32(context->initrd_mem); - #if defined(__x86_64__) - params->ext_ramdisk_size = HIGH_U32(size); -- params->ext_ramdisk_image = HIGH_U32(initrd_mem); -+ params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); - #endif - -- ptr = initrd_mem; -+ ptr = context->initrd_mem; - - for (i = 0; i < nfiles; i++) - { -@@ -261,8 +277,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - grub_file_close (files[i]); - grub_free (files); - -- if (initrd_mem && grub_errno) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, -+ if (context->initrd_mem && grub_errno) -+ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, - BYTES_TO_PAGES(size)); - - return grub_errno; -@@ -277,6 +293,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_ssize_t start, filelen; - void *kernel = NULL; - int setup_header_end_offset; -+ void *kernel_mem = 0; -+ grub_uint64_t kernel_size = 0; -+ grub_uint32_t handover_offset; -+ struct linux_kernel_params *params = 0; -+ char *cmdline = 0; -+ struct grub_linuxefi_context *context = 0; - - grub_dl_ref (my_mod); - -@@ -390,27 +412,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_dprintf ("linux", "new lh is at %p\n", lh); - - grub_dprintf ("linux", "setting up cmdline\n"); -- linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); -- if (!linux_cmdline) -+ cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); -+ if (!cmdline) - goto fail; -- grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); -+ grub_dprintf ("linux", "cmdline = %p\n", cmdline); - -- grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); -+ grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); - grub_create_loader_cmdline (argc, argv, -- linux_cmdline + sizeof (LINUX_IMAGE) - 1, -+ cmdline + 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", "cmdline:%s\n", cmdline); - grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", -- LOW_U32(linux_cmdline)); -- lh->cmd_line_ptr = LOW_U32(linux_cmdline); -+ LOW_U32(cmdline)); -+ lh->cmd_line_ptr = LOW_U32(cmdline); - #if defined(__x86_64__) -- if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) -+ if ((grub_efi_uintn_t)cmdline > 0xffffffffull) - { - grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", -- HIGH_U32(linux_cmdline)); -- params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); -+ HIGH_U32(cmdline)); -+ params->ext_cmd_line_ptr = HIGH_U32(cmdline); - } - #endif - -@@ -435,16 +457,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; - max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; -- kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); -+ kernel_size = lh->init_size; -+ kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); - restore_addresses(); - if (!kernel_mem) - goto fail; - grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); - -- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); -- -- loaded = 1; -- - grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", - LOW_U32(kernel_mem)); - lh->code32_start = LOW_U32(kernel_mem); -@@ -461,33 +480,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", - params->ext_loader_type, params->ext_loader_ver); - -+ context = grub_zalloc (sizeof (*context)); -+ if (!context) -+ goto fail; -+ context->kernel_mem = kernel_mem; -+ context->kernel_size = kernel_size; -+ context->handover_offset = handover_offset; -+ context->params = params; -+ context->cmdline = cmdline; -+ -+ grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); -+ -+ cmd_initrd->data = context; -+ cmd_initrdefi->data = context; -+ -+ grub_file_close (file); -+ grub_free (kernel); -+ return 0; -+ - fail: - if (file) - grub_file_close (file); - -- if (grub_errno != GRUB_ERR_NONE) -- { -- grub_dl_unref (my_mod); -- loaded = 0; -- } -+ grub_dl_unref (my_mod); - -- if (!loaded) -- { -- if (lh) -- kernel_free (linux_cmdline, lh->cmdline_size + 1); -+ if (lh) -+ kernel_free (cmdline, lh->cmdline_size + 1); - -- kernel_free (kernel_mem, kernel_size); -- kernel_free (params, sizeof(*params)); -- } -+ kernel_free (kernel_mem, kernel_size); -+ kernel_free (params, sizeof(*params)); - -+ grub_free (context); - grub_free (kernel); - - return grub_errno; - } - --static grub_command_t cmd_linux, cmd_initrd; --static grub_command_t cmd_linuxefi, cmd_initrdefi; -- - GRUB_MOD_INIT(linux) - { - cmd_linux = diff --git a/0226-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/0226-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch new file mode 100644 index 0000000..bcc5503 --- /dev/null +++ b/0226-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 25 Jun 2021 02:19:05 +1000 +Subject: [PATCH] kern/file: Do not leak device_name on error in + grub_file_open() + +If we have an error in grub_file_open() before we free device_name, we +will leak it. + +Free device_name in the error path and null out the pointer in the good +path once we free it there. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea) +--- + grub-core/kern/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index e19aea3e51..ed69fc0f0f 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -81,6 +81,7 @@ grub_file_open (const char *name, enum grub_file_type type) + + device = grub_device_open (device_name); + grub_free (device_name); ++ device_name = NULL; + if (! device) + goto fail; + +@@ -135,6 +136,7 @@ grub_file_open (const char *name, enum grub_file_type type) + return file; + + fail: ++ grub_free (device_name); + if (device) + grub_device_close (device); + diff --git a/0226-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch b/0226-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch deleted file mode 100644 index 51953fd..0000000 --- a/0226-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Chris Coulson -Date: Tue, 3 May 2022 09:47:35 +0200 -Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd - command - -Subsequent invocations of the initrd command result in the previous -initrd being leaked, so fix that. - -Signed-off-by: Chris Coulson -(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0) ---- - grub-core/loader/i386/efi/linux.c | 21 ++++++++++++--------- - 1 file changed, 12 insertions(+), 9 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index e3c2d6fe0b..9e5c11ac69 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -209,6 +209,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - grub_uint8_t *ptr; - struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; - struct linux_kernel_params *params; -+ void *initrd_mem = 0; - - if (argc == 0) - { -@@ -241,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - } - } - -- context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); -- if (context->initrd_mem == NULL) -+ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); -+ if (initrd_mem == NULL) - goto fail; -- grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); -+ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); - - params->ramdisk_size = LOW_U32(size); -- params->ramdisk_image = LOW_U32(context->initrd_mem); -+ params->ramdisk_image = LOW_U32(initrd_mem); - #if defined(__x86_64__) - params->ext_ramdisk_size = HIGH_U32(size); -- params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); -+ params->ext_ramdisk_image = HIGH_U32(initrd_mem); - #endif - -- ptr = context->initrd_mem; -+ ptr = initrd_mem; - - for (i = 0; i < nfiles; i++) - { -@@ -270,6 +271,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - ptr += ALIGN_UP_OVERHEAD (cursize, 4); - } - -+ kernel_free(context->initrd_mem, params->ramdisk_size); -+ -+ context->initrd_mem = initrd_mem; - params->ramdisk_size = size; - - fail: -@@ -277,9 +281,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - grub_file_close (files[i]); - grub_free (files); - -- if (context->initrd_mem && grub_errno) -- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, -- BYTES_TO_PAGES(size)); -+ if (initrd_mem && grub_errno) -+ kernel_free (initrd_mem, size); - - return grub_errno; - } diff --git a/0227-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/0227-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch deleted file mode 100644 index 715e6e1..0000000 --- a/0227-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Julian Andres Klode -Date: Thu, 2 Dec 2021 15:03:53 +0100 -Subject: [PATCH] kern/efi/sb: Reject non-kernel files in the shim_lock - verifier - -We must not allow other verifiers to pass things like the GRUB modules. -Instead of maintaining a blocklist, maintain an allowlist of things -that we do not care about. - -This allowlist really should be made reusable, and shared by the -lockdown verifier, but this is the minimal patch addressing -security concerns where the TPM verifier was able to mark modules -as verified (or the OpenPGP verifier for that matter), when it -should not do so on shim-powered secure boot systems. - -Fixes: CVE-2022-28735 - -Signed-off-by: Julian Andres Klode -Reviewed-by: Daniel Kiper -(cherry picked from commit fa61ad69861c1cb3f68bf853d78fae7fd93986a0) ---- - grub-core/kern/efi/sb.c | 39 ++++++++++++++++++++++++++++++++++++--- - include/grub/verify.h | 1 + - 2 files changed, 37 insertions(+), 3 deletions(-) - -diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c -index c52ec6226a..89c4bb3fd1 100644 ---- a/grub-core/kern/efi/sb.c -+++ b/grub-core/kern/efi/sb.c -@@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), - void **context __attribute__ ((unused)), - enum grub_verify_flags *flags) - { -- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; -+ *flags = GRUB_VERIFY_FLAGS_NONE; - - switch (type & GRUB_FILE_TYPE_MASK) - { -+ /* Files we check. */ - case GRUB_FILE_TYPE_LINUX_KERNEL: - case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: - case GRUB_FILE_TYPE_BSD_KERNEL: -@@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), - case GRUB_FILE_TYPE_PLAN9_KERNEL: - case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: - *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; -+ return GRUB_ERR_NONE; - -- /* Fall through. */ -+ /* Files that do not affect secureboot state. */ -+ case GRUB_FILE_TYPE_NONE: -+ case GRUB_FILE_TYPE_LOOPBACK: -+ case GRUB_FILE_TYPE_LINUX_INITRD: -+ case GRUB_FILE_TYPE_OPENBSD_RAMDISK: -+ case GRUB_FILE_TYPE_XNU_RAMDISK: -+ case GRUB_FILE_TYPE_SIGNATURE: -+ case GRUB_FILE_TYPE_PUBLIC_KEY: -+ case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST: -+ case GRUB_FILE_TYPE_PRINT_BLOCKLIST: -+ case GRUB_FILE_TYPE_TESTLOAD: -+ case GRUB_FILE_TYPE_GET_SIZE: -+ case GRUB_FILE_TYPE_FONT: -+ case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: -+ case GRUB_FILE_TYPE_CAT: -+ case GRUB_FILE_TYPE_HEXCAT: -+ case GRUB_FILE_TYPE_CMP: -+ case GRUB_FILE_TYPE_HASHLIST: -+ case GRUB_FILE_TYPE_TO_HASH: -+ case GRUB_FILE_TYPE_KEYBOARD_LAYOUT: -+ case GRUB_FILE_TYPE_PIXMAP: -+ case GRUB_FILE_TYPE_GRUB_MODULE_LIST: -+ case GRUB_FILE_TYPE_CONFIG: -+ case GRUB_FILE_TYPE_THEME: -+ case GRUB_FILE_TYPE_GETTEXT_CATALOG: -+ case GRUB_FILE_TYPE_FS_SEARCH: -+ case GRUB_FILE_TYPE_LOADENV: -+ case GRUB_FILE_TYPE_SAVEENV: -+ case GRUB_FILE_TYPE_VERIFY_SIGNATURE: -+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; -+ return GRUB_ERR_NONE; - -+ /* Other files. */ - default: -- return GRUB_ERR_NONE; -+ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy")); - } - } - -diff --git a/include/grub/verify.h b/include/grub/verify.h -index cd129c398f..672ae16924 100644 ---- a/include/grub/verify.h -+++ b/include/grub/verify.h -@@ -24,6 +24,7 @@ - - enum grub_verify_flags - { -+ GRUB_VERIFY_FLAGS_NONE = 0, - GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, - GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, - /* Defer verification to another authority. */ diff --git a/0227-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/0227-video-readers-png-Abort-sooner-if-a-read-operation-f.patch new file mode 100644 index 0000000..385d3ed --- /dev/null +++ b/0227-video-readers-png-Abort-sooner-if-a-read-operation-f.patch @@ -0,0 +1,198 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:02:55 +1000 +Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494) +--- + grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++------- + 1 file changed, 47 insertions(+), 8 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 0157ff7420..e2a6b1cf3c 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -142,6 +142,7 @@ static grub_uint8_t + grub_png_get_byte (struct grub_png_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read = 0; + + if ((data->inside_idat) && (data->idat_remain == 0)) + { +@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data) + } + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: unexpected end of data"); ++ return 0; ++ } + + if (data->inside_idat) + data->idat_remain--; +@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data, + if (len == 0) + return GRUB_ERR_NONE; + +- for (i = 0; 3 * i < len && i < 256; i++) ++ grub_errno = GRUB_ERR_NONE; ++ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++) + for (j = 0; j < 3; j++) + data->palette[i][j] = grub_png_get_byte (data); +- for (i *= 3; i < len; i++) ++ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_get_byte (data); + + grub_png_get_dword (data); + +- return GRUB_ERR_NONE; ++ return grub_errno; + } + + static grub_err_t +@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); + + color_bits = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + data->is_16bit = (color_bits == 16); + + color_type = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* According to PNG spec, no other types are valid. */ + if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) +@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data) + if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: compression method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: filter method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_INTERLACE_NONE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: interlace method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* Skip crc checksum. */ + grub_png_get_dword (data); +@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht) + int code, i; + + code = 0; +- for (i = 0; i < ht->max_length; i++) ++ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++) + { + code = (code << 1) + grub_png_get_bits (data, 1); + if (code < ht->maxval[i]) +@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + grub_uint8_t lens[DEFLATE_HCLEN_MAX]; + + nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) || + (nb > DEFLATE_HCLEN_MAX)) +@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + data->dist_offset); + + prev = 0; +- for (i = 0; i < nl + nd; i++) ++ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++) + { + int n, code; + struct huff_table *ht; +@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + pos = data->wp - dist; + if (pos < 0) + pos += WSIZE; + +- while (len > 0) ++ while (len > 0 && grub_errno == GRUB_ERR_NONE) + { + data->slide[data->wp] = data->slide[pos]; + grub_png_output_byte (data, data->slide[data->wp]); +@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int final; + + cmf = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + flg = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((cmf & 0xF) != Z_DEFLATED) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, +@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int block_type; + + final = grub_png_get_bits (data, 1); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + block_type = grub_png_get_bits (data, 2); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + switch (block_type) + { +@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data) + grub_png_get_byte (data); + grub_png_get_byte (data); + +- for (i = 0; i < len; i++) ++ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_output_byte (data, grub_png_get_byte (data)); + + break; +@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data) + + len = grub_png_get_dword (data); + type = grub_png_get_dword (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ break; + data->next_offset = data->file->offset + len + 4; + + switch (type) diff --git a/0228-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/0228-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch deleted file mode 100644 index bcc5503..0000000 --- a/0228-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Fri, 25 Jun 2021 02:19:05 +1000 -Subject: [PATCH] kern/file: Do not leak device_name on error in - grub_file_open() - -If we have an error in grub_file_open() before we free device_name, we -will leak it. - -Free device_name in the error path and null out the pointer in the good -path once we free it there. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea) ---- - grub-core/kern/file.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c -index e19aea3e51..ed69fc0f0f 100644 ---- a/grub-core/kern/file.c -+++ b/grub-core/kern/file.c -@@ -81,6 +81,7 @@ grub_file_open (const char *name, enum grub_file_type type) - - device = grub_device_open (device_name); - grub_free (device_name); -+ device_name = NULL; - if (! device) - goto fail; - -@@ -135,6 +136,7 @@ grub_file_open (const char *name, enum grub_file_type type) - return file; - - fail: -+ grub_free (device_name); - if (device) - grub_device_close (device); - diff --git a/0228-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/0228-video-readers-png-Refuse-to-handle-multiple-image-he.patch new file mode 100644 index 0000000..9168fe5 --- /dev/null +++ b/0228-video-readers-png-Refuse-to-handle-multiple-image-he.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:13:40 +1000 +Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers + +This causes the bitmap to be leaked. Do not permit multiple image headers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb) +--- + grub-core/video/readers/png.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index e2a6b1cf3c..8955b8ecfd 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data) + int color_bits; + enum grub_video_blit_format blt; + ++ if (data->image_width || data->image_height) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found"); ++ + data->image_width = grub_png_get_dword (data); + data->image_height = grub_png_get_dword (data); + diff --git a/0229-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/0229-video-readers-png-Abort-sooner-if-a-read-operation-f.patch deleted file mode 100644 index 385d3ed..0000000 --- a/0229-video-readers-png-Abort-sooner-if-a-read-operation-f.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 6 Jul 2021 14:02:55 +1000 -Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails - -Fuzzing revealed some inputs that were taking a long time, potentially -forever, because they did not bail quickly upon encountering an I/O error. - -Try to catch I/O errors sooner and bail out. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494) ---- - grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++------- - 1 file changed, 47 insertions(+), 8 deletions(-) - -diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c -index 0157ff7420..e2a6b1cf3c 100644 ---- a/grub-core/video/readers/png.c -+++ b/grub-core/video/readers/png.c -@@ -142,6 +142,7 @@ static grub_uint8_t - grub_png_get_byte (struct grub_png_data *data) - { - grub_uint8_t r; -+ grub_ssize_t bytes_read = 0; - - if ((data->inside_idat) && (data->idat_remain == 0)) - { -@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data) - } - - r = 0; -- grub_file_read (data->file, &r, 1); -+ bytes_read = grub_file_read (data->file, &r, 1); -+ -+ if (bytes_read != 1) -+ { -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "png: unexpected end of data"); -+ return 0; -+ } - - if (data->inside_idat) - data->idat_remain--; -@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data, - if (len == 0) - return GRUB_ERR_NONE; - -- for (i = 0; 3 * i < len && i < 256; i++) -+ grub_errno = GRUB_ERR_NONE; -+ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++) - for (j = 0; j < 3; j++) - data->palette[i][j] = grub_png_get_byte (data); -- for (i *= 3; i < len; i++) -+ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++) - grub_png_get_byte (data); - - grub_png_get_dword (data); - -- return GRUB_ERR_NONE; -+ return grub_errno; - } - - static grub_err_t -@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); - - color_bits = grub_png_get_byte (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - data->is_16bit = (color_bits == 16); - - color_type = grub_png_get_byte (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - /* According to PNG spec, no other types are valid. */ - if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) -@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data) - if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "png: compression method not supported"); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "png: filter method not supported"); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - if (grub_png_get_byte (data) != PNG_INTERLACE_NONE) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "png: interlace method not supported"); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - /* Skip crc checksum. */ - grub_png_get_dword (data); -@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht) - int code, i; - - code = 0; -- for (i = 0; i < ht->max_length; i++) -+ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++) - { - code = (code << 1) + grub_png_get_bits (data, 1); - if (code < ht->maxval[i]) -@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data) - grub_uint8_t lens[DEFLATE_HCLEN_MAX]; - - nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) || - (nb > DEFLATE_HCLEN_MAX)) -@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data) - data->dist_offset); - - prev = 0; -- for (i = 0; i < nl + nd; i++) -+ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++) - { - int n, code; - struct huff_table *ht; -@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data) - len = cplens[n]; - if (cplext[n]) - len += grub_png_get_bits (data, cplext[n]); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - n = grub_png_get_huff_code (data, &data->dist_table); - dist = cpdist[n]; - if (cpdext[n]) - dist += grub_png_get_bits (data, cpdext[n]); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - pos = data->wp - dist; - if (pos < 0) - pos += WSIZE; - -- while (len > 0) -+ while (len > 0 && grub_errno == GRUB_ERR_NONE) - { - data->slide[data->wp] = data->slide[pos]; - grub_png_output_byte (data, data->slide[data->wp]); -@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data) - int final; - - cmf = grub_png_get_byte (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - flg = grub_png_get_byte (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - if ((cmf & 0xF) != Z_DEFLATED) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, -@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data) - int block_type; - - final = grub_png_get_bits (data, 1); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - block_type = grub_png_get_bits (data, 2); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - switch (block_type) - { -@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data) - grub_png_get_byte (data); - grub_png_get_byte (data); - -- for (i = 0; i < len; i++) -+ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++) - grub_png_output_byte (data, grub_png_get_byte (data)); - - break; -@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data) - - len = grub_png_get_dword (data); - type = grub_png_get_dword (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ break; - data->next_offset = data->file->offset + len + 4; - - switch (type) diff --git a/0229-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/0229-video-readers-png-Drop-greyscale-support-to-fix-heap.patch new file mode 100644 index 0000000..4529cb8 --- /dev/null +++ b/0229-video-readers-png-Drop-greyscale-support-to-fix-heap.patch @@ -0,0 +1,170 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 18:51:35 +1000 +Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap + out-of-bounds write + +A 16-bit greyscale PNG without alpha is processed in the following loop: + + for (i = 0; i < (data->image_width * data->image_height); + i++, d1 += 4, d2 += 2) + { + d1[R3] = d2[1]; + d1[G3] = d2[1]; + d1[B3] = d2[1]; + } + +The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration, +but there are only 3 bytes allocated for storage. This means that image +data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes +out of every 4 following the end of the image. + +This has existed since greyscale support was added in 2013 in commit +3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale). + +Saving starfield.png as a 16-bit greyscale image without alpha in the gimp +and attempting to load it causes grub-emu to crash - I don't think this code +has ever worked. + +Delete all PNG greyscale support. + +Fixes: CVE-2021-3695 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9) +[rharwood: context conflict] +Signed-off-by: Robbie Harwood +--- + grub-core/video/readers/png.c | 85 +++---------------------------------------- + 1 file changed, 6 insertions(+), 79 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 8955b8ecfd..a3161e25b6 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -100,7 +100,7 @@ struct grub_png_data + + unsigned image_width, image_height; + int bpp, is_16bit; +- int raw_bytes, is_gray, is_alpha, is_palette; ++ int raw_bytes, is_alpha, is_palette; + int row_bytes, color_bits; + grub_uint8_t *image_data; + +@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + data->bpp = 3; + else + { +- data->is_gray = 1; +- data->bpp = 1; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: color type not supported"); + } + + if ((color_bits != 8) && (color_bits != 16) + && (color_bits != 4 +- || !(data->is_gray || data->is_palette))) ++ || !data->is_palette)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: bit depth must be 8 or 16"); + +@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data) + } + + #ifndef GRUB_CPU_WORDS_BIGENDIAN +- if (data->is_16bit || data->is_gray || data->is_palette) ++ if (data->is_16bit || data->is_palette) + #endif + { + data->image_data = grub_calloc (data->image_height, data->row_bytes); +@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data) + int shift; + int mask = (1 << data->color_bits) - 1; + unsigned j; +- if (data->is_gray) +- { +- /* Generic formula is +- (0xff * i) / ((1U << data->color_bits) - 1) +- but for allowed bit depth of 1, 2 and for it's +- equivalent to +- (0xff / ((1U << data->color_bits) - 1)) * i +- Precompute the multipliers to avoid division. +- */ + +- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 }; +- for (i = 0; i < (1U << data->color_bits); i++) +- { +- grub_uint8_t col = multipliers[data->color_bits] * i; +- palette[i][0] = col; +- palette[i][1] = col; +- palette[i][2] = col; +- } +- } +- else +- grub_memcpy (palette, data->palette, 3 << data->color_bits); ++ grub_memcpy (palette, data->palette, 3 << data->color_bits); + d1c = d1; + d2c = d2; + for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3, +@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data) + } + return; + } +- +- if (data->is_gray) +- { +- switch (data->bpp) +- { +- case 4: +- /* 16-bit gray with alpha. */ +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 4) +- { +- d1[R4] = d2[3]; +- d1[G4] = d2[3]; +- d1[B4] = d2[3]; +- d1[A4] = d2[1]; +- } +- break; +- case 2: +- if (data->is_16bit) +- /* 16-bit gray without alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R3] = d2[1]; +- d1[G3] = d2[1]; +- d1[B3] = d2[1]; +- } +- } +- else +- /* 8-bit gray with alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R4] = d2[1]; +- d1[G4] = d2[1]; +- d1[B4] = d2[1]; +- d1[A4] = d2[0]; +- } +- } +- break; +- /* 8-bit gray without alpha. */ +- case 1: +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 3, d2++) +- { +- d1[R3] = d2[0]; +- d1[G3] = d2[0]; +- d1[B3] = d2[0]; +- } +- break; +- } +- return; +- } + + { + /* Only copy the upper 8 bit. */ diff --git a/0230-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/0230-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch new file mode 100644 index 0000000..51dddfe --- /dev/null +++ b/0230-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 23:25:07 +1000 +Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table + items + +In fuzzing we observed crashes where a code would attempt to be inserted +into a huffman table before the start, leading to a set of heap OOB reads +and writes as table entries with negative indices were shifted around and +the new code written in. + +Catch the case where we would underflow the array and bail. + +Fixes: CVE-2021-3696 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa) +--- + grub-core/video/readers/png.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index a3161e25b6..d7ed5aa6cf 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len) + for (i = len; i < ht->max_length; i++) + n += ht->maxval[i]; + ++ if (n > ht->num_values) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: out of range inserting huffman table item"); ++ return; ++ } ++ + for (i = 0; i < n; i++) + ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1]; + diff --git a/0230-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/0230-video-readers-png-Refuse-to-handle-multiple-image-he.patch deleted file mode 100644 index 9168fe5..0000000 --- a/0230-video-readers-png-Refuse-to-handle-multiple-image-he.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 6 Jul 2021 14:13:40 +1000 -Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers - -This causes the bitmap to be leaked. Do not permit multiple image headers. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb) ---- - grub-core/video/readers/png.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c -index e2a6b1cf3c..8955b8ecfd 100644 ---- a/grub-core/video/readers/png.c -+++ b/grub-core/video/readers/png.c -@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data) - int color_bits; - enum grub_video_blit_format blt; - -+ if (data->image_width || data->image_height) -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found"); -+ - data->image_width = grub_png_get_dword (data); - data->image_height = grub_png_get_dword (data); - diff --git a/0231-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/0231-video-readers-png-Drop-greyscale-support-to-fix-heap.patch deleted file mode 100644 index 4529cb8..0000000 --- a/0231-video-readers-png-Drop-greyscale-support-to-fix-heap.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 6 Jul 2021 18:51:35 +1000 -Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap - out-of-bounds write - -A 16-bit greyscale PNG without alpha is processed in the following loop: - - for (i = 0; i < (data->image_width * data->image_height); - i++, d1 += 4, d2 += 2) - { - d1[R3] = d2[1]; - d1[G3] = d2[1]; - d1[B3] = d2[1]; - } - -The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration, -but there are only 3 bytes allocated for storage. This means that image -data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes -out of every 4 following the end of the image. - -This has existed since greyscale support was added in 2013 in commit -3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale). - -Saving starfield.png as a 16-bit greyscale image without alpha in the gimp -and attempting to load it causes grub-emu to crash - I don't think this code -has ever worked. - -Delete all PNG greyscale support. - -Fixes: CVE-2021-3695 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9) -[rharwood: context conflict] -Signed-off-by: Robbie Harwood ---- - grub-core/video/readers/png.c | 85 +++---------------------------------------- - 1 file changed, 6 insertions(+), 79 deletions(-) - -diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c -index 8955b8ecfd..a3161e25b6 100644 ---- a/grub-core/video/readers/png.c -+++ b/grub-core/video/readers/png.c -@@ -100,7 +100,7 @@ struct grub_png_data - - unsigned image_width, image_height; - int bpp, is_16bit; -- int raw_bytes, is_gray, is_alpha, is_palette; -+ int raw_bytes, is_alpha, is_palette; - int row_bytes, color_bits; - grub_uint8_t *image_data; - -@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data) - data->bpp = 3; - else - { -- data->is_gray = 1; -- data->bpp = 1; -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "png: color type not supported"); - } - - if ((color_bits != 8) && (color_bits != 16) - && (color_bits != 4 -- || !(data->is_gray || data->is_palette))) -+ || !data->is_palette)) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "png: bit depth must be 8 or 16"); - -@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data) - } - - #ifndef GRUB_CPU_WORDS_BIGENDIAN -- if (data->is_16bit || data->is_gray || data->is_palette) -+ if (data->is_16bit || data->is_palette) - #endif - { - data->image_data = grub_calloc (data->image_height, data->row_bytes); -@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data) - int shift; - int mask = (1 << data->color_bits) - 1; - unsigned j; -- if (data->is_gray) -- { -- /* Generic formula is -- (0xff * i) / ((1U << data->color_bits) - 1) -- but for allowed bit depth of 1, 2 and for it's -- equivalent to -- (0xff / ((1U << data->color_bits) - 1)) * i -- Precompute the multipliers to avoid division. -- */ - -- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 }; -- for (i = 0; i < (1U << data->color_bits); i++) -- { -- grub_uint8_t col = multipliers[data->color_bits] * i; -- palette[i][0] = col; -- palette[i][1] = col; -- palette[i][2] = col; -- } -- } -- else -- grub_memcpy (palette, data->palette, 3 << data->color_bits); -+ grub_memcpy (palette, data->palette, 3 << data->color_bits); - d1c = d1; - d2c = d2; - for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3, -@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data) - } - return; - } -- -- if (data->is_gray) -- { -- switch (data->bpp) -- { -- case 4: -- /* 16-bit gray with alpha. */ -- for (i = 0; i < (data->image_width * data->image_height); -- i++, d1 += 4, d2 += 4) -- { -- d1[R4] = d2[3]; -- d1[G4] = d2[3]; -- d1[B4] = d2[3]; -- d1[A4] = d2[1]; -- } -- break; -- case 2: -- if (data->is_16bit) -- /* 16-bit gray without alpha. */ -- { -- for (i = 0; i < (data->image_width * data->image_height); -- i++, d1 += 4, d2 += 2) -- { -- d1[R3] = d2[1]; -- d1[G3] = d2[1]; -- d1[B3] = d2[1]; -- } -- } -- else -- /* 8-bit gray with alpha. */ -- { -- for (i = 0; i < (data->image_width * data->image_height); -- i++, d1 += 4, d2 += 2) -- { -- d1[R4] = d2[1]; -- d1[G4] = d2[1]; -- d1[B4] = d2[1]; -- d1[A4] = d2[0]; -- } -- } -- break; -- /* 8-bit gray without alpha. */ -- case 1: -- for (i = 0; i < (data->image_width * data->image_height); -- i++, d1 += 3, d2++) -- { -- d1[R3] = d2[0]; -- d1[G3] = d2[0]; -- d1[B3] = d2[0]; -- } -- break; -- } -- return; -- } - - { - /* Only copy the upper 8 bit. */ diff --git a/0231-video-readers-png-Sanity-check-some-huffman-codes.patch b/0231-video-readers-png-Sanity-check-some-huffman-codes.patch new file mode 100644 index 0000000..c9cef25 --- /dev/null +++ b/0231-video-readers-png-Sanity-check-some-huffman-codes.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 19:19:11 +1000 +Subject: [PATCH] video/readers/png: Sanity check some huffman codes + +ASAN picked up two OOB global reads: we weren't checking if some code +values fit within the cplens or cpdext arrays. Check and throw an error +if not. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117) +--- + grub-core/video/readers/png.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index d7ed5aa6cf..7f2ba7849b 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + int len, dist, pos; + + n -= 257; ++ if (((unsigned int) n) >= ARRAY_SIZE (cplens)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); +@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); ++ if (((unsigned int) n) >= ARRAY_SIZE (cpdist)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); diff --git a/0232-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/0232-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch new file mode 100644 index 0000000..5491816 --- /dev/null +++ b/0232-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch @@ -0,0 +1,255 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:14 +1000 +Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c) +--- + grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++-------- + 1 file changed, 70 insertions(+), 16 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index e31602f766..10225abd53 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -109,9 +109,17 @@ static grub_uint8_t + grub_jpeg_get_byte (struct grub_jpeg_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return r; + } +@@ -120,9 +128,17 @@ static grub_uint16_t + grub_jpeg_get_word (struct grub_jpeg_data *data) + { + grub_uint16_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ ++ if (bytes_read != sizeof (grub_uint16_t)) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return grub_be_to_cpu16 (r); + } +@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + if (data->bit_mask == 0) + { + data->bit_save = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: file read error"); ++ return 0; ++ } + if (data->bit_save == JPEG_ESC_CHAR) + { + if (grub_jpeg_get_byte (data) != 0) +@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + "jpeg: invalid 0xFF in data stream"); + return 0; + } ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error"); ++ return 0; ++ } + } + data->bit_mask = 0x80; + } +@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num) + return 0; + + msb = value = grub_jpeg_get_bit (data); +- for (i = 1; i < num; i++) ++ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++) + value = (value << 1) + (grub_jpeg_get_bit (data) != 0); + if (!msb) + value += 1 - (1 << num); +@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + while (data->file->offset + sizeof (count) + 1 <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ac = (id >> 4) & 1; + id &= 0xF; + if (id > 1) +@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (next_marker > data->file->size) + { +@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (id >= 0x10) /* Upper 4-bit is precision. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (grub_jpeg_get_byte (data) != 8) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); + + ss = grub_jpeg_get_byte (data); /* Sampling factor. */ ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (!id) + { + grub_uint8_t vs, hs; +@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du) + } + } + +-static void ++static grub_err_t + grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + { + int h1, h2, qt; +@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + data->dc_value[id] += + grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; + pos = 1; + while (pos < ARRAY_SIZE (data->quan_table[qt])) +@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + num >>= 4; + pos += num; + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) + { +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: invalid position in zigzag order!?"); +- return; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: invalid position in zigzag order!?"); + } + + du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; +@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + } + + grub_jpeg_idct_transform (du); ++ return GRUB_ERR_NONE; + } + + static void +@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + data_offset += grub_jpeg_get_word (data); + + cc = grub_jpeg_get_byte (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (cc != 3 && cc != 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: component count must be 1 or 3"); +@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + id = grub_jpeg_get_byte (data) - 1; + if ((id < 0) || (id >= 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ht = grub_jpeg_get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; +@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) || + (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + } + + grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ + grub_jpeg_get_word (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + +@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + { + unsigned c1, vb, hb, nr1, nc1; + int rst = data->dri; ++ grub_err_t err = GRUB_ERR_NONE; + + vb = 8 << data->log_vs; + hb = 8 << data->log_hs; +@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + + for (r2 = 0; r2 < (1U << data->log_vs); r2++) + for (c2 = 0; c2 < (1U << data->log_hs); c2++) +- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ { ++ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } + + if (data->color_components >= 3) + { +- grub_jpeg_decode_du (data, 1, data->cbdu); +- grub_jpeg_decode_du (data, 2, data->crdu); ++ err = grub_jpeg_decode_du (data, 1, data->cbdu); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ err = grub_jpeg_decode_du (data, 2, data->crdu); ++ if (err != GRUB_ERR_NONE) ++ return err; + } + +- if (grub_errno) +- return grub_errno; +- + nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; + nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; + diff --git a/0232-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/0232-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch deleted file mode 100644 index 51dddfe..0000000 --- a/0232-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 6 Jul 2021 23:25:07 +1000 -Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table - items - -In fuzzing we observed crashes where a code would attempt to be inserted -into a huffman table before the start, leading to a set of heap OOB reads -and writes as table entries with negative indices were shifted around and -the new code written in. - -Catch the case where we would underflow the array and bail. - -Fixes: CVE-2021-3696 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa) ---- - grub-core/video/readers/png.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c -index a3161e25b6..d7ed5aa6cf 100644 ---- a/grub-core/video/readers/png.c -+++ b/grub-core/video/readers/png.c -@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len) - for (i = len; i < ht->max_length; i++) - n += ht->maxval[i]; - -+ if (n > ht->num_values) -+ { -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "png: out of range inserting huffman table item"); -+ return; -+ } -+ - for (i = 0; i < n; i++) - ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1]; - diff --git a/0233-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/0233-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch new file mode 100644 index 0000000..199ec32 --- /dev/null +++ b/0233-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:58 +1000 +Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table + +Fix a memory leak where an invalid file could cause us to reallocate +memory for a huffman table we had already allocated memory for. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9) +--- + grub-core/video/readers/jpeg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 10225abd53..caa211f06d 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + n += count[i]; + + id += ac * 2; ++ if (data->huff_value[id] != NULL) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempt to reallocate huffman table"); + data->huff_value[id] = grub_malloc (n); + if (grub_errno) + return grub_errno; diff --git a/0233-video-readers-png-Sanity-check-some-huffman-codes.patch b/0233-video-readers-png-Sanity-check-some-huffman-codes.patch deleted file mode 100644 index c9cef25..0000000 --- a/0233-video-readers-png-Sanity-check-some-huffman-codes.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 6 Jul 2021 19:19:11 +1000 -Subject: [PATCH] video/readers/png: Sanity check some huffman codes - -ASAN picked up two OOB global reads: we weren't checking if some code -values fit within the cplens or cpdext arrays. Check and throw an error -if not. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117) ---- - grub-core/video/readers/png.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c -index d7ed5aa6cf..7f2ba7849b 100644 ---- a/grub-core/video/readers/png.c -+++ b/grub-core/video/readers/png.c -@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) - int len, dist, pos; - - n -= 257; -+ if (((unsigned int) n) >= ARRAY_SIZE (cplens)) -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "png: invalid huff code"); - len = cplens[n]; - if (cplext[n]) - len += grub_png_get_bits (data, cplext[n]); -@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) - return grub_errno; - - n = grub_png_get_huff_code (data, &data->dist_table); -+ if (((unsigned int) n) >= ARRAY_SIZE (cpdist)) -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "png: invalid huff code"); - dist = cpdist[n]; - if (cpdext[n]) - dist += grub_png_get_bits (data, cpdext[n]); diff --git a/0234-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/0234-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch deleted file mode 100644 index 5491816..0000000 --- a/0234-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch +++ /dev/null @@ -1,255 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 28 Jun 2021 14:16:14 +1000 -Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails - -Fuzzing revealed some inputs that were taking a long time, potentially -forever, because they did not bail quickly upon encountering an I/O error. - -Try to catch I/O errors sooner and bail out. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c) ---- - grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++-------- - 1 file changed, 70 insertions(+), 16 deletions(-) - -diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c -index e31602f766..10225abd53 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -109,9 +109,17 @@ static grub_uint8_t - grub_jpeg_get_byte (struct grub_jpeg_data *data) - { - grub_uint8_t r; -+ grub_ssize_t bytes_read; - - r = 0; -- grub_file_read (data->file, &r, 1); -+ bytes_read = grub_file_read (data->file, &r, 1); -+ -+ if (bytes_read != 1) -+ { -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: unexpected end of data"); -+ return 0; -+ } - - return r; - } -@@ -120,9 +128,17 @@ static grub_uint16_t - grub_jpeg_get_word (struct grub_jpeg_data *data) - { - grub_uint16_t r; -+ grub_ssize_t bytes_read; - - r = 0; -- grub_file_read (data->file, &r, sizeof (grub_uint16_t)); -+ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t)); -+ -+ if (bytes_read != sizeof (grub_uint16_t)) -+ { -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: unexpected end of data"); -+ return 0; -+ } - - return grub_be_to_cpu16 (r); - } -@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) - if (data->bit_mask == 0) - { - data->bit_save = grub_jpeg_get_byte (data); -+ if (grub_errno != GRUB_ERR_NONE) { -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: file read error"); -+ return 0; -+ } - if (data->bit_save == JPEG_ESC_CHAR) - { - if (grub_jpeg_get_byte (data) != 0) -@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) - "jpeg: invalid 0xFF in data stream"); - return 0; - } -+ if (grub_errno != GRUB_ERR_NONE) -+ { -+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error"); -+ return 0; -+ } - } - data->bit_mask = 0x80; - } -@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num) - return 0; - - msb = value = grub_jpeg_get_bit (data); -- for (i = 1; i < num; i++) -+ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++) - value = (value << 1) + (grub_jpeg_get_bit (data) != 0); - if (!msb) - value += 1 - (1 << num); -@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) - while (data->file->offset + sizeof (count) + 1 <= next_marker) - { - id = grub_jpeg_get_byte (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - ac = (id >> 4) & 1; - id &= 0xF; - if (id > 1) -@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) - - next_marker = data->file->offset; - next_marker += grub_jpeg_get_word (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - - if (next_marker > data->file->size) - { -@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) - <= next_marker) - { - id = grub_jpeg_get_byte (data); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - if (id >= 0x10) /* Upper 4-bit is precision. */ - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: only 8-bit precision is supported"); -@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) - next_marker = data->file->offset; - next_marker += grub_jpeg_get_word (data); - -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; -+ - if (grub_jpeg_get_byte (data) != 8) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: only 8-bit precision is supported"); -@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); - - ss = grub_jpeg_get_byte (data); /* Sampling factor. */ -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - if (!id) - { - grub_uint8_t vs, hs; -@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du) - } - } - --static void -+static grub_err_t - grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) - { - int h1, h2, qt; -@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) - data->dc_value[id] += - grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); - -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; -+ - du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; - pos = 1; - while (pos < ARRAY_SIZE (data->quan_table[qt])) -@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) - num >>= 4; - pos += num; - -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; -+ - if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) - { -- grub_error (GRUB_ERR_BAD_FILE_TYPE, -- "jpeg: invalid position in zigzag order!?"); -- return; -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: invalid position in zigzag order!?"); - } - - du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; -@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) - } - - grub_jpeg_idct_transform (du); -+ return GRUB_ERR_NONE; - } - - static void -@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) - data_offset += grub_jpeg_get_word (data); - - cc = grub_jpeg_get_byte (data); -- -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - if (cc != 3 && cc != 1) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: component count must be 1 or 3"); -@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) - id = grub_jpeg_get_byte (data) - 1; - if ((id < 0) || (id >= 3)) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); -- -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - ht = grub_jpeg_get_byte (data); - data->comp_index[id][1] = (ht >> 4); - data->comp_index[id][2] = (ht & 0xF) + 2; -@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) - if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) || - (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3)) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index"); -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - } - - grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ - grub_jpeg_get_word (data); -- -+ if (grub_errno != GRUB_ERR_NONE) -+ return grub_errno; - if (data->file->offset != data_offset) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); - -@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) - { - unsigned c1, vb, hb, nr1, nc1; - int rst = data->dri; -+ grub_err_t err = GRUB_ERR_NONE; - - vb = 8 << data->log_vs; - hb = 8 << data->log_hs; -@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) - - for (r2 = 0; r2 < (1U << data->log_vs); r2++) - for (c2 = 0; c2 < (1U << data->log_hs); c2++) -- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); -+ { -+ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); -+ if (err != GRUB_ERR_NONE) -+ return err; -+ } - - if (data->color_components >= 3) - { -- grub_jpeg_decode_du (data, 1, data->cbdu); -- grub_jpeg_decode_du (data, 2, data->crdu); -+ err = grub_jpeg_decode_du (data, 1, data->cbdu); -+ if (err != GRUB_ERR_NONE) -+ return err; -+ err = grub_jpeg_decode_du (data, 2, data->crdu); -+ if (err != GRUB_ERR_NONE) -+ return err; - } - -- if (grub_errno) -- return grub_errno; -- - nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; - nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; - diff --git a/0234-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/0234-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch new file mode 100644 index 0000000..179238b --- /dev/null +++ b/0234-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:25:17 +1000 +Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of + streams + +An invalid file could contain multiple start of stream blocks, which +would cause us to reallocate and leak our bitmap. Refuse to handle +multiple start of streams. + +Additionally, fix a grub_error() call formatting. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f) +--- + grub-core/video/readers/jpeg.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index caa211f06d..1df1171d78 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + ++ if (*data->bitmap) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks"); ++ + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_RGB_888)) +@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs); + + if (data->bitmap_ptr == NULL) +- return grub_error(GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: attempted to decode data before start of stream"); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempted to decode data before start of stream"); + + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) diff --git a/0235-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/0235-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch new file mode 100644 index 0000000..99eeb62 --- /dev/null +++ b/0235-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 7 Jul 2021 15:38:19 +1000 +Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write + +Certain 1 px wide images caused a wild pointer write in +grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(), +we have the following loop: + +for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + +We did not check if vb * width >= hb * nc1. + +On a 64-bit platform, if that turns out to be negative, it will underflow, +be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so +we see data->bitmap_ptr jump, e.g.: + +0x6180_0000_0480 to +0x6181_0000_0498 + ^ + ~--- carry has occurred and this pointer is now far away from + any object. + +On a 32-bit platform, it will decrement the pointer, creating a pointer +that won't crash but will overwrite random data. + +Catch the underflow and error out. + +Fixes: CVE-2021-3697 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5) +--- + 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 1df1171d78..2da04094b3 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: attempted to decode data before start of stream"); + ++ if (vb * data->image_width <= hb * nc1) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: cannot decode image with these dimensions"); ++ + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + for (c1 = 0; c1 < nc1 && (!data->dri || rst); diff --git a/0235-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/0235-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch deleted file mode 100644 index 199ec32..0000000 --- a/0235-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 28 Jun 2021 14:16:58 +1000 -Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table - -Fix a memory leak where an invalid file could cause us to reallocate -memory for a huffman table we had already allocated memory for. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9) ---- - grub-core/video/readers/jpeg.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c -index 10225abd53..caa211f06d 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) - n += count[i]; - - id += ac * 2; -+ if (data->huff_value[id] != NULL) -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: attempt to reallocate huffman table"); - data->huff_value[id] = grub_malloc (n); - if (grub_errno) - return grub_errno; diff --git a/0236-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/0236-normal-charset-Fix-array-out-of-bounds-formatting-un.patch new file mode 100644 index 0000000..6e64ed8 --- /dev/null +++ b/0236-normal-charset-Fix-array-out-of-bounds-formatting-un.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 13 Jul 2021 13:24:38 +1000 +Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode + for display + +In some cases attempting to display arbitrary binary strings leads +to ASAN splats reading the widthspec array out of bounds. + +Check the index. If it would be out of bounds, return a width of 1. +I don't know if that's strictly correct, but we're not really expecting +great display of arbitrary binary data, and it's certainly not worse than +an OOB read. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d) +--- + grub-core/normal/charset.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index 4dfcc31078..7a5a7c153c 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c) + { + if (grub_unicode_get_comb_type (c->base)) + return 0; ++ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec)) ++ return 1; + if (widthspec[c->base >> 3] & (1 << (c->base & 7))) + return 2; + else diff --git a/0236-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/0236-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch deleted file mode 100644 index 179238b..0000000 --- a/0236-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 28 Jun 2021 14:25:17 +1000 -Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of - streams - -An invalid file could contain multiple start of stream blocks, which -would cause us to reallocate and leak our bitmap. Refuse to handle -multiple start of streams. - -Additionally, fix a grub_error() call formatting. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f) ---- - grub-core/video/readers/jpeg.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c -index caa211f06d..1df1171d78 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) - if (data->file->offset != data_offset) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); - -+ if (*data->bitmap) -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks"); -+ - if (grub_video_bitmap_create (data->bitmap, data->image_width, - data->image_height, - GRUB_VIDEO_BLIT_FORMAT_RGB_888)) -@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) - nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs); - - if (data->bitmap_ptr == NULL) -- return grub_error(GRUB_ERR_BAD_FILE_TYPE, -- "jpeg: attempted to decode data before start of stream"); -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: attempted to decode data before start of stream"); - - for (; data->r1 < nr1 && (!data->dri || rst); - data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) diff --git a/0237-net-netbuff-Block-overly-large-netbuff-allocs.patch b/0237-net-netbuff-Block-overly-large-netbuff-allocs.patch new file mode 100644 index 0000000..2e10d49 --- /dev/null +++ b/0237-net-netbuff-Block-overly-large-netbuff-allocs.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 23:47:46 +1100 +Subject: [PATCH] net/netbuff: Block overly large netbuff allocs + +A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment +reassembly. + +This helps avoid some bugs (and provides a spot to instrument to catch +them at their source). + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57) +--- + grub-core/net/netbuff.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c +index dbeeefe478..d5e9e9a0d7 100644 +--- a/grub-core/net/netbuff.c ++++ b/grub-core/net/netbuff.c +@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len) + + COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); + ++ /* ++ * The largest size of a TCP packet is 64 KiB, and everything else ++ * should be a lot smaller - most MTUs are 1500 or less. Cap data ++ * size at 64 KiB + a buffer. ++ */ ++ if (len > 0xffffUL + 0x1000UL) ++ { ++ grub_error (GRUB_ERR_BUG, ++ "attempted to allocate a packet that is too big"); ++ return NULL; ++ } ++ + if (len < NETBUFFMINLEN) + len = NETBUFFMINLEN; + + len = ALIGN_UP (len, NETBUFF_ALIGN); ++ + #ifdef GRUB_MACHINE_EMU + data = grub_malloc (len + sizeof (*nb)); + #else diff --git a/0237-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/0237-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch deleted file mode 100644 index 99eeb62..0000000 --- a/0237-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Wed, 7 Jul 2021 15:38:19 +1000 -Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write - -Certain 1 px wide images caused a wild pointer write in -grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(), -we have the following loop: - -for (; data->r1 < nr1 && (!data->dri || rst); - data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) - -We did not check if vb * width >= hb * nc1. - -On a 64-bit platform, if that turns out to be negative, it will underflow, -be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so -we see data->bitmap_ptr jump, e.g.: - -0x6180_0000_0480 to -0x6181_0000_0498 - ^ - ~--- carry has occurred and this pointer is now far away from - any object. - -On a 32-bit platform, it will decrement the pointer, creating a pointer -that won't crash but will overwrite random data. - -Catch the underflow and error out. - -Fixes: CVE-2021-3697 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5) ---- - 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 1df1171d78..2da04094b3 100644 ---- a/grub-core/video/readers/jpeg.c -+++ b/grub-core/video/readers/jpeg.c -@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: attempted to decode data before start of stream"); - -+ if (vb * data->image_width <= hb * nc1) -+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, -+ "jpeg: cannot decode image with these dimensions"); -+ - for (; data->r1 < nr1 && (!data->dri || rst); - data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) - for (c1 = 0; c1 < nc1 && (!data->dri || rst); diff --git a/0238-net-ip-Do-IP-fragment-maths-safely.patch b/0238-net-ip-Do-IP-fragment-maths-safely.patch new file mode 100644 index 0000000..118448d --- /dev/null +++ b/0238-net-ip-Do-IP-fragment-maths-safely.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 19:41:21 +1100 +Subject: [PATCH] net/ip: Do IP fragment maths safely + +This avoids an underflow and subsequent unpleasantness. + +Fixes: CVE-2022-28733 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936) +--- + grub-core/net/ip.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index ce6bdc75c6..cf74f1f794 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + struct iphdr { +@@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb, + { + rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + + (nb->tail - nb->data)); +- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t)); ++ ++ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t), ++ &rsm->total_len)) ++ { ++ grub_dprintf ("net", "IP reassembly size underflow\n"); ++ return GRUB_ERR_NONE; ++ } ++ + rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len); + if (!rsm->asm_netbuff) + { diff --git a/0238-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/0238-normal-charset-Fix-array-out-of-bounds-formatting-un.patch deleted file mode 100644 index 6e64ed8..0000000 --- a/0238-normal-charset-Fix-array-out-of-bounds-formatting-un.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 13 Jul 2021 13:24:38 +1000 -Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode - for display - -In some cases attempting to display arbitrary binary strings leads -to ASAN splats reading the widthspec array out of bounds. - -Check the index. If it would be out of bounds, return a width of 1. -I don't know if that's strictly correct, but we're not really expecting -great display of arbitrary binary data, and it's certainly not worse than -an OOB read. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d) ---- - grub-core/normal/charset.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c -index 4dfcc31078..7a5a7c153c 100644 ---- a/grub-core/normal/charset.c -+++ b/grub-core/normal/charset.c -@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c) - { - if (grub_unicode_get_comb_type (c->base)) - return 0; -+ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec)) -+ return 1; - if (widthspec[c->base >> 3] & (1 << (c->base & 7))) - return 2; - else diff --git a/0239-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/0239-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch new file mode 100644 index 0000000..19701b6 --- /dev/null +++ b/0239-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 16 Sep 2021 01:29:54 +1000 +Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response + +grub_net_dns_lookup() takes as inputs a pointer to an array of addresses +("addresses") for the given name, and pointer to a number of addresses +("naddresses"). grub_net_dns_lookup() is responsible for allocating +"addresses", and the caller is responsible for freeing it if +"naddresses" > 0. + +The DNS recv_hook will sometimes set and free the addresses array, +for example if the packet is too short: + + if (ptr + 10 >= nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + +Later on the nslookup command code unconditionally frees the "addresses" +array. Normally this is fine: the array is either populated with valid +data or is NULL. But in these sorts of error cases it is neither NULL +nor valid and we get a double-free. + +Only free "addresses" if "naddresses" > 0. + +It looks like the other use of grub_net_dns_lookup() is not affected. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1) +--- + grub-core/net/dns.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 906ec7d678..135faac035 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)), + grub_net_addr_to_str (&addresses[i], buf); + grub_printf ("%s\n", buf); + } +- grub_free (addresses); + if (naddresses) +- return GRUB_ERR_NONE; ++ { ++ grub_free (addresses); ++ return GRUB_ERR_NONE; ++ } + return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found")); + } + diff --git a/0239-net-netbuff-Block-overly-large-netbuff-allocs.patch b/0239-net-netbuff-Block-overly-large-netbuff-allocs.patch deleted file mode 100644 index 2e10d49..0000000 --- a/0239-net-netbuff-Block-overly-large-netbuff-allocs.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 8 Mar 2022 23:47:46 +1100 -Subject: [PATCH] net/netbuff: Block overly large netbuff allocs - -A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment -reassembly. - -This helps avoid some bugs (and provides a spot to instrument to catch -them at their source). - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57) ---- - grub-core/net/netbuff.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c -index dbeeefe478..d5e9e9a0d7 100644 ---- a/grub-core/net/netbuff.c -+++ b/grub-core/net/netbuff.c -@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len) - - COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); - -+ /* -+ * The largest size of a TCP packet is 64 KiB, and everything else -+ * should be a lot smaller - most MTUs are 1500 or less. Cap data -+ * size at 64 KiB + a buffer. -+ */ -+ if (len > 0xffffUL + 0x1000UL) -+ { -+ grub_error (GRUB_ERR_BUG, -+ "attempted to allocate a packet that is too big"); -+ return NULL; -+ } -+ - if (len < NETBUFFMINLEN) - len = NETBUFFMINLEN; - - len = ALIGN_UP (len, NETBUFF_ALIGN); -+ - #ifdef GRUB_MACHINE_EMU - data = grub_malloc (len + sizeof (*nb)); - #else diff --git a/0240-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/0240-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch new file mode 100644 index 0000000..ab0d471 --- /dev/null +++ b/0240-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 21:55:43 +1100 +Subject: [PATCH] net/dns: Don't read past the end of the string we're checking + against + +I don't really understand what's going on here but fuzzing found +a bug where we read past the end of check_with. That's a C string, +so use grub_strlen() to make sure we don't overread it. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21) +--- + grub-core/net/dns.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 135faac035..17961a9f18 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + int *length, char *set) + { + const char *readable_ptr = check_with; ++ int readable_len; + const grub_uint8_t *ptr; + char *optr = set; + int bytes_processed = 0; + if (length) + *length = 0; ++ ++ if (readable_ptr != NULL) ++ readable_len = grub_strlen (readable_ptr); ++ else ++ readable_len = 0; ++ + for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) + { + /* End marker. */ +@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); + continue; + } +- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) ++ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)) + return 0; + if (grub_memchr (ptr + 1, 0, *ptr) + || grub_memchr (ptr + 1, '.', *ptr)) + return 0; + if (readable_ptr) +- readable_ptr += *ptr; ++ { ++ readable_ptr += *ptr; ++ readable_len -= *ptr; ++ } + if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) + return 0; + bytes_processed += *ptr + 1; +@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + if (optr) + *optr++ = '.'; + if (readable_ptr && *readable_ptr) +- readable_ptr++; ++ { ++ readable_ptr++; ++ readable_len--; ++ } + ptr += *ptr + 1; + } + return 0; diff --git a/0240-net-ip-Do-IP-fragment-maths-safely.patch b/0240-net-ip-Do-IP-fragment-maths-safely.patch deleted file mode 100644 index 118448d..0000000 --- a/0240-net-ip-Do-IP-fragment-maths-safely.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 20 Dec 2021 19:41:21 +1100 -Subject: [PATCH] net/ip: Do IP fragment maths safely - -This avoids an underflow and subsequent unpleasantness. - -Fixes: CVE-2022-28733 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936) ---- - grub-core/net/ip.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c -index ce6bdc75c6..cf74f1f794 100644 ---- a/grub-core/net/ip.c -+++ b/grub-core/net/ip.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - #include - - struct iphdr { -@@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb, - { - rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) - + (nb->tail - nb->data)); -- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t)); -+ -+ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t), -+ &rsm->total_len)) -+ { -+ grub_dprintf ("net", "IP reassembly size underflow\n"); -+ return GRUB_ERR_NONE; -+ } -+ - rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len); - if (!rsm->asm_netbuff) - { diff --git a/0241-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/0241-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch deleted file mode 100644 index 19701b6..0000000 --- a/0241-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Thu, 16 Sep 2021 01:29:54 +1000 -Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response - -grub_net_dns_lookup() takes as inputs a pointer to an array of addresses -("addresses") for the given name, and pointer to a number of addresses -("naddresses"). grub_net_dns_lookup() is responsible for allocating -"addresses", and the caller is responsible for freeing it if -"naddresses" > 0. - -The DNS recv_hook will sometimes set and free the addresses array, -for example if the packet is too short: - - if (ptr + 10 >= nb->tail) - { - if (!*data->naddresses) - grub_free (*data->addresses); - grub_netbuff_free (nb); - return GRUB_ERR_NONE; - } - -Later on the nslookup command code unconditionally frees the "addresses" -array. Normally this is fine: the array is either populated with valid -data or is NULL. But in these sorts of error cases it is neither NULL -nor valid and we get a double-free. - -Only free "addresses" if "naddresses" > 0. - -It looks like the other use of grub_net_dns_lookup() is not affected. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1) ---- - grub-core/net/dns.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c -index 906ec7d678..135faac035 100644 ---- a/grub-core/net/dns.c -+++ b/grub-core/net/dns.c -@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)), - grub_net_addr_to_str (&addresses[i], buf); - grub_printf ("%s\n", buf); - } -- grub_free (addresses); - if (naddresses) -- return GRUB_ERR_NONE; -+ { -+ grub_free (addresses); -+ return GRUB_ERR_NONE; -+ } - return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found")); - } - diff --git a/0241-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/0241-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch new file mode 100644 index 0000000..3ff7b6b --- /dev/null +++ b/0241-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Sep 2021 01:12:24 +1000 +Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek + +A malicious tftp server can cause UAFs and a double free. + +An attempt to read from a network file is handled by grub_net_fs_read(). If +the read is at an offset other than the current offset, grub_net_seek_real() +is invoked. + +In grub_net_seek_real(), if a backwards seek cannot be satisfied from the +currently received packets, and the underlying transport does not provide +a seek method, then grub_net_seek_real() will close and reopen the network +protocol layer. + +For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t +file->data. The file->data pointer is not nulled out after the free. + +If the ->open() call fails, the file->data will not be reallocated and will +continue point to a freed memory block. This could happen from a server +refusing to send the requisite ack to the new tftp request, for example. + +The seek and the read will then fail, but the grub_file continues to exist: +the failed seek does not necessarily cause the entire file to be thrown +away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc., +a read failure is interpreted as a decompressor passing on the file, not as +an invalidation of the entire grub_file_t structure). + +This means subsequent attempts to read or seek the file will use the old +file->data after free. Eventually, the file will be close()d again and +file->data will be freed again. + +Mark a net_fs file that doesn't reopen as broken. Do not permit read() or +close() on a broken file (seek is not exposed directly to the file API - +it is only called as part of read, so this blocks seeks as well). + +As an additional defence, null out the ->data pointer if tftp_open() fails. +That would have lead to a simple null pointer dereference rather than +a mess of UAFs. + +This may affect other protocols, I haven't checked. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81) +--- + grub-core/net/net.c | 11 +++++++++-- + grub-core/net/tftp.c | 1 + + include/grub/net.h | 1 + + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 55aed92722..1001c611d1 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file) + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } +- file->device->net->protocol->close (file); ++ if (!file->device->net->broken) ++ file->device->net->protocol->close (file); + grub_free (file->device->net->name); + return GRUB_ERR_NONE; + } +@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + file->device->net->stall = 0; + err = file->device->net->protocol->open (file, file->device->net->name); + if (err) +- return err; ++ { ++ file->device->net->broken = 1; ++ return err; ++ } + grub_net_fs_read_real (file, NULL, offset); + return grub_errno; + } +@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + static grub_ssize_t + grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) + { ++ if (file->device->net->broken) ++ return -1; ++ + if (file->offset != file->device->net->offset) + { + grub_err_t err; +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index d54b13f09f..788ad1dc44 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -408,6 +408,7 @@ tftp_open (struct grub_file *file, const char *filename) + { + grub_net_udp_close (data->sock); + grub_free (data); ++ file->data = NULL; + return grub_errno; + } + +diff --git a/include/grub/net.h b/include/grub/net.h +index 42af7de250..9e4898cc6b 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -280,6 +280,7 @@ typedef struct grub_net + grub_fs_t fs; + int eof; + int stall; ++ int broken; + } *grub_net_t; + + extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); diff --git a/0242-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/0242-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch deleted file mode 100644 index ab0d471..0000000 --- a/0242-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 20 Dec 2021 21:55:43 +1100 -Subject: [PATCH] net/dns: Don't read past the end of the string we're checking - against - -I don't really understand what's going on here but fuzzing found -a bug where we read past the end of check_with. That's a C string, -so use grub_strlen() to make sure we don't overread it. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21) ---- - grub-core/net/dns.c | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c -index 135faac035..17961a9f18 100644 ---- a/grub-core/net/dns.c -+++ b/grub-core/net/dns.c -@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, - int *length, char *set) - { - const char *readable_ptr = check_with; -+ int readable_len; - const grub_uint8_t *ptr; - char *optr = set; - int bytes_processed = 0; - if (length) - *length = 0; -+ -+ if (readable_ptr != NULL) -+ readable_len = grub_strlen (readable_ptr); -+ else -+ readable_len = 0; -+ - for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) - { - /* End marker. */ -@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, - ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); - continue; - } -- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) -+ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)) - return 0; - if (grub_memchr (ptr + 1, 0, *ptr) - || grub_memchr (ptr + 1, '.', *ptr)) - return 0; - if (readable_ptr) -- readable_ptr += *ptr; -+ { -+ readable_ptr += *ptr; -+ readable_len -= *ptr; -+ } - if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) - return 0; - bytes_processed += *ptr + 1; -@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, - if (optr) - *optr++ = '.'; - if (readable_ptr && *readable_ptr) -- readable_ptr++; -+ { -+ readable_ptr++; -+ readable_len--; -+ } - ptr += *ptr + 1; - } - return 0; diff --git a/0242-net-tftp-Avoid-a-trivial-UAF.patch b/0242-net-tftp-Avoid-a-trivial-UAF.patch new file mode 100644 index 0000000..4ec3b56 --- /dev/null +++ b/0242-net-tftp-Avoid-a-trivial-UAF.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 18 Jan 2022 14:29:20 +1100 +Subject: [PATCH] net/tftp: Avoid a trivial UAF + +Under tftp errors, we print a tftp error message from the tftp header. +However, the tftph pointer is a pointer inside nb, the netbuff. Previously, +we were freeing the nb and then dereferencing it. Don't do that, use it +and then free it later. + +This isn't really _bad_ per se, especially as we're single-threaded, but +it trips up fuzzers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5) +--- + grub-core/net/tftp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 788ad1dc44..a95766dcbd 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + return GRUB_ERR_NONE; + case TFTP_ERROR: + data->have_oack = 1; +- grub_netbuff_free (nb); + grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); + grub_error_save (&data->save_err); ++ grub_netbuff_free (nb); + return GRUB_ERR_NONE; + default: + grub_netbuff_free (nb); diff --git a/0243-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/0243-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch new file mode 100644 index 0000000..186f0c3 --- /dev/null +++ b/0243-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 1 Mar 2022 23:14:15 +1100 +Subject: [PATCH] net/http: Do not tear down socket if it's already been torn + down + +It's possible for data->sock to get torn down in tcp error handling. +If we unconditionally tear it down again we will end up doing writes +to an offset of the NULL pointer when we go to tear it down again. + +Detect if it has been torn down and don't do it again. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85) +--- + grub-core/net/http.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 7f878b5615..19cb8768e3 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + return err; + } + +- for (i = 0; !data->headers_recv && i < 100; i++) ++ for (i = 0; data->sock && !data->headers_recv && i < 100; i++) + { + grub_net_tcp_retransmit (); + grub_net_poll_cards (300, &data->headers_recv); +@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + + if (!data->headers_recv) + { +- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); ++ if (data->sock) ++ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->err) + { + char *str = data->errmsg; diff --git a/0243-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/0243-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch deleted file mode 100644 index 3ff7b6b..0000000 --- a/0243-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Mon, 20 Sep 2021 01:12:24 +1000 -Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek - -A malicious tftp server can cause UAFs and a double free. - -An attempt to read from a network file is handled by grub_net_fs_read(). If -the read is at an offset other than the current offset, grub_net_seek_real() -is invoked. - -In grub_net_seek_real(), if a backwards seek cannot be satisfied from the -currently received packets, and the underlying transport does not provide -a seek method, then grub_net_seek_real() will close and reopen the network -protocol layer. - -For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t -file->data. The file->data pointer is not nulled out after the free. - -If the ->open() call fails, the file->data will not be reallocated and will -continue point to a freed memory block. This could happen from a server -refusing to send the requisite ack to the new tftp request, for example. - -The seek and the read will then fail, but the grub_file continues to exist: -the failed seek does not necessarily cause the entire file to be thrown -away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc., -a read failure is interpreted as a decompressor passing on the file, not as -an invalidation of the entire grub_file_t structure). - -This means subsequent attempts to read or seek the file will use the old -file->data after free. Eventually, the file will be close()d again and -file->data will be freed again. - -Mark a net_fs file that doesn't reopen as broken. Do not permit read() or -close() on a broken file (seek is not exposed directly to the file API - -it is only called as part of read, so this blocks seeks as well). - -As an additional defence, null out the ->data pointer if tftp_open() fails. -That would have lead to a simple null pointer dereference rather than -a mess of UAFs. - -This may affect other protocols, I haven't checked. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81) ---- - grub-core/net/net.c | 11 +++++++++-- - grub-core/net/tftp.c | 1 + - include/grub/net.h | 1 + - 3 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/net.c b/grub-core/net/net.c -index 55aed92722..1001c611d1 100644 ---- a/grub-core/net/net.c -+++ b/grub-core/net/net.c -@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file) - grub_netbuff_free (file->device->net->packs.first->nb); - grub_net_remove_packet (file->device->net->packs.first); - } -- file->device->net->protocol->close (file); -+ if (!file->device->net->broken) -+ file->device->net->protocol->close (file); - grub_free (file->device->net->name); - return GRUB_ERR_NONE; - } -@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) - file->device->net->stall = 0; - err = file->device->net->protocol->open (file, file->device->net->name); - if (err) -- return err; -+ { -+ file->device->net->broken = 1; -+ return err; -+ } - grub_net_fs_read_real (file, NULL, offset); - return grub_errno; - } -@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) - static grub_ssize_t - grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) - { -+ if (file->device->net->broken) -+ return -1; -+ - if (file->offset != file->device->net->offset) - { - grub_err_t err; -diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c -index d54b13f09f..788ad1dc44 100644 ---- a/grub-core/net/tftp.c -+++ b/grub-core/net/tftp.c -@@ -408,6 +408,7 @@ tftp_open (struct grub_file *file, const char *filename) - { - grub_net_udp_close (data->sock); - grub_free (data); -+ file->data = NULL; - return grub_errno; - } - -diff --git a/include/grub/net.h b/include/grub/net.h -index 42af7de250..9e4898cc6b 100644 ---- a/include/grub/net.h -+++ b/include/grub/net.h -@@ -280,6 +280,7 @@ typedef struct grub_net - grub_fs_t fs; - int eof; - int stall; -+ int broken; - } *grub_net_t; - - extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); diff --git a/0244-net-http-Fix-OOB-write-for-split-http-headers.patch b/0244-net-http-Fix-OOB-write-for-split-http-headers.patch new file mode 100644 index 0000000..f22960b --- /dev/null +++ b/0244-net-http-Fix-OOB-write-for-split-http-headers.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 18:17:03 +1100 +Subject: [PATCH] net/http: Fix OOB write for split http headers + +GRUB has special code for handling an http header that is split +across two packets. + +The code tracks the end of line by looking for a "\n" byte. The +code for split headers has always advanced the pointer just past the +end of the line, whereas the code that handles unsplit headers does +not advance the pointer. This extra advance causes the length to be +one greater, which breaks an assumption in parse_line(), leading to +it writing a NUL byte one byte past the end of the buffer where we +reconstruct the line from the two packets. + +It's conceivable that an attacker controlled set of packets could +cause this to zero out the first byte of the "next" pointer of the +grub_mm_region structure following the current_line buffer. + +Do not advance the pointer in the split header case. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617) +--- + grub-core/net/http.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 19cb8768e3..58546739a2 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + int have_line = 1; + char *t; + ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); +- if (ptr) +- ptr++; +- else ++ if (ptr == NULL) + { + have_line = 0; + ptr = (char *) nb->tail; diff --git a/0244-net-tftp-Avoid-a-trivial-UAF.patch b/0244-net-tftp-Avoid-a-trivial-UAF.patch deleted file mode 100644 index 4ec3b56..0000000 --- a/0244-net-tftp-Avoid-a-trivial-UAF.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 18 Jan 2022 14:29:20 +1100 -Subject: [PATCH] net/tftp: Avoid a trivial UAF - -Under tftp errors, we print a tftp error message from the tftp header. -However, the tftph pointer is a pointer inside nb, the netbuff. Previously, -we were freeing the nb and then dereferencing it. Don't do that, use it -and then free it later. - -This isn't really _bad_ per se, especially as we're single-threaded, but -it trips up fuzzers. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5) ---- - grub-core/net/tftp.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c -index 788ad1dc44..a95766dcbd 100644 ---- a/grub-core/net/tftp.c -+++ b/grub-core/net/tftp.c -@@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), - return GRUB_ERR_NONE; - case TFTP_ERROR: - data->have_oack = 1; -- grub_netbuff_free (nb); - grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); - grub_error_save (&data->save_err); -+ grub_netbuff_free (nb); - return GRUB_ERR_NONE; - default: - grub_netbuff_free (nb); diff --git a/0245-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/0245-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch deleted file mode 100644 index 186f0c3..0000000 --- a/0245-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 1 Mar 2022 23:14:15 +1100 -Subject: [PATCH] net/http: Do not tear down socket if it's already been torn - down - -It's possible for data->sock to get torn down in tcp error handling. -If we unconditionally tear it down again we will end up doing writes -to an offset of the NULL pointer when we go to tear it down again. - -Detect if it has been torn down and don't do it again. - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85) ---- - grub-core/net/http.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/grub-core/net/http.c b/grub-core/net/http.c -index 7f878b5615..19cb8768e3 100644 ---- a/grub-core/net/http.c -+++ b/grub-core/net/http.c -@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) - return err; - } - -- for (i = 0; !data->headers_recv && i < 100; i++) -+ for (i = 0; data->sock && !data->headers_recv && i < 100; i++) - { - grub_net_tcp_retransmit (); - grub_net_poll_cards (300, &data->headers_recv); -@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) - - if (!data->headers_recv) - { -- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); -+ if (data->sock) -+ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); - if (data->err) - { - char *str = data->errmsg; diff --git a/0245-net-http-Error-out-on-headers-with-LF-without-CR.patch b/0245-net-http-Error-out-on-headers-with-LF-without-CR.patch new file mode 100644 index 0000000..b73c169 --- /dev/null +++ b/0245-net-http-Error-out-on-headers-with-LF-without-CR.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 19:04:40 +1100 +Subject: [PATCH] net/http: Error out on headers with LF without CR + +In a similar vein to the previous patch, parse_line() would write +a NUL byte past the end of the buffer if there was an HTTP header +with a LF rather than a CRLF. + +RFC-2616 says: + + Many HTTP/1.1 header field values consist of words separated by LWS + or special characters. These special characters MUST be in a quoted + string to be used within a parameter value (as defined in section 3.6). + +We don't support quoted sections or continuation lines, etc. + +If we see an LF that's not part of a CRLF, bail out. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de) +--- + grub-core/net/http.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 58546739a2..57d2721719 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + char *end = ptr + len; + while (end > ptr && *(end - 1) == '\r') + end--; ++ ++ /* LF without CR. */ ++ if (end == ptr + len) ++ { ++ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR")); ++ return GRUB_ERR_NONE; ++ } + *end = 0; ++ + /* Trailing CRLF. */ + if (data->in_chunk_len == 1) + { diff --git a/0246-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/0246-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch new file mode 100644 index 0000000..79df1c2 --- /dev/null +++ b/0246-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:03:37 +0530 +Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries + +A corrupt f2fs file system could specify a nat journal entry count +that is beyond the maximum NAT_JOURNAL_ENTRIES. + +Check if the specified nat journal entry count before accessing the +array, and throw an error if it is too large. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e) +--- + grub-core/fs/f2fs.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8a9992ca9e..63702214b0 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data) + return err; + } + +-static grub_uint32_t +-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid) ++static grub_err_t ++get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, ++ grub_uint32_t *blkaddr) + { + grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); +- grub_uint32_t blkaddr = 0; + grub_uint16_t i; + ++ if (n >= NAT_JOURNAL_ENTRIES) ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid number of nat journal entries"); ++ + for (i = 0; i < n; i++) + { + if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid) + { +- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); ++ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); + break; + } + } + +- return blkaddr; ++ return GRUB_ERR_NONE; + } + + static grub_uint32_t +@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + { + struct grub_f2fs_nat_block *nat_block; + grub_uint32_t seg_off, block_off, entry_off, block_addr; +- grub_uint32_t blkaddr; ++ grub_uint32_t blkaddr = 0; + grub_err_t err; + +- blkaddr = get_blkaddr_from_nat_journal (data, nid); ++ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); ++ if (err != GRUB_ERR_NONE) ++ return 0; ++ + if (blkaddr) + return blkaddr; + diff --git a/0246-net-http-Fix-OOB-write-for-split-http-headers.patch b/0246-net-http-Fix-OOB-write-for-split-http-headers.patch deleted file mode 100644 index f22960b..0000000 --- a/0246-net-http-Fix-OOB-write-for-split-http-headers.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 8 Mar 2022 18:17:03 +1100 -Subject: [PATCH] net/http: Fix OOB write for split http headers - -GRUB has special code for handling an http header that is split -across two packets. - -The code tracks the end of line by looking for a "\n" byte. The -code for split headers has always advanced the pointer just past the -end of the line, whereas the code that handles unsplit headers does -not advance the pointer. This extra advance causes the length to be -one greater, which breaks an assumption in parse_line(), leading to -it writing a NUL byte one byte past the end of the buffer where we -reconstruct the line from the two packets. - -It's conceivable that an attacker controlled set of packets could -cause this to zero out the first byte of the "next" pointer of the -grub_mm_region structure following the current_line buffer. - -Do not advance the pointer in the split header case. - -Fixes: CVE-2022-28734 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617) ---- - grub-core/net/http.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/grub-core/net/http.c b/grub-core/net/http.c -index 19cb8768e3..58546739a2 100644 ---- a/grub-core/net/http.c -+++ b/grub-core/net/http.c -@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), - int have_line = 1; - char *t; - ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); -- if (ptr) -- ptr++; -- else -+ if (ptr == NULL) - { - have_line = 0; - ptr = (char *) nb->tail; diff --git a/0247-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/0247-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch new file mode 100644 index 0000000..855e882 --- /dev/null +++ b/0247-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch @@ -0,0 +1,132 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:49:09 +0530 +Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap + +A corrupt f2fs filesystem could have a block offset or a bitmap +offset that would cause us to read beyond the bounds of the nat +bitmap. + +Introduce the nat_bitmap_size member in grub_f2fs_data which holds +the size of nat bitmap. + +Set the size when loading the nat bitmap in nat_bitmap_ptr(), and +catch when an invalid offset would create a pointer past the end of +the allocated space. + +Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid +reading past the end of the nat bitmap. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e) +--- + grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 63702214b0..8898b235e0 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ + + #define MAX_VOLUME_NAME 512 ++#define MAX_NAT_BITMAP_SIZE 3900 + + enum FILE_TYPE + { +@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint + grub_uint32_t checksum_offset; + grub_uint64_t elapsed_time; + grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; +- grub_uint8_t sit_nat_version_bitmap[3900]; ++ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE]; + grub_uint32_t checksum; + } GRUB_PACKED; + +@@ -302,6 +303,7 @@ struct grub_f2fs_data + + struct grub_f2fs_nat_journal nat_j; + char *nat_bitmap; ++ grub_uint32_t nat_bitmap_size; + + grub_disk_t disk; + struct grub_f2fs_node *inode; +@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type) + } + + static void * +-nat_bitmap_ptr (struct grub_f2fs_data *data) ++nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size) + { + struct grub_f2fs_checkpoint *ckpt = &data->ckpt; + grub_uint32_t offset; ++ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE; + + if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) + return ckpt->sit_nat_version_bitmap; + + offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); ++ if (offset >= MAX_NAT_BITMAP_SIZE) ++ return NULL; ++ ++ *nat_bitmap_size = *nat_bitmap_size - offset; + + return ckpt->sit_nat_version_bitmap + offset; + } +@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len) + } + + static int +-grub_f2fs_test_bit (grub_uint32_t nr, const char *p) ++grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len) + { + int mask; ++ grub_uint32_t shifted_nr = (nr >> 3); + +- p += (nr >> 3); ++ if (shifted_nr >= len) ++ return -1; ++ ++ p += shifted_nr; + mask = 1 << (7 - (nr & 0x07)); + + return mask & *p; +@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + grub_uint32_t seg_off, block_off, entry_off, block_addr; + grub_uint32_t blkaddr = 0; + grub_err_t err; ++ int result_bit; + + err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); + if (err != GRUB_ERR_NONE) +@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + ((seg_off * data->blocks_per_seg) << 1) + + (block_off & (data->blocks_per_seg - 1)); + +- if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) ++ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap, ++ data->nat_bitmap_size); ++ if (result_bit > 0) + block_addr += data->blocks_per_seg; ++ else if (result_bit == -1) ++ { ++ grub_free (nat_block); ++ return 0; ++ } + + err = grub_f2fs_block_read (data, block_addr, nat_block); + if (err) +@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk) + if (err) + goto fail; + +- data->nat_bitmap = nat_bitmap_ptr (data); ++ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size); ++ if (data->nat_bitmap == NULL) ++ goto fail; + + err = get_nat_journal (data); + if (err) diff --git a/0247-net-http-Error-out-on-headers-with-LF-without-CR.patch b/0247-net-http-Error-out-on-headers-with-LF-without-CR.patch deleted file mode 100644 index b73c169..0000000 --- a/0247-net-http-Error-out-on-headers-with-LF-without-CR.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Daniel Axtens -Date: Tue, 8 Mar 2022 19:04:40 +1100 -Subject: [PATCH] net/http: Error out on headers with LF without CR - -In a similar vein to the previous patch, parse_line() would write -a NUL byte past the end of the buffer if there was an HTTP header -with a LF rather than a CRLF. - -RFC-2616 says: - - Many HTTP/1.1 header field values consist of words separated by LWS - or special characters. These special characters MUST be in a quoted - string to be used within a parameter value (as defined in section 3.6). - -We don't support quoted sections or continuation lines, etc. - -If we see an LF that's not part of a CRLF, bail out. - -Fixes: CVE-2022-28734 - -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de) ---- - grub-core/net/http.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/grub-core/net/http.c b/grub-core/net/http.c -index 58546739a2..57d2721719 100644 ---- a/grub-core/net/http.c -+++ b/grub-core/net/http.c -@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) - char *end = ptr + len; - while (end > ptr && *(end - 1) == '\r') - end--; -+ -+ /* LF without CR. */ -+ if (end == ptr + len) -+ { -+ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR")); -+ return GRUB_ERR_NONE; -+ } - *end = 0; -+ - /* Trailing CRLF. */ - if (data->in_chunk_len == 1) - { diff --git a/0248-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/0248-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch new file mode 100644 index 0000000..0553d60 --- /dev/null +++ b/0248-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:17:43 +0530 +Subject: [PATCH] fs/f2fs: Do not copy file names that are too long + +A corrupt f2fs file system might specify a name length which is greater +than the maximum name length supported by the GRUB f2fs driver. + +We will allocate enough memory to store the overly long name, but there +are only F2FS_NAME_LEN bytes in the source, so we would read past the end +of the source. + +While checking directory entries, do not copy a file name with an invalid +length. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a) +--- + grub-core/fs/f2fs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8898b235e0..df6beb544c 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -1003,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) + + ftype = ctx->dentry[i].file_type; + name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len); ++ ++ if (name_len >= F2FS_NAME_LEN) ++ return 0; ++ + filename = grub_malloc (name_len + 1); + if (!filename) + return 0; diff --git a/0248-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/0248-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch deleted file mode 100644 index 79df1c2..0000000 --- a/0248-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sudhakar Kuppusamy -Date: Wed, 6 Apr 2022 18:03:37 +0530 -Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries - -A corrupt f2fs file system could specify a nat journal entry count -that is beyond the maximum NAT_JOURNAL_ENTRIES. - -Check if the specified nat journal entry count before accessing the -array, and throw an error if it is too large. - -Signed-off-by: Sudhakar Kuppusamy -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e) ---- - grub-core/fs/f2fs.c | 21 ++++++++++++++------- - 1 file changed, 14 insertions(+), 7 deletions(-) - -diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c -index 8a9992ca9e..63702214b0 100644 ---- a/grub-core/fs/f2fs.c -+++ b/grub-core/fs/f2fs.c -@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data) - return err; - } - --static grub_uint32_t --get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid) -+static grub_err_t -+get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, -+ grub_uint32_t *blkaddr) - { - grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); -- grub_uint32_t blkaddr = 0; - grub_uint16_t i; - -+ if (n >= NAT_JOURNAL_ENTRIES) -+ return grub_error (GRUB_ERR_BAD_FS, -+ "invalid number of nat journal entries"); -+ - for (i = 0; i < n; i++) - { - if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid) - { -- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); -+ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); - break; - } - } - -- return blkaddr; -+ return GRUB_ERR_NONE; - } - - static grub_uint32_t -@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) - { - struct grub_f2fs_nat_block *nat_block; - grub_uint32_t seg_off, block_off, entry_off, block_addr; -- grub_uint32_t blkaddr; -+ grub_uint32_t blkaddr = 0; - grub_err_t err; - -- blkaddr = get_blkaddr_from_nat_journal (data, nid); -+ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); -+ if (err != GRUB_ERR_NONE) -+ return 0; -+ - if (blkaddr) - return blkaddr; - diff --git a/0249-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/0249-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch new file mode 100644 index 0000000..7ff5821 --- /dev/null +++ b/0249-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 29 Mar 2022 10:49:56 +0000 +Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item + sizing + +According to the btrfs code in Linux, the structure of a directory item +leaf should be of the form: + + |struct btrfs_dir_item|name|data| + +in GRUB the name len and data len are in the grub_btrfs_dir_item +structure's n and m fields respectively. + +The combined size of the structure, name and data should be less than +the allocated memory, a difference to the Linux kernel's struct +btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for +where the name is stored, so we adjust for that too. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0) +[rharwood: we've an extra variable here] +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 07c0ff874b..2fcfb738fe 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2254,6 +2254,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, + grub_uint64_t tree; + grub_uint8_t type; + char *new_path = NULL; ++ grub_size_t est_size = 0; + + if (!data) + return grub_errno; +@@ -2320,6 +2321,18 @@ grub_btrfs_dir (grub_device_t device, const char *path, + break; + } + ++ if (direl == NULL || ++ grub_add (grub_le_to_cpu16 (direl->n), ++ grub_le_to_cpu16 (direl->m), &est_size) || ++ grub_add (est_size, sizeof (*direl), &est_size) || ++ grub_sub (est_size, sizeof (direl->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; +@@ -2330,6 +2343,19 @@ grub_btrfs_dir (grub_device_t device, const char *path, + char c; + struct grub_btrfs_inode inode; + struct grub_dirhook_info info; ++ ++ if (cdirel == NULL || ++ grub_add (grub_le_to_cpu16 (cdirel->n), ++ grub_le_to_cpu16 (cdirel->m), &est_size) || ++ grub_add (est_size, sizeof (*cdirel), &est_size) || ++ grub_sub (est_size, sizeof (cdirel->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, + tree); + grub_memset (&info, 0, sizeof (info)); diff --git a/0249-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/0249-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch deleted file mode 100644 index 855e882..0000000 --- a/0249-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sudhakar Kuppusamy -Date: Wed, 6 Apr 2022 18:49:09 +0530 -Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap - -A corrupt f2fs filesystem could have a block offset or a bitmap -offset that would cause us to read beyond the bounds of the nat -bitmap. - -Introduce the nat_bitmap_size member in grub_f2fs_data which holds -the size of nat bitmap. - -Set the size when loading the nat bitmap in nat_bitmap_ptr(), and -catch when an invalid offset would create a pointer past the end of -the allocated space. - -Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid -reading past the end of the nat bitmap. - -Signed-off-by: Sudhakar Kuppusamy -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e) ---- - grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------ - 1 file changed, 27 insertions(+), 6 deletions(-) - -diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c -index 63702214b0..8898b235e0 100644 ---- a/grub-core/fs/f2fs.c -+++ b/grub-core/fs/f2fs.c -@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); - #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ - - #define MAX_VOLUME_NAME 512 -+#define MAX_NAT_BITMAP_SIZE 3900 - - enum FILE_TYPE - { -@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint - grub_uint32_t checksum_offset; - grub_uint64_t elapsed_time; - grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; -- grub_uint8_t sit_nat_version_bitmap[3900]; -+ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE]; - grub_uint32_t checksum; - } GRUB_PACKED; - -@@ -302,6 +303,7 @@ struct grub_f2fs_data - - struct grub_f2fs_nat_journal nat_j; - char *nat_bitmap; -+ grub_uint32_t nat_bitmap_size; - - grub_disk_t disk; - struct grub_f2fs_node *inode; -@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type) - } - - static void * --nat_bitmap_ptr (struct grub_f2fs_data *data) -+nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size) - { - struct grub_f2fs_checkpoint *ckpt = &data->ckpt; - grub_uint32_t offset; -+ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE; - - if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) - return ckpt->sit_nat_version_bitmap; - - offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); -+ if (offset >= MAX_NAT_BITMAP_SIZE) -+ return NULL; -+ -+ *nat_bitmap_size = *nat_bitmap_size - offset; - - return ckpt->sit_nat_version_bitmap + offset; - } -@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len) - } - - static int --grub_f2fs_test_bit (grub_uint32_t nr, const char *p) -+grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len) - { - int mask; -+ grub_uint32_t shifted_nr = (nr >> 3); - -- p += (nr >> 3); -+ if (shifted_nr >= len) -+ return -1; -+ -+ p += shifted_nr; - mask = 1 << (7 - (nr & 0x07)); - - return mask & *p; -@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) - grub_uint32_t seg_off, block_off, entry_off, block_addr; - grub_uint32_t blkaddr = 0; - grub_err_t err; -+ int result_bit; - - err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); - if (err != GRUB_ERR_NONE) -@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) - ((seg_off * data->blocks_per_seg) << 1) + - (block_off & (data->blocks_per_seg - 1)); - -- if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) -+ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap, -+ data->nat_bitmap_size); -+ if (result_bit > 0) - block_addr += data->blocks_per_seg; -+ else if (result_bit == -1) -+ { -+ grub_free (nat_block); -+ return 0; -+ } - - err = grub_f2fs_block_read (data, block_addr, nat_block); - if (err) -@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk) - if (err) - goto fail; - -- data->nat_bitmap = nat_bitmap_ptr (data); -+ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size); -+ if (data->nat_bitmap == NULL) -+ goto fail; - - err = get_nat_journal (data); - if (err) diff --git a/0250-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/0250-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch new file mode 100644 index 0000000..d638c11 --- /dev/null +++ b/0250-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 29 Mar 2022 15:52:46 +0000 +Subject: [PATCH] fs/btrfs: Fix more ASAN and SEGV issues found with fuzzing + +The fuzzer is generating btrfs file systems that have chunks with +invalid combinations of stripes and substripes for the given RAID +configurations. + +After examining the Linux kernel fs/btrfs/tree-checker.c code, it +appears that sub-stripes should only be applied to RAID10, and in that +case there should only ever be 2 of them. + +Similarly, RAID single should only have 1 stripe, and RAID1/1C3/1C4 +should have 2. 3 or 4 stripes respectively, which is what redundancy +corresponds. + +Some of the chunks ended up with a size of 0, which grub_malloc() still +returned memory for and in turn generated ASAN errors later when +accessed. + +While it would be possible to specifically limit the number of stripes, +a more correct test was on the combination of the chunk item, and the +number of stripes by the size of the chunk stripe structure in +comparison to the size of the chunk itself. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +(cherry picked from commit 3849647b4b98a4419366708fc4b7f339c6f55ec7) +--- + grub-core/fs/btrfs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 2fcfb738fe..0e9b450413 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -941,6 +941,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + ++ if (!chsize) ++ { ++ grub_dprintf ("btrfs", "zero-size chunk\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid zero-size chunk"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -999,6 +1005,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), + nstripes, + NULL); ++ ++ /* For single, there should be exactly 1 stripe. */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != 1) ++ { ++ grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID_SINGLE: nstripes != 1 (%u)", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ } + if (stripe_length == 0) + stripe_length = 512; + stripen = grub_divmod64 (off, stripe_length, &stripe_offset); +@@ -1018,6 +1034,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripen = 0; + stripe_offset = off; + csize = grub_le_to_cpu64 (chunk->size) - off; ++ ++ /* ++ * Redundancy, and substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != redundancy) ++ { ++ grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID1: nstripes != %u (%u)", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ } + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: +@@ -1054,6 +1083,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_offset = low + chunk_stripe_length + * high; + csize = chunk_stripe_length - low; ++ ++ /* ++ * Substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nsubstripes) != 2) ++ { ++ grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ } ++ + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID5: +@@ -1153,6 +1196,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + + for (j = 0; j < 2; j++) + { ++ grub_size_t est_chunk_alloc = 0; ++ + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" +@@ -1165,6 +1210,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n", + addr); + ++ if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe), ++ grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) || ++ grub_add (est_chunk_alloc, ++ sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) || ++ est_chunk_alloc > chunk->size) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/0250-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/0250-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch deleted file mode 100644 index 0553d60..0000000 --- a/0250-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Sudhakar Kuppusamy -Date: Wed, 6 Apr 2022 18:17:43 +0530 -Subject: [PATCH] fs/f2fs: Do not copy file names that are too long - -A corrupt f2fs file system might specify a name length which is greater -than the maximum name length supported by the GRUB f2fs driver. - -We will allocate enough memory to store the overly long name, but there -are only F2FS_NAME_LEN bytes in the source, so we would read past the end -of the source. - -While checking directory entries, do not copy a file name with an invalid -length. - -Signed-off-by: Sudhakar Kuppusamy -Signed-off-by: Daniel Axtens -Reviewed-by: Daniel Kiper -(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a) ---- - grub-core/fs/f2fs.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c -index 8898b235e0..df6beb544c 100644 ---- a/grub-core/fs/f2fs.c -+++ b/grub-core/fs/f2fs.c -@@ -1003,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) - - ftype = ctx->dentry[i].file_type; - name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len); -+ -+ if (name_len >= F2FS_NAME_LEN) -+ return 0; -+ - filename = grub_malloc (name_len + 1); - if (!filename) - return 0; diff --git a/0251-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/0251-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch new file mode 100644 index 0000000..2e5145f --- /dev/null +++ b/0251-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 7 Apr 2022 15:18:12 +0000 +Subject: [PATCH] fs/btrfs: Fix more fuzz issues related to chunks + +The corpus we generating issues in grub_btrfs_read_logical() when +attempting to iterate over nstripes entries in the boot mapping. + +In most cases the reason for the failure was that the number of strips +exceeded the possible space statically allocated in superblock bootmapping +space. Each stripe entry in the bootmapping block consists of +a grub_btrfs_key followed by a grub_btrfs_chunk_stripe. + +Another issue that came up was that while calculating the chunk size, +in an earlier piece of code in that function, depending on the data +provided in the btrfs file system, it would end up calculating a size +that was too small to contain even 1 grub_btrfs_chunk_item, which is +obviously invalid too. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +(cherry picked from commit e00cd76cbadcc897a9cc4087cb2fcb5dbe15e596) +--- + grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 0e9b450413..47325f6ad7 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -947,6 +947,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "got an invalid zero-size chunk"); + } ++ ++ /* ++ * The space being allocated for a chunk should at least be able to ++ * contain one chunk item. ++ */ ++ if (chsize < sizeof (struct grub_btrfs_chunk_item)) ++ { ++ grub_dprintf ("btrfs", "chunk-size too small\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid chunk size"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -1194,6 +1205,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + if (csize > (grub_uint64_t) size) + csize = size; + ++ /* ++ * The space for a chunk stripe is limited to the space provide in the super-block's ++ * bootstrap mapping with an initial btrfs key at the start of each chunk. ++ */ ++ grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) / ++ (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe)); ++ + for (j = 0; j < 2; j++) + { + grub_size_t est_chunk_alloc = 0; +@@ -1220,6 +1238,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + break; + } + ++ if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/0251-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/0251-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch deleted file mode 100644 index 7ff5821..0000000 --- a/0251-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 29 Mar 2022 10:49:56 +0000 -Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item - sizing - -According to the btrfs code in Linux, the structure of a directory item -leaf should be of the form: - - |struct btrfs_dir_item|name|data| - -in GRUB the name len and data len are in the grub_btrfs_dir_item -structure's n and m fields respectively. - -The combined size of the structure, name and data should be less than -the allocated memory, a difference to the Linux kernel's struct -btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for -where the name is stored, so we adjust for that too. - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper -(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0) -[rharwood: we've an extra variable here] -Signed-off-by: Robbie Harwood ---- - grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 07c0ff874b..2fcfb738fe 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -2254,6 +2254,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, - grub_uint64_t tree; - grub_uint8_t type; - char *new_path = NULL; -+ grub_size_t est_size = 0; - - if (!data) - return grub_errno; -@@ -2320,6 +2321,18 @@ grub_btrfs_dir (grub_device_t device, const char *path, - break; - } - -+ if (direl == NULL || -+ grub_add (grub_le_to_cpu16 (direl->n), -+ grub_le_to_cpu16 (direl->m), &est_size) || -+ grub_add (est_size, sizeof (*direl), &est_size) || -+ grub_sub (est_size, sizeof (direl->name), &est_size) || -+ est_size > allocated) -+ { -+ grub_errno = GRUB_ERR_OUT_OF_RANGE; -+ r = -grub_errno; -+ goto out; -+ } -+ - for (cdirel = direl; - (grub_uint8_t *) cdirel - (grub_uint8_t *) direl - < (grub_ssize_t) elemsize; -@@ -2330,6 +2343,19 @@ grub_btrfs_dir (grub_device_t device, const char *path, - char c; - struct grub_btrfs_inode inode; - struct grub_dirhook_info info; -+ -+ if (cdirel == NULL || -+ grub_add (grub_le_to_cpu16 (cdirel->n), -+ grub_le_to_cpu16 (cdirel->m), &est_size) || -+ grub_add (est_size, sizeof (*cdirel), &est_size) || -+ grub_sub (est_size, sizeof (cdirel->name), &est_size) || -+ est_size > allocated) -+ { -+ grub_errno = GRUB_ERR_OUT_OF_RANGE; -+ r = -grub_errno; -+ goto out; -+ } -+ - err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, - tree); - grub_memset (&info, 0, sizeof (info)); diff --git a/0252-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/0252-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch deleted file mode 100644 index d638c11..0000000 --- a/0252-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Tue, 29 Mar 2022 15:52:46 +0000 -Subject: [PATCH] fs/btrfs: Fix more ASAN and SEGV issues found with fuzzing - -The fuzzer is generating btrfs file systems that have chunks with -invalid combinations of stripes and substripes for the given RAID -configurations. - -After examining the Linux kernel fs/btrfs/tree-checker.c code, it -appears that sub-stripes should only be applied to RAID10, and in that -case there should only ever be 2 of them. - -Similarly, RAID single should only have 1 stripe, and RAID1/1C3/1C4 -should have 2. 3 or 4 stripes respectively, which is what redundancy -corresponds. - -Some of the chunks ended up with a size of 0, which grub_malloc() still -returned memory for and in turn generated ASAN errors later when -accessed. - -While it would be possible to specifically limit the number of stripes, -a more correct test was on the combination of the chunk item, and the -number of stripes by the size of the chunk stripe structure in -comparison to the size of the chunk itself. - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper -(cherry picked from commit 3849647b4b98a4419366708fc4b7f339c6f55ec7) ---- - grub-core/fs/btrfs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 55 insertions(+) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 2fcfb738fe..0e9b450413 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -941,6 +941,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - return grub_error (GRUB_ERR_BAD_FS, - "couldn't find the chunk descriptor"); - -+ if (!chsize) -+ { -+ grub_dprintf ("btrfs", "zero-size chunk\n"); -+ return grub_error (GRUB_ERR_BAD_FS, -+ "got an invalid zero-size chunk"); -+ } - chunk = grub_malloc (chsize); - if (!chunk) - return grub_errno; -@@ -999,6 +1005,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), - nstripes, - NULL); -+ -+ /* For single, there should be exactly 1 stripe. */ -+ if (grub_le_to_cpu16 (chunk->nstripes) != 1) -+ { -+ grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n", -+ grub_le_to_cpu16 (chunk->nstripes)); -+ return grub_error (GRUB_ERR_BAD_FS, -+ "invalid RAID_SINGLE: nstripes != 1 (%u)", -+ grub_le_to_cpu16 (chunk->nstripes)); -+ } - if (stripe_length == 0) - stripe_length = 512; - stripen = grub_divmod64 (off, stripe_length, &stripe_offset); -@@ -1018,6 +1034,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - stripen = 0; - stripe_offset = off; - csize = grub_le_to_cpu64 (chunk->size) - off; -+ -+ /* -+ * Redundancy, and substripes only apply to RAID10, and there -+ * should be exactly 2 sub-stripes. -+ */ -+ if (grub_le_to_cpu16 (chunk->nstripes) != redundancy) -+ { -+ grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n", -+ redundancy, grub_le_to_cpu16 (chunk->nstripes)); -+ return grub_error (GRUB_ERR_BAD_FS, -+ "invalid RAID1: nstripes != %u (%u)", -+ redundancy, grub_le_to_cpu16 (chunk->nstripes)); -+ } - break; - } - case GRUB_BTRFS_CHUNK_TYPE_RAID0: -@@ -1054,6 +1083,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - stripe_offset = low + chunk_stripe_length - * high; - csize = chunk_stripe_length - low; -+ -+ /* -+ * Substripes only apply to RAID10, and there -+ * should be exactly 2 sub-stripes. -+ */ -+ if (grub_le_to_cpu16 (chunk->nsubstripes) != 2) -+ { -+ grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)", -+ grub_le_to_cpu16 (chunk->nsubstripes)); -+ return grub_error (GRUB_ERR_BAD_FS, -+ "invalid RAID10: nsubstripes != 2 (%u)", -+ grub_le_to_cpu16 (chunk->nsubstripes)); -+ } -+ - break; - } - case GRUB_BTRFS_CHUNK_TYPE_RAID5: -@@ -1153,6 +1196,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - - for (j = 0; j < 2; j++) - { -+ grub_size_t est_chunk_alloc = 0; -+ - grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T - "+0x%" PRIxGRUB_UINT64_T - " (%d stripes (%d substripes) of %" -@@ -1165,6 +1210,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n", - addr); - -+ if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe), -+ grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) || -+ grub_add (est_chunk_alloc, -+ sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) || -+ est_chunk_alloc > chunk->size) -+ { -+ err = GRUB_ERR_BAD_FS; -+ break; -+ } -+ - if (is_raid56) - { - err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/0252-misc-Make-grub_min-and-grub_max-more-resilient.patch b/0252-misc-Make-grub_min-and-grub_max-more-resilient.patch new file mode 100644 index 0000000..eb2e8fd --- /dev/null +++ b/0252-misc-Make-grub_min-and-grub_max-more-resilient.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 16:06:10 -0400 +Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient. + +grub_min(a,b) and grub_max(a,b) use a relatively naive implementation +which leads to several problems: +- they evaluate their parameters more than once +- the naive way to address this, to declare temporary variables in a + statement-expression, isn't resilient against nested uses, because + MIN(a,MIN(b,c)) results in the temporary variables being declared in + two nested scopes, which may result in a build warning depending on + your build options. + +This patch changes our implementation to use a statement-expression +inside a helper macro, and creates the symbols for the temporary +variables with __COUNTER__ (A GNU C cpp extension) and token pasting to +create uniquely named internal variables. + +Signed-off-by: Peter Jones +--- + grub-core/loader/multiboot_elfxx.c | 4 +--- + include/grub/misc.h | 25 +++++++++++++++++++++++-- + 2 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c +index f2318e0d16..87f6e31aa6 100644 +--- a/grub-core/loader/multiboot_elfxx.c ++++ b/grub-core/loader/multiboot_elfxx.c +@@ -35,9 +35,7 @@ + #endif + + #include +- +-#define CONCAT(a,b) CONCAT_(a, b) +-#define CONCAT_(a,b) a ## b ++#include + + #pragma GCC diagnostic ignored "-Wcast-align" + +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 6c4aa85ac5..cf84aec1db 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -35,6 +35,14 @@ + #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) + #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } + ++#ifndef CONCAT_ ++#define CONCAT_(a, b) a ## b ++#endif ++ ++#ifndef CONCAT ++#define CONCAT(a, b) CONCAT_(a, b) ++#endif ++ + #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) + + void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); +@@ -498,8 +506,21 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + #define grub_boot_time(...) + #endif + +-#define grub_max(a, b) (((a) > (b)) ? (a) : (b)) +-#define grub_min(a, b) (((a) < (b)) ? (a) : (b)) ++#define _grub_min(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++#define grub_min(a, b) _grub_min(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) ++ ++#define _grub_max(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a > _b ? _a : _b; }) ++#define grub_max(a, b) _grub_max(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) + + #define grub_log2ull(n) (GRUB_TYPE_BITS (grub_uint64_t) - __builtin_clzll (n) - 1) + diff --git a/0253-ReiserFS-switch-to-using-grub_min-grub_max.patch b/0253-ReiserFS-switch-to-using-grub_min-grub_max.patch new file mode 100644 index 0000000..0707af3 --- /dev/null +++ b/0253-ReiserFS-switch-to-using-grub_min-grub_max.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 21 Apr 2022 16:31:17 -0400 +Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max() + +This is a minor cleanup patch to remove the bespoke MIN() and MAX() +definitions from the reiserfs driver, and uses grub_min() / grub_max() +instead. + +Signed-off-by: Peter Jones +--- + grub-core/fs/reiserfs.c | 28 +++++++++------------------- + 1 file changed, 9 insertions(+), 19 deletions(-) + +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index af6a226a7f..b8253da7fe 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -42,16 +42,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- +-#define MAX(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a > _b ? _a : _b; }) +- + #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 + #define REISERFS_MAGIC_LEN 12 + #define REISERFS_MAGIC_STRING "ReIsEr" +@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2); + initial_position = off; + current_position = 0; +- final_position = MIN (len + initial_position, node->size); ++ final_position = grub_min (len + initial_position, node->size); + grub_dprintf ("reiserfs", + "Reading from %lld to %lld (%lld instead of requested %ld)\n", + (unsigned long long) initial_position, +@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); + if (initial_position < current_position + item_size) + { +- offset = MAX ((signed) (initial_position - current_position), 0); +- length = (MIN (item_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), 0); ++ length = (grub_min (item_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading direct block %u from %u to %u...\n", +@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); + if (current_position + block_size >= initial_position) + { +- offset = MAX ((signed) (initial_position - current_position), +- 0); +- length = (MIN (block_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), ++ 0); ++ length = (grub_min (block_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading indirect block %u from %u to %u...\n", +@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + switch (found.type) + { + case GRUB_REISERFS_DIRECT: +- read_length = MIN (len, item_size - file->offset); ++ read_length = grub_min (len, item_size - file->offset); + grub_disk_read (found.data->disk, + (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE, + grub_le_to_cpu16 (found.header.item_location) + file->offset, +@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + item_size, (char *) indirect_block_ptr); + if (grub_errno) + goto fail; +- len = MIN (len, file->size - file->offset); ++ len = grub_min (len, file->size - file->offset); + for (indirect_block = file->offset / block_size; + indirect_block < indirect_block_count && read_length < len; + indirect_block++) + { +- read = MIN (block_size, len - read_length); ++ read = grub_min (block_size, len - read_length); + grub_disk_read (found.data->disk, + (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE, + file->offset % block_size, read, diff --git a/0253-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/0253-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch deleted file mode 100644 index 2e5145f..0000000 --- a/0253-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Darren Kenny -Date: Thu, 7 Apr 2022 15:18:12 +0000 -Subject: [PATCH] fs/btrfs: Fix more fuzz issues related to chunks - -The corpus we generating issues in grub_btrfs_read_logical() when -attempting to iterate over nstripes entries in the boot mapping. - -In most cases the reason for the failure was that the number of strips -exceeded the possible space statically allocated in superblock bootmapping -space. Each stripe entry in the bootmapping block consists of -a grub_btrfs_key followed by a grub_btrfs_chunk_stripe. - -Another issue that came up was that while calculating the chunk size, -in an earlier piece of code in that function, depending on the data -provided in the btrfs file system, it would end up calculating a size -that was too small to contain even 1 grub_btrfs_chunk_item, which is -obviously invalid too. - -Signed-off-by: Darren Kenny -Reviewed-by: Daniel Kiper -(cherry picked from commit e00cd76cbadcc897a9cc4087cb2fcb5dbe15e596) ---- - grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c -index 0e9b450413..47325f6ad7 100644 ---- a/grub-core/fs/btrfs.c -+++ b/grub-core/fs/btrfs.c -@@ -947,6 +947,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - return grub_error (GRUB_ERR_BAD_FS, - "got an invalid zero-size chunk"); - } -+ -+ /* -+ * The space being allocated for a chunk should at least be able to -+ * contain one chunk item. -+ */ -+ if (chsize < sizeof (struct grub_btrfs_chunk_item)) -+ { -+ grub_dprintf ("btrfs", "chunk-size too small\n"); -+ return grub_error (GRUB_ERR_BAD_FS, -+ "got an invalid chunk size"); -+ } - chunk = grub_malloc (chsize); - if (!chunk) - return grub_errno; -@@ -1194,6 +1205,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - if (csize > (grub_uint64_t) size) - csize = size; - -+ /* -+ * The space for a chunk stripe is limited to the space provide in the super-block's -+ * bootstrap mapping with an initial btrfs key at the start of each chunk. -+ */ -+ grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) / -+ (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe)); -+ - for (j = 0; j < 2; j++) - { - grub_size_t est_chunk_alloc = 0; -@@ -1220,6 +1238,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, - break; - } - -+ if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes) -+ { -+ err = GRUB_ERR_BAD_FS; -+ break; -+ } -+ - if (is_raid56) - { - err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/0254-misc-Make-grub_min-and-grub_max-more-resilient.patch b/0254-misc-Make-grub_min-and-grub_max-more-resilient.patch deleted file mode 100644 index eb2e8fd..0000000 --- a/0254-misc-Make-grub_min-and-grub_max-more-resilient.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 21 Mar 2022 16:06:10 -0400 -Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient. - -grub_min(a,b) and grub_max(a,b) use a relatively naive implementation -which leads to several problems: -- they evaluate their parameters more than once -- the naive way to address this, to declare temporary variables in a - statement-expression, isn't resilient against nested uses, because - MIN(a,MIN(b,c)) results in the temporary variables being declared in - two nested scopes, which may result in a build warning depending on - your build options. - -This patch changes our implementation to use a statement-expression -inside a helper macro, and creates the symbols for the temporary -variables with __COUNTER__ (A GNU C cpp extension) and token pasting to -create uniquely named internal variables. - -Signed-off-by: Peter Jones ---- - grub-core/loader/multiboot_elfxx.c | 4 +--- - include/grub/misc.h | 25 +++++++++++++++++++++++-- - 2 files changed, 24 insertions(+), 5 deletions(-) - -diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c -index f2318e0d16..87f6e31aa6 100644 ---- a/grub-core/loader/multiboot_elfxx.c -+++ b/grub-core/loader/multiboot_elfxx.c -@@ -35,9 +35,7 @@ - #endif - - #include -- --#define CONCAT(a,b) CONCAT_(a, b) --#define CONCAT_(a,b) a ## b -+#include - - #pragma GCC diagnostic ignored "-Wcast-align" - -diff --git a/include/grub/misc.h b/include/grub/misc.h -index 6c4aa85ac5..cf84aec1db 100644 ---- a/include/grub/misc.h -+++ b/include/grub/misc.h -@@ -35,6 +35,14 @@ - #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) - #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } - -+#ifndef CONCAT_ -+#define CONCAT_(a, b) a ## b -+#endif -+ -+#ifndef CONCAT -+#define CONCAT(a, b) CONCAT_(a, b) -+#endif -+ - #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) - - void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); -@@ -498,8 +506,21 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, - #define grub_boot_time(...) - #endif - --#define grub_max(a, b) (((a) > (b)) ? (a) : (b)) --#define grub_min(a, b) (((a) < (b)) ? (a) : (b)) -+#define _grub_min(a, b, _a, _b) \ -+ ({ typeof (a) _a = (a); \ -+ typeof (b) _b = (b); \ -+ _a < _b ? _a : _b; }) -+#define grub_min(a, b) _grub_min(a, b, \ -+ CONCAT(_a_,__COUNTER__), \ -+ CONCAT(_b_,__COUNTER__)) -+ -+#define _grub_max(a, b, _a, _b) \ -+ ({ typeof (a) _a = (a); \ -+ typeof (b) _b = (b); \ -+ _a > _b ? _a : _b; }) -+#define grub_max(a, b) _grub_max(a, b, \ -+ CONCAT(_a_,__COUNTER__), \ -+ CONCAT(_b_,__COUNTER__)) - - #define grub_log2ull(n) (GRUB_TYPE_BITS (grub_uint64_t) - __builtin_clzll (n) - 1) - diff --git a/0254-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch b/0254-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch new file mode 100644 index 0000000..a7ac6f2 --- /dev/null +++ b/0254-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Mar 2022 14:40:01 -0400 +Subject: [PATCH] misc: make grub_boot_time() also call + grub_dprintf("boot",...) + +Currently grub_boot_time() includes valuable debugging messages, but if +you build without BOOT_TIME_STATS enabled, they are silently and +confusingly compiled away. + +This patch changes grub_boot_time() to also log when "boot" is enabled +in DEBUG, regardless of BOOT_TIME_STATS. + +Signed-off-by: Peter Jones +--- + grub-core/kern/misc.c | 3 ++- + include/grub/misc.h | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index a186ad3dd4..cb45461402 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1334,7 +1334,8 @@ grub_real_boot_time (const char *file, + n->next = 0; + + va_start (args, fmt); +- n->msg = grub_xvasprintf (fmt, args); ++ n->msg = grub_xvasprintf (fmt, args); ++ grub_dprintf ("boot", "%s\n", n->msg); + va_end (args); + + *boot_time_last = n; +diff --git a/include/grub/misc.h b/include/grub/misc.h +index cf84aec1db..faae0ae860 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -503,7 +503,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); + #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__) + #else +-#define grub_boot_time(...) ++#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__) + #endif + + #define _grub_min(a, b, _a, _b) \ diff --git a/0255-ReiserFS-switch-to-using-grub_min-grub_max.patch b/0255-ReiserFS-switch-to-using-grub_min-grub_max.patch deleted file mode 100644 index 0707af3..0000000 --- a/0255-ReiserFS-switch-to-using-grub_min-grub_max.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 21 Apr 2022 16:31:17 -0400 -Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max() - -This is a minor cleanup patch to remove the bespoke MIN() and MAX() -definitions from the reiserfs driver, and uses grub_min() / grub_max() -instead. - -Signed-off-by: Peter Jones ---- - grub-core/fs/reiserfs.c | 28 +++++++++------------------- - 1 file changed, 9 insertions(+), 19 deletions(-) - -diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c -index af6a226a7f..b8253da7fe 100644 ---- a/grub-core/fs/reiserfs.c -+++ b/grub-core/fs/reiserfs.c -@@ -42,16 +42,6 @@ - - GRUB_MOD_LICENSE ("GPLv3+"); - --#define MIN(a, b) \ -- ({ typeof (a) _a = (a); \ -- typeof (b) _b = (b); \ -- _a < _b ? _a : _b; }) -- --#define MAX(a, b) \ -- ({ typeof (a) _a = (a); \ -- typeof (b) _b = (b); \ -- _a > _b ? _a : _b; }) -- - #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 - #define REISERFS_MAGIC_LEN 12 - #define REISERFS_MAGIC_STRING "ReIsEr" -@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, - grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2); - initial_position = off; - current_position = 0; -- final_position = MIN (len + initial_position, node->size); -+ final_position = grub_min (len + initial_position, node->size); - grub_dprintf ("reiserfs", - "Reading from %lld to %lld (%lld instead of requested %ld)\n", - (unsigned long long) initial_position, -@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, - grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); - if (initial_position < current_position + item_size) - { -- offset = MAX ((signed) (initial_position - current_position), 0); -- length = (MIN (item_size, final_position - current_position) -+ offset = grub_max ((signed) (initial_position - current_position), 0); -+ length = (grub_min (item_size, final_position - current_position) - - offset); - grub_dprintf ("reiserfs", - "Reading direct block %u from %u to %u...\n", -@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, - grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); - if (current_position + block_size >= initial_position) - { -- offset = MAX ((signed) (initial_position - current_position), -- 0); -- length = (MIN (block_size, final_position - current_position) -+ offset = grub_max ((signed) (initial_position - current_position), -+ 0); -+ length = (grub_min (block_size, final_position - current_position) - - offset); - grub_dprintf ("reiserfs", - "Reading indirect block %u from %u to %u...\n", -@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, - switch (found.type) - { - case GRUB_REISERFS_DIRECT: -- read_length = MIN (len, item_size - file->offset); -+ read_length = grub_min (len, item_size - file->offset); - grub_disk_read (found.data->disk, - (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE, - grub_le_to_cpu16 (found.header.item_location) + file->offset, -@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, - item_size, (char *) indirect_block_ptr); - if (grub_errno) - goto fail; -- len = MIN (len, file->size - file->offset); -+ len = grub_min (len, file->size - file->offset); - for (indirect_block = file->offset / block_size; - indirect_block < indirect_block_count && read_length < len; - indirect_block++) - { -- read = MIN (block_size, len - read_length); -+ read = grub_min (block_size, len - read_length); - grub_disk_read (found.data->disk, - (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE, - file->offset % block_size, read, diff --git a/0255-modules-make-.module_license-read-only.patch b/0255-modules-make-.module_license-read-only.patch new file mode 100644 index 0000000..ba3b313 --- /dev/null +++ b/0255-modules-make-.module_license-read-only.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Feb 2022 16:32:51 -0500 +Subject: [PATCH] modules: make .module_license read-only + +Currently .module_license is set writable (that is, the section has the +SHF_WRITE flag set) in the module's ELF headers. This probably never +actually matters, but it can't possibly be correct. + +This patch sets that data as "const", which causes that flag not to be +set. + +Signed-off-by: Peter Jones +--- + include/grub/dl.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 20d870f2a4..618ae6f474 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -121,7 +121,7 @@ grub_mod_fini (void) + #define ATTRIBUTE_USED __unused__ + #endif + #define GRUB_MOD_LICENSE(license) \ +- static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; ++ static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; + #define GRUB_MOD_DEP(name) \ + static const char grub_module_depend_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name diff --git a/0256-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch b/0256-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch deleted file mode 100644 index a7ac6f2..0000000 --- a/0256-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 24 Mar 2022 14:40:01 -0400 -Subject: [PATCH] misc: make grub_boot_time() also call - grub_dprintf("boot",...) - -Currently grub_boot_time() includes valuable debugging messages, but if -you build without BOOT_TIME_STATS enabled, they are silently and -confusingly compiled away. - -This patch changes grub_boot_time() to also log when "boot" is enabled -in DEBUG, regardless of BOOT_TIME_STATS. - -Signed-off-by: Peter Jones ---- - grub-core/kern/misc.c | 3 ++- - include/grub/misc.h | 2 +- - 2 files changed, 3 insertions(+), 2 deletions(-) - -diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c -index a186ad3dd4..cb45461402 100644 ---- a/grub-core/kern/misc.c -+++ b/grub-core/kern/misc.c -@@ -1334,7 +1334,8 @@ grub_real_boot_time (const char *file, - n->next = 0; - - va_start (args, fmt); -- n->msg = grub_xvasprintf (fmt, args); -+ n->msg = grub_xvasprintf (fmt, args); -+ grub_dprintf ("boot", "%s\n", n->msg); - va_end (args); - - *boot_time_last = n; -diff --git a/include/grub/misc.h b/include/grub/misc.h -index cf84aec1db..faae0ae860 100644 ---- a/include/grub/misc.h -+++ b/include/grub/misc.h -@@ -503,7 +503,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, - const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); - #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__) - #else --#define grub_boot_time(...) -+#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__) - #endif - - #define _grub_min(a, b, _a, _b) \ diff --git a/0256-modules-strip-.llvm_addrsig-sections-and-similar.patch b/0256-modules-strip-.llvm_addrsig-sections-and-similar.patch new file mode 100644 index 0000000..9f26115 --- /dev/null +++ b/0256-modules-strip-.llvm_addrsig-sections-and-similar.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Feb 2022 16:40:11 -0500 +Subject: [PATCH] modules: strip .llvm_addrsig sections and similar. + +Currently grub modules built with clang or gcc have several sections +which we don't actually need or support. + +We already have a list of section to skip in genmod.sh, and this patch +adds the following sections to that list (as well as a few newlines): + +.note.gnu.property +.llvm* + +Note that the glob there won't work without a new enough linker, but the +failure is just reversion to the status quo, so that's not a big problem. + +Signed-off-by: Peter Jones +--- + grub-core/genmod.sh.in | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in +index 1250589b3f..c2c5280d75 100644 +--- a/grub-core/genmod.sh.in ++++ b/grub-core/genmod.sh.in +@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then + @TARGET_STRIP@ --strip-unneeded \ + -K grub_mod_init -K grub_mod_fini \ + -K _grub_mod_init -K _grub_mod_fini \ +- -R .note.gnu.gold-version -R .note.GNU-stack \ ++ -R .note.GNU-stack \ ++ -R .note.gnu.gold-version \ ++ -R .note.gnu.property \ + -R .gnu.build.attributes \ ++ -R '.llvm*' \ + -R .rel.gnu.build.attributes \ + -R .rela.gnu.build.attributes \ + -R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \ diff --git a/0257-modules-Don-t-allocate-space-for-non-allocable-secti.patch b/0257-modules-Don-t-allocate-space-for-non-allocable-secti.patch new file mode 100644 index 0000000..d07d838 --- /dev/null +++ b/0257-modules-Don-t-allocate-space-for-non-allocable-secti.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 16:56:10 -0400 +Subject: [PATCH] modules: Don't allocate space for non-allocable sections. + +Currently when loading grub modules, we allocate space for all sections, +including those without SHF_ALLOC set. We then copy the sections that +/do/ have SHF_ALLOC set into the allocated memory, leaving some of our +allocation untouched forever. Additionally, on platforms with GOT +fixups and trampolines, we currently compute alignment round-ups for the +sections and sections with sh_size = 0. + +This patch removes the extra space from the allocation computation, and +makes the allocation computation loop skip empty sections as the loading +loop does. + +Signed-off-by: Peter Jones +--- + grub-core/kern/dl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index f304494574..aef8af8aa7 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -289,6 +289,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + i < e->e_shnum; + i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) + { ++ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ + tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; + if (talign < s->sh_addralign) + talign = s->sh_addralign; diff --git a/0257-modules-make-.module_license-read-only.patch b/0257-modules-make-.module_license-read-only.patch deleted file mode 100644 index ba3b313..0000000 --- a/0257-modules-make-.module_license-read-only.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 24 Feb 2022 16:32:51 -0500 -Subject: [PATCH] modules: make .module_license read-only - -Currently .module_license is set writable (that is, the section has the -SHF_WRITE flag set) in the module's ELF headers. This probably never -actually matters, but it can't possibly be correct. - -This patch sets that data as "const", which causes that flag not to be -set. - -Signed-off-by: Peter Jones ---- - include/grub/dl.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/grub/dl.h b/include/grub/dl.h -index 20d870f2a4..618ae6f474 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -121,7 +121,7 @@ grub_mod_fini (void) - #define ATTRIBUTE_USED __unused__ - #endif - #define GRUB_MOD_LICENSE(license) \ -- static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; -+ static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; - #define GRUB_MOD_DEP(name) \ - static const char grub_module_depend_##name[] \ - __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name diff --git a/0258-modules-strip-.llvm_addrsig-sections-and-similar.patch b/0258-modules-strip-.llvm_addrsig-sections-and-similar.patch deleted file mode 100644 index 9f26115..0000000 --- a/0258-modules-strip-.llvm_addrsig-sections-and-similar.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Thu, 24 Feb 2022 16:40:11 -0500 -Subject: [PATCH] modules: strip .llvm_addrsig sections and similar. - -Currently grub modules built with clang or gcc have several sections -which we don't actually need or support. - -We already have a list of section to skip in genmod.sh, and this patch -adds the following sections to that list (as well as a few newlines): - -.note.gnu.property -.llvm* - -Note that the glob there won't work without a new enough linker, but the -failure is just reversion to the status quo, so that's not a big problem. - -Signed-off-by: Peter Jones ---- - grub-core/genmod.sh.in | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in -index 1250589b3f..c2c5280d75 100644 ---- a/grub-core/genmod.sh.in -+++ b/grub-core/genmod.sh.in -@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then - @TARGET_STRIP@ --strip-unneeded \ - -K grub_mod_init -K grub_mod_fini \ - -K _grub_mod_init -K _grub_mod_fini \ -- -R .note.gnu.gold-version -R .note.GNU-stack \ -+ -R .note.GNU-stack \ -+ -R .note.gnu.gold-version \ -+ -R .note.gnu.property \ - -R .gnu.build.attributes \ -+ -R '.llvm*' \ - -R .rel.gnu.build.attributes \ - -R .rela.gnu.build.attributes \ - -R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \ diff --git a/0258-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch b/0258-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch new file mode 100644 index 0000000..ef51214 --- /dev/null +++ b/0258-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 25 Mar 2022 15:40:12 -0400 +Subject: [PATCH] pe: add the DOS header struct and fix some bad naming. + +In order to properly validate a loaded kernel's support for being loaded +without a writable stack or executable, we need to be able to properly +parse arbitrary PE headers. + +Currently, pe32.h is written in such a way that the MS-DOS header that +tells us where to find the PE header in the binary can't be accessed. +Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC". + +This patch adds the structure for the DOS header, renames the DOS magic +define, and adds defines for the actual PE magic. + +Signed-off-by: Peter Jones +--- + grub-core/loader/arm64/linux.c | 2 +- + include/grub/efi/pe32.h | 28 ++++++++++++++++++++++++++-- + 2 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index d2af47c2c0..cc67f43906 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -58,7 +58,7 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) + if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) + return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); + +- if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC) ++ if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); + +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index a43adf2746..2a5e1ee003 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -46,7 +46,30 @@ + + #define GRUB_PE32_MSDOS_STUB_SIZE 0x80 + +-#define GRUB_PE32_MAGIC 0x5a4d ++#define GRUB_DOS_MAGIC 0x5a4d ++ ++struct grub_dos_header ++{ ++ grub_uint16_t magic; ++ grub_uint16_t cblp; ++ grub_uint16_t cp; ++ grub_uint16_t crlc; ++ grub_uint16_t cparhdr; ++ grub_uint16_t minalloc; ++ grub_uint16_t maxalloc; ++ grub_uint16_t ss; ++ grub_uint16_t sp; ++ grub_uint16_t csum; ++ grub_uint16_t ip; ++ grub_uint16_t cs; ++ grub_uint16_t lfarlc; ++ grub_uint16_t ovno; ++ grub_uint16_t res0[4]; ++ grub_uint16_t oemid; ++ grub_uint16_t oeminfo; ++ grub_uint16_t res1[10]; ++ grub_uint32_t lfanew; ++}; + + /* According to the spec, the minimal alignment is 512 bytes... + But some examples (such as EFI drivers in the Intel +@@ -280,7 +303,8 @@ struct grub_pe32_section_table + + + +-#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SIGNATURE "PE\0\0" + + struct grub_pe32_header + { diff --git a/0259-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch b/0259-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch new file mode 100644 index 0000000..c6688cd --- /dev/null +++ b/0259-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 9 Feb 2022 16:08:20 -0500 +Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of + EFI_LOADER_DATA. + +On some of the firmwares with more security mitigations, EFI_LOADER_DATA +doesn't get you executable memory, and we take a fault and reboot when +we enter kernel. + +This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE +rather than EFI_LOADER_DATA. + +Signed-off-by: Peter Jones +[rharwood: use kernel_size] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 9e5c11ac69..92b2fb5091 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -86,7 +86,9 @@ kernel_free(void *addr, grub_efi_uintn_t size) + } + + static void * +-kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) ++kernel_alloc(grub_efi_uintn_t size, ++ grub_efi_memory_type_t memtype, ++ const char * const errmsg) + { + void *addr = 0; + unsigned int i; +@@ -112,7 +114,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, + max_addresses[i].alloc_type, +- GRUB_EFI_LOADER_DATA); ++ memtype); + if (addr) + grub_dprintf ("linux", "Allocated at %p\n", addr); + } +@@ -242,7 +244,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; + grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); +@@ -393,7 +396,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); ++ params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA, ++ "cannot allocate kernel parameters"); + if (!params) + goto fail; + grub_dprintf ("linux", "params = %p\n", params); +@@ -415,7 +419,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); ++ cmdline = kernel_alloc (lh->cmdline_size + 1, ++ GRUB_EFI_RUNTIME_SERVICES_DATA, ++ N_("can't allocate cmdline")); + if (!cmdline) + goto fail; + grub_dprintf ("linux", "cmdline = %p\n", cmdline); +@@ -461,7 +467,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_size = lh->init_size; +- kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); ++ kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, ++ N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) + goto fail; diff --git a/0259-modules-Don-t-allocate-space-for-non-allocable-secti.patch b/0259-modules-Don-t-allocate-space-for-non-allocable-secti.patch deleted file mode 100644 index d07d838..0000000 --- a/0259-modules-Don-t-allocate-space-for-non-allocable-secti.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 21 Mar 2022 16:56:10 -0400 -Subject: [PATCH] modules: Don't allocate space for non-allocable sections. - -Currently when loading grub modules, we allocate space for all sections, -including those without SHF_ALLOC set. We then copy the sections that -/do/ have SHF_ALLOC set into the allocated memory, leaving some of our -allocation untouched forever. Additionally, on platforms with GOT -fixups and trampolines, we currently compute alignment round-ups for the -sections and sections with sh_size = 0. - -This patch removes the extra space from the allocation computation, and -makes the allocation computation loop skip empty sections as the loading -loop does. - -Signed-off-by: Peter Jones ---- - grub-core/kern/dl.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c -index f304494574..aef8af8aa7 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -289,6 +289,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - i < e->e_shnum; - i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) - { -+ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) -+ continue; -+ - tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; - if (talign < s->sh_addralign) - talign = s->sh_addralign; diff --git a/0260-modules-load-module-sections-at-page-aligned-address.patch b/0260-modules-load-module-sections-at-page-aligned-address.patch new file mode 100644 index 0000000..9a5048c --- /dev/null +++ b/0260-modules-load-module-sections-at-page-aligned-address.patch @@ -0,0 +1,378 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 17:45:40 -0400 +Subject: [PATCH] modules: load module sections at page-aligned addresses + +Currently we load module sections at whatever alignment gcc+ld happened +to dump into the ELF section header, which is often pretty useless. For +example, by default time.mod has these sections on a current x86_64 +build: + +$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13 +Section Headers: +[Nr] Name Type Addr Off Size ES Flags Lk Inf Al +[ 0] NULL 0 00000000 00000000 0 0 0 0 +[ 1] .text PROGBITS 0 00000040 0000015e 0 AX 0 0 1 +[ 2] .rela.text RELA 0 00000458 000001e0 24 I 8 1 8 +[ 3] .rodata.str1.1 PROGBITS 0 0000019e 000000a1 1 AMS 0 0 1 +[ 4] .module_license PROGBITS 0 00000240 0000000f 0 A 0 0 8 +[ 5] .data PROGBITS 0 0000024f 00000000 0 WA 0 0 1 +[ 6] .bss NOBITS 0 00000250 00000008 0 WA 0 0 8 +[ 7] .modname PROGBITS 0 00000250 00000005 0 0 0 1 +[ 8] .symtab SYMTAB 0 00000258 00000150 24 9 6 8 +[ 9] .strtab STRTAB 0 000003a8 000000ab 0 0 0 1 +[10] .shstrtab STRTAB 0 00000638 00000059 0 0 0 1 + +With NX protections being page based, loading sections with either a 1 +or 8 *byte* alignment does absolutely nothing to help us out. + +This patch switches most EFI platforms to load module sections at 4kB +page-aligned addresses. To do so, it adds an new per-arch function, +grub_arch_dl_min_alignment(), which returns the alignment needed for +dynamically loaded sections (in bytes). Currently it sets it to 4096 +when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and +1-byte alignment on everything else. + +It then changes the allocation size computation and the loader code in +grub_dl_load_segments() to align the locations and sizes up to these +boundaries, and fills any added padding with zeros. + +All of this happens before relocations are applied, so the relocations +factor that in with no change. + +As an aside, initially Daniel Kiper and I thought that it might be a +better idea to split the modules up into top-level sections as +.text.modules, .rodata.modules, .data.modules, etc., so that their page +permissions would get set by the loader that's loading grub itself. +This turns out to have two significant downsides: 1) either in mkimage +or in grub_dl_relocate_symbols(), you wind up having to dynamically +process the relocations to accommodate the moved module sections, and 2) +you then need to change the permissions on the modules and change them +back while relocating them in grub_dl_relocate_symbols(), which means +that any loader that /does/ honor the section flags but does /not/ +generally support NX with the memory attributes API will cause grub to +fail. + +Signed-off-by: Peter Jones +--- + grub-core/kern/arm/dl.c | 13 +++++++++++++ + grub-core/kern/arm64/dl.c | 13 +++++++++++++ + grub-core/kern/dl.c | 29 +++++++++++++++++++++-------- + grub-core/kern/emu/full.c | 13 +++++++++++++ + grub-core/kern/i386/dl.c | 13 +++++++++++++ + grub-core/kern/ia64/dl.c | 9 +++++++++ + grub-core/kern/mips/dl.c | 8 ++++++++ + grub-core/kern/powerpc/dl.c | 9 +++++++++ + grub-core/kern/riscv/dl.c | 13 +++++++++++++ + grub-core/kern/sparc64/dl.c | 9 +++++++++ + grub-core/kern/x86_64/dl.c | 13 +++++++++++++ + include/grub/dl.h | 2 ++ + docs/grub-dev.texi | 6 +++--- + 13 files changed, 139 insertions(+), 11 deletions(-) + +diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c +index eab9d17ff2..9260737936 100644 +--- a/grub-core/kern/arm/dl.c ++++ b/grub-core/kern/arm/dl.c +@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr) + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c +index 512e5a80b0..0d4a26857f 100644 +--- a/grub-core/kern/arm64/dl.c ++++ b/grub-core/kern/arm64/dl.c +@@ -196,3 +196,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index aef8af8aa7..8c7aacef39 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -277,7 +277,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + unsigned i; + const Elf_Shdr *s; +- grub_size_t tsize = 0, talign = 1; ++ grub_size_t tsize = 0, talign = 1, arch_addralign = 1; + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) + grub_size_t tramp; + grub_size_t got; +@@ -285,16 +285,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + #endif + char *ptr; + ++ arch_addralign = grub_arch_dl_min_alignment (); ++ + for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) + { ++ grub_size_t sh_addralign; ++ grub_size_t sh_size; ++ + if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) + continue; + +- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; +- if (talign < s->sh_addralign) +- talign = s->sh_addralign; ++ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ ++ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size; ++ if (talign < sh_addralign) ++ talign = sh_addralign; + } + + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) +@@ -323,6 +331,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + i < e->e_shnum; + i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + { ++ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ + if (s->sh_flags & SHF_ALLOC) + { + grub_dl_segment_t seg; +@@ -335,17 +346,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + void *addr; + +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign); + addr = ptr; +- ptr += s->sh_size; ++ ptr += sh_size; + + switch (s->sh_type) + { + case SHT_PROGBITS: + grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); ++ grub_memset ((char *)addr + s->sh_size, 0, ++ sh_size - s->sh_size); + break; + case SHT_NOBITS: +- grub_memset (addr, 0, s->sh_size); ++ grub_memset (addr, 0, sh_size); + break; + } + +@@ -354,7 +367,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + else + seg->addr = 0; + +- seg->size = s->sh_size; ++ seg->size = sh_size; + seg->section = i; + seg->next = mod->segment; + mod->segment = seg; +diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c +index e8d63b1f5f..1de1c28eb0 100644 +--- a/grub-core/kern/emu/full.c ++++ b/grub-core/kern/emu/full.c +@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void) + } + #endif + ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c +index 1346da5cc9..d6b4681fc9 100644 +--- a/grub-core/kern/i386/dl.c ++++ b/grub-core/kern/i386/dl.c +@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c +index db59300fea..92d82c5750 100644 +--- a/grub-core/kern/ia64/dl.c ++++ b/grub-core/kern/ia64/dl.c +@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + } + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c +index 5d7d299c74..6d83bd71e9 100644 +--- a/grub-core/kern/mips/dl.c ++++ b/grub-core/kern/mips/dl.c +@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void) + grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0); + } + ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c +index cdd61b305f..5d9ba2e158 100644 +--- a/grub-core/kern/powerpc/dl.c ++++ b/grub-core/kern/powerpc/dl.c +@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c +index f26b12aaa4..aa18f9e990 100644 +--- a/grub-core/kern/riscv/dl.c ++++ b/grub-core/kern/riscv/dl.c +@@ -343,3 +343,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c +index f3d960186b..f054f08241 100644 +--- a/grub-core/kern/sparc64/dl.c ++++ b/grub-core/kern/sparc64/dl.c +@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c +index e5a8bdcf4f..a105dc50ce 100644 +--- a/grub-core/kern/x86_64/dl.c ++++ b/grub-core/kern/x86_64/dl.c +@@ -119,3 +119,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 618ae6f474..f36ed5cb17 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr); + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Shdr *s, grub_dl_segment_t seg); ++grub_size_t ++grub_arch_dl_min_alignment (void); + #endif + + #if defined (_mips) +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 90083772c8..c23ba313dc 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -755,9 +755,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files + (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c). + At this stage you will also need to add dummy dl.c and cache.S with functions + grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and +-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They +-won't be used for now. ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t ++grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void ++*address, grub_size_t len) (cache.S). They won't be used for now. + + You will need to create directory include/$cpu/$platform and a file + include/$cpu/types.h. The later folowing this template: diff --git a/0260-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch b/0260-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch deleted file mode 100644 index ef51214..0000000 --- a/0260-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 25 Mar 2022 15:40:12 -0400 -Subject: [PATCH] pe: add the DOS header struct and fix some bad naming. - -In order to properly validate a loaded kernel's support for being loaded -without a writable stack or executable, we need to be able to properly -parse arbitrary PE headers. - -Currently, pe32.h is written in such a way that the MS-DOS header that -tells us where to find the PE header in the binary can't be accessed. -Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC". - -This patch adds the structure for the DOS header, renames the DOS magic -define, and adds defines for the actual PE magic. - -Signed-off-by: Peter Jones ---- - grub-core/loader/arm64/linux.c | 2 +- - include/grub/efi/pe32.h | 28 ++++++++++++++++++++++++++-- - 2 files changed, 27 insertions(+), 3 deletions(-) - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index d2af47c2c0..cc67f43906 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -58,7 +58,7 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) - if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) - return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); - -- if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC) -+ if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); - -diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h -index a43adf2746..2a5e1ee003 100644 ---- a/include/grub/efi/pe32.h -+++ b/include/grub/efi/pe32.h -@@ -46,7 +46,30 @@ - - #define GRUB_PE32_MSDOS_STUB_SIZE 0x80 - --#define GRUB_PE32_MAGIC 0x5a4d -+#define GRUB_DOS_MAGIC 0x5a4d -+ -+struct grub_dos_header -+{ -+ grub_uint16_t magic; -+ grub_uint16_t cblp; -+ grub_uint16_t cp; -+ grub_uint16_t crlc; -+ grub_uint16_t cparhdr; -+ grub_uint16_t minalloc; -+ grub_uint16_t maxalloc; -+ grub_uint16_t ss; -+ grub_uint16_t sp; -+ grub_uint16_t csum; -+ grub_uint16_t ip; -+ grub_uint16_t cs; -+ grub_uint16_t lfarlc; -+ grub_uint16_t ovno; -+ grub_uint16_t res0[4]; -+ grub_uint16_t oemid; -+ grub_uint16_t oeminfo; -+ grub_uint16_t res1[10]; -+ grub_uint32_t lfanew; -+}; - - /* According to the spec, the minimal alignment is 512 bytes... - But some examples (such as EFI drivers in the Intel -@@ -280,7 +303,8 @@ struct grub_pe32_section_table - - - --#define GRUB_PE32_SIGNATURE_SIZE 4 -+#define GRUB_PE32_SIGNATURE_SIZE 4 -+#define GRUB_PE32_SIGNATURE "PE\0\0" - - struct grub_pe32_header - { diff --git a/0261-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch b/0261-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch deleted file mode 100644 index c6688cd..0000000 --- a/0261-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 9 Feb 2022 16:08:20 -0500 -Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of - EFI_LOADER_DATA. - -On some of the firmwares with more security mitigations, EFI_LOADER_DATA -doesn't get you executable memory, and we take a fault and reboot when -we enter kernel. - -This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE -rather than EFI_LOADER_DATA. - -Signed-off-by: Peter Jones -[rharwood: use kernel_size] -Signed-off-by: Robbie Harwood ---- - grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------ - 1 file changed, 13 insertions(+), 6 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 9e5c11ac69..92b2fb5091 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -86,7 +86,9 @@ kernel_free(void *addr, grub_efi_uintn_t size) - } - - static void * --kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) -+kernel_alloc(grub_efi_uintn_t size, -+ grub_efi_memory_type_t memtype, -+ const char * const errmsg) - { - void *addr = 0; - unsigned int i; -@@ -112,7 +114,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) - prev_max = max; - addr = grub_efi_allocate_pages_real (max, pages, - max_addresses[i].alloc_type, -- GRUB_EFI_LOADER_DATA); -+ memtype); - if (addr) - grub_dprintf ("linux", "Allocated at %p\n", addr); - } -@@ -242,7 +244,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - } - } - -- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); -+ initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA, -+ N_("can't allocate initrd")); - if (initrd_mem == NULL) - goto fail; - grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); -@@ -393,7 +396,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - #endif - -- params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); -+ params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA, -+ "cannot allocate kernel parameters"); - if (!params) - goto fail; - grub_dprintf ("linux", "params = %p\n", params); -@@ -415,7 +419,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_dprintf ("linux", "new lh is at %p\n", lh); - - grub_dprintf ("linux", "setting up cmdline\n"); -- cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); -+ cmdline = kernel_alloc (lh->cmdline_size + 1, -+ GRUB_EFI_RUNTIME_SERVICES_DATA, -+ N_("can't allocate cmdline")); - if (!cmdline) - goto fail; - grub_dprintf ("linux", "cmdline = %p\n", cmdline); -@@ -461,7 +467,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; - max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; - kernel_size = lh->init_size; -- kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); -+ kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, -+ N_("can't allocate kernel")); - restore_addresses(); - if (!kernel_mem) - goto fail; diff --git a/0261-nx-add-memory-attribute-get-set-API.patch b/0261-nx-add-memory-attribute-get-set-API.patch new file mode 100644 index 0000000..91c9d2f --- /dev/null +++ b/0261-nx-add-memory-attribute-get-set-API.patch @@ -0,0 +1,317 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:56:21 -0400 +Subject: [PATCH] nx: add memory attribute get/set API + +For NX, we need to set the page access permission attributes for write +and execute permissions. + +This patch adds two new primitives, grub_set_mem_attrs() and +grub_clear_mem_attrs(), and associated constant definitions, to be used +for that purpose. + +For most platforms, it adds a dummy implementation that returns +GRUB_ERR_NONE. On EFI platforms, it adds a common helper function, +grub_efi_status_to_err(), which translates EFI error codes to grub error +codes, adds headers for the EFI Memory Attribute Protocol (still pending +standardization), and an implementation of the grub nx primitives using +it. + +Signed-off-by: Peter Jones +[rharwood: add pjones's none/nyi fixup] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/efi/efi.c | 36 +++++++++++++ + grub-core/kern/efi/mm.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 25 +++++++++ + include/grub/efi/efi.h | 2 + + include/grub/mm.h | 32 ++++++++++++ + 5 files changed, 226 insertions(+) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 7fcca69c17..4ac2b2754e 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -1096,3 +1096,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1, + + return 0; + } ++ ++grub_err_t ++grub_efi_status_to_err (grub_efi_status_t status) ++{ ++ grub_err_t err; ++ switch (status) ++ { ++ case GRUB_EFI_SUCCESS: ++ err = GRUB_ERR_NONE; ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ default: ++ err = GRUB_ERR_BAD_ARGUMENT; ++ break; ++ case GRUB_EFI_OUT_OF_RESOURCES: ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ break; ++ case GRUB_EFI_DEVICE_ERROR: ++ err = GRUB_ERR_IO; ++ break; ++ case GRUB_EFI_WRITE_PROTECTED: ++ err = GRUB_ERR_WRITE_ERROR; ++ break; ++ case GRUB_EFI_SECURITY_VIOLATION: ++ err = GRUB_ERR_ACCESS_DENIED; ++ break; ++ case GRUB_EFI_NOT_FOUND: ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ break; ++ case GRUB_EFI_ABORTED: ++ err = GRUB_ERR_WAIT; ++ break; ++ } ++ ++ return err; ++} +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index e84961d078..2c33758ed7 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -738,3 +738,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) + return GRUB_ERR_NONE; + } + #endif ++ ++static inline grub_uint64_t ++grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_EFI_MEMORY_RP | ++ GRUB_EFI_MEMORY_RO | ++ GRUB_EFI_MEMORY_XP; ++ ++ if (attrs & GRUB_MEM_ATTR_R) ++ ret &= ~GRUB_EFI_MEMORY_RP; ++ ++ if (attrs & GRUB_MEM_ATTR_W) ++ ret &= ~GRUB_EFI_MEMORY_RO; ++ ++ if (attrs & GRUB_MEM_ATTR_X) ++ ret &= ~GRUB_EFI_MEMORY_XP; ++ ++ return ret; ++} ++ ++static inline grub_uint64_t ++uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ ++ if (attrs & GRUB_EFI_MEMORY_RP) ++ ret &= ~GRUB_MEM_ATTR_R; ++ ++ if (attrs & GRUB_EFI_MEMORY_RO) ++ ret &= ~GRUB_MEM_ATTR_W; ++ ++ if (attrs & GRUB_EFI_MEMORY_XP) ++ ret &= ~GRUB_MEM_ATTR_X; ++ ++ return ret; ++} ++ ++grub_err_t ++grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n", ++ __func__, physaddr, physaddr+size-1, attrs); ++ return 0; ++ } ++ ++ efi_status = efi_call_4(proto->get_memory_attributes, ++ proto, physaddr, size, attrs); ++ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs); ++ ++ return grub_efi_status_to_err (efi_status); ++} ++ ++grub_err_t ++grub_update_mem_attrs (grub_addr_t addr, grub_size_t size, ++ grub_uint64_t set_attrs, grub_uint64_t clear_attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS; ++ grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; ++ grub_err_t err; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NONE; ++ ++ err = grub_get_mem_attrs (addr, size, &before); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &before, err); ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n", ++ __func__, physaddr, physaddr + size - 1, ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ return 0; ++ } ++ ++ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs); ++ grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs); ++ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs); ++ grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); ++ if (uefi_set_attrs) ++ efi_status = efi_call_4(proto->set_memory_attributes, ++ proto, physaddr, size, uefi_set_attrs); ++ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs) ++ efi_status = efi_call_4(proto->clear_memory_attributes, ++ proto, physaddr, size, uefi_clear_attrs); ++ ++ err = grub_get_mem_attrs (addr, size, &after); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &after, err); ++ ++ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ addr, addr + size - 1, ++ (before & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (before & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (before & GRUB_MEM_ATTR_X) ? 'x' : '-', ++ (after & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (after & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (after & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ ++ return grub_efi_status_to_err (efi_status); ++} +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index f431f49973..464842ba37 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -363,6 +363,11 @@ + { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ + } + ++#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \ ++ { 0xf4560cf6, 0x40ec, 0x4b4a, \ ++ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +@@ -2102,6 +2107,26 @@ struct grub_efi_ip6_config_manual_address { + }; + typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; + ++struct grub_efi_memory_attribute_protocol ++{ ++ grub_efi_status_t (*get_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t *attributes); ++ grub_efi_status_t (*set_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++ grub_efi_status_t (*clear_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++}; ++typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index ec52083c49..34825c4adc 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -164,4 +164,6 @@ struct grub_net_card; + grub_efi_handle_t + grub_efinet_get_device_handle (struct grub_net_card *card); + ++grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status); ++ + #endif /* ! GRUB_EFI_EFI_HEADER */ +diff --git a/include/grub/mm.h b/include/grub/mm.h +index 9c38dd3ca5..d81623d226 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -22,6 +22,7 @@ + + #include + #include ++#include + #include + + #ifndef NULL +@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); + void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); + #endif + ++#define GRUB_MEM_ATTR_R 0x0000000000000004LLU ++#define GRUB_MEM_ATTR_W 0x0000000000000002LLU ++#define GRUB_MEM_ATTR_X 0x0000000000000001LLU ++ ++#ifdef GRUB_MACHINE_EFI ++grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t *attrs); ++grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t set_attrs, ++ grub_uint64_t clear_attrs); ++#else /* !GRUB_MACHINE_EFI */ ++static inline grub_err_t ++grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t *attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++ ++static inline grub_err_t ++grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t set_attrs __attribute__((__unused__)), ++ grub_uint64_t clear_attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++#endif /* GRUB_MACHINE_EFI */ ++ + void grub_mm_check_real (const char *file, int line); + #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); + diff --git a/0262-modules-load-module-sections-at-page-aligned-address.patch b/0262-modules-load-module-sections-at-page-aligned-address.patch deleted file mode 100644 index 9a5048c..0000000 --- a/0262-modules-load-module-sections-at-page-aligned-address.patch +++ /dev/null @@ -1,378 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 21 Mar 2022 17:45:40 -0400 -Subject: [PATCH] modules: load module sections at page-aligned addresses - -Currently we load module sections at whatever alignment gcc+ld happened -to dump into the ELF section header, which is often pretty useless. For -example, by default time.mod has these sections on a current x86_64 -build: - -$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13 -Section Headers: -[Nr] Name Type Addr Off Size ES Flags Lk Inf Al -[ 0] NULL 0 00000000 00000000 0 0 0 0 -[ 1] .text PROGBITS 0 00000040 0000015e 0 AX 0 0 1 -[ 2] .rela.text RELA 0 00000458 000001e0 24 I 8 1 8 -[ 3] .rodata.str1.1 PROGBITS 0 0000019e 000000a1 1 AMS 0 0 1 -[ 4] .module_license PROGBITS 0 00000240 0000000f 0 A 0 0 8 -[ 5] .data PROGBITS 0 0000024f 00000000 0 WA 0 0 1 -[ 6] .bss NOBITS 0 00000250 00000008 0 WA 0 0 8 -[ 7] .modname PROGBITS 0 00000250 00000005 0 0 0 1 -[ 8] .symtab SYMTAB 0 00000258 00000150 24 9 6 8 -[ 9] .strtab STRTAB 0 000003a8 000000ab 0 0 0 1 -[10] .shstrtab STRTAB 0 00000638 00000059 0 0 0 1 - -With NX protections being page based, loading sections with either a 1 -or 8 *byte* alignment does absolutely nothing to help us out. - -This patch switches most EFI platforms to load module sections at 4kB -page-aligned addresses. To do so, it adds an new per-arch function, -grub_arch_dl_min_alignment(), which returns the alignment needed for -dynamically loaded sections (in bytes). Currently it sets it to 4096 -when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and -1-byte alignment on everything else. - -It then changes the allocation size computation and the loader code in -grub_dl_load_segments() to align the locations and sizes up to these -boundaries, and fills any added padding with zeros. - -All of this happens before relocations are applied, so the relocations -factor that in with no change. - -As an aside, initially Daniel Kiper and I thought that it might be a -better idea to split the modules up into top-level sections as -.text.modules, .rodata.modules, .data.modules, etc., so that their page -permissions would get set by the loader that's loading grub itself. -This turns out to have two significant downsides: 1) either in mkimage -or in grub_dl_relocate_symbols(), you wind up having to dynamically -process the relocations to accommodate the moved module sections, and 2) -you then need to change the permissions on the modules and change them -back while relocating them in grub_dl_relocate_symbols(), which means -that any loader that /does/ honor the section flags but does /not/ -generally support NX with the memory attributes API will cause grub to -fail. - -Signed-off-by: Peter Jones ---- - grub-core/kern/arm/dl.c | 13 +++++++++++++ - grub-core/kern/arm64/dl.c | 13 +++++++++++++ - grub-core/kern/dl.c | 29 +++++++++++++++++++++-------- - grub-core/kern/emu/full.c | 13 +++++++++++++ - grub-core/kern/i386/dl.c | 13 +++++++++++++ - grub-core/kern/ia64/dl.c | 9 +++++++++ - grub-core/kern/mips/dl.c | 8 ++++++++ - grub-core/kern/powerpc/dl.c | 9 +++++++++ - grub-core/kern/riscv/dl.c | 13 +++++++++++++ - grub-core/kern/sparc64/dl.c | 9 +++++++++ - grub-core/kern/x86_64/dl.c | 13 +++++++++++++ - include/grub/dl.h | 2 ++ - docs/grub-dev.texi | 6 +++--- - 13 files changed, 139 insertions(+), 11 deletions(-) - -diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c -index eab9d17ff2..9260737936 100644 ---- a/grub-core/kern/arm/dl.c -+++ b/grub-core/kern/arm/dl.c -@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr) - - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+#ifdef GRUB_MACHINE_EFI -+ return 4096; -+#else -+ return 1; -+#endif -+} -diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c -index 512e5a80b0..0d4a26857f 100644 ---- a/grub-core/kern/arm64/dl.c -+++ b/grub-core/kern/arm64/dl.c -@@ -196,3 +196,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+#ifdef GRUB_MACHINE_EFI -+ return 4096; -+#else -+ return 1; -+#endif -+} -diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c -index aef8af8aa7..8c7aacef39 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -277,7 +277,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - { - unsigned i; - const Elf_Shdr *s; -- grub_size_t tsize = 0, talign = 1; -+ grub_size_t tsize = 0, talign = 1, arch_addralign = 1; - #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) - grub_size_t tramp; - grub_size_t got; -@@ -285,16 +285,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - #endif - char *ptr; - -+ arch_addralign = grub_arch_dl_min_alignment (); -+ - for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); - i < e->e_shnum; - i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) - { -+ grub_size_t sh_addralign; -+ grub_size_t sh_size; -+ - if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) - continue; - -- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; -- if (talign < s->sh_addralign) -- talign = s->sh_addralign; -+ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); -+ sh_size = ALIGN_UP(s->sh_size, sh_addralign); -+ -+ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size; -+ if (talign < sh_addralign) -+ talign = sh_addralign; - } - - #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) -@@ -323,6 +331,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - i < e->e_shnum; - i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) - { -+ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); -+ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign); -+ - if (s->sh_flags & SHF_ALLOC) - { - grub_dl_segment_t seg; -@@ -335,17 +346,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - { - void *addr; - -- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign); -+ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign); - addr = ptr; -- ptr += s->sh_size; -+ ptr += sh_size; - - switch (s->sh_type) - { - case SHT_PROGBITS: - grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); -+ grub_memset ((char *)addr + s->sh_size, 0, -+ sh_size - s->sh_size); - break; - case SHT_NOBITS: -- grub_memset (addr, 0, s->sh_size); -+ grub_memset (addr, 0, sh_size); - break; - } - -@@ -354,7 +367,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - else - seg->addr = 0; - -- seg->size = s->sh_size; -+ seg->size = sh_size; - seg->section = i; - seg->next = mod->segment; - mod->segment = seg; -diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c -index e8d63b1f5f..1de1c28eb0 100644 ---- a/grub-core/kern/emu/full.c -+++ b/grub-core/kern/emu/full.c -@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void) - } - #endif - -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+#ifdef GRUB_MACHINE_EFI -+ return 4096; -+#else -+ return 1; -+#endif -+} -diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c -index 1346da5cc9..d6b4681fc9 100644 ---- a/grub-core/kern/i386/dl.c -+++ b/grub-core/kern/i386/dl.c -@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+#ifdef GRUB_MACHINE_EFI -+ return 4096; -+#else -+ return 1; -+#endif -+} -diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c -index db59300fea..92d82c5750 100644 ---- a/grub-core/kern/ia64/dl.c -+++ b/grub-core/kern/ia64/dl.c -@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - } - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+ return 1; -+} -diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c -index 5d7d299c74..6d83bd71e9 100644 ---- a/grub-core/kern/mips/dl.c -+++ b/grub-core/kern/mips/dl.c -@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void) - grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0); - } - -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+ return 1; -+} -diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c -index cdd61b305f..5d9ba2e158 100644 ---- a/grub-core/kern/powerpc/dl.c -+++ b/grub-core/kern/powerpc/dl.c -@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+ return 1; -+} -diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c -index f26b12aaa4..aa18f9e990 100644 ---- a/grub-core/kern/riscv/dl.c -+++ b/grub-core/kern/riscv/dl.c -@@ -343,3 +343,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+#ifdef GRUB_MACHINE_EFI -+ return 4096; -+#else -+ return 1; -+#endif -+} -diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c -index f3d960186b..f054f08241 100644 ---- a/grub-core/kern/sparc64/dl.c -+++ b/grub-core/kern/sparc64/dl.c -@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+ return 1; -+} -diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c -index e5a8bdcf4f..a105dc50ce 100644 ---- a/grub-core/kern/x86_64/dl.c -+++ b/grub-core/kern/x86_64/dl.c -@@ -119,3 +119,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - - return GRUB_ERR_NONE; - } -+ -+/* -+ * Tell the loader what our minimum section alignment is. -+ */ -+grub_size_t -+grub_arch_dl_min_alignment (void) -+{ -+#ifdef GRUB_MACHINE_EFI -+ return 4096; -+#else -+ return 1; -+#endif -+} -diff --git a/include/grub/dl.h b/include/grub/dl.h -index 618ae6f474..f36ed5cb17 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr); - grub_err_t - grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, - Elf_Shdr *s, grub_dl_segment_t seg); -+grub_size_t -+grub_arch_dl_min_alignment (void); - #endif - - #if defined (_mips) -diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi -index 90083772c8..c23ba313dc 100644 ---- a/docs/grub-dev.texi -+++ b/docs/grub-dev.texi -@@ -755,9 +755,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files - (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c). - At this stage you will also need to add dummy dl.c and cache.S with functions - grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t --grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and --void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They --won't be used for now. -+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t -+grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void -+*address, grub_size_t len) (cache.S). They won't be used for now. - - You will need to create directory include/$cpu/$platform and a file - include/$cpu/types.h. The later folowing this template: diff --git a/0262-nx-set-page-permissions-for-loaded-modules.patch b/0262-nx-set-page-permissions-for-loaded-modules.patch new file mode 100644 index 0000000..9e0aebb --- /dev/null +++ b/0262-nx-set-page-permissions-for-loaded-modules.patch @@ -0,0 +1,263 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 17:46:35 -0400 +Subject: [PATCH] nx: set page permissions for loaded modules. + +For NX, we need to set write and executable permissions on the sections +of grub modules when we load them. + +On sections with SHF_ALLOC set, which is typically everything except +.modname and the symbol and string tables, this patch clears the Read +Only flag on sections that have the ELF flag SHF_WRITE set, and clears +the No eXecute flag on sections with SHF_EXECINSTR set. In all other +cases it sets both flags. + +Signed-off-by: Peter Jones +[rharwood: arm tgptr -> tgaddr] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++------------- + include/grub/dl.h | 44 +++++++++++++++++++ + 2 files changed, 134 insertions(+), 30 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 8c7aacef39..d5de80186f 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -285,6 +285,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + #endif + char *ptr; + ++ grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name); ++ + arch_addralign = grub_arch_dl_min_alignment (); + + for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); +@@ -384,6 +386,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + ptr += got; + #endif + ++ grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name); + return GRUB_ERR_NONE; + } + +@@ -517,23 +520,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name) + return s; + return NULL; + } +-static long +-grub_dl_find_section_index (Elf_Ehdr *e, const char *name) +-{ +- Elf_Shdr *s; +- const char *str; +- unsigned i; +- +- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); +- str = (char *) e + s->sh_offset; +- +- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); +- i < e->e_shnum; +- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +- if (grub_strcmp (str + s->sh_name, name) == 0) +- return (long)i; +- return -1; +-} + + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. +@@ -662,6 +648,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + Elf_Shdr *s; + unsigned i; + ++ grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name); + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +@@ -670,24 +657,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + grub_dl_segment_t seg; + grub_err_t err; + +- /* Find the target segment. */ +- for (seg = mod->segment; seg; seg = seg->next) +- if (seg->section == s->sh_info) +- break; ++ seg = grub_dl_find_segment(mod, s->sh_info); ++ if (!seg) ++ continue; + +- if (seg) +- { +- if (!mod->symtab) +- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); ++ if (!mod->symtab) ++ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); + +- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); +- if (err) +- return err; +- } ++ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); ++ if (err) ++ return err; + } + ++ grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name); + return GRUB_ERR_NONE; + } ++ ++static grub_err_t ++grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) ++{ ++ unsigned i; ++ const Elf_Shdr *s; ++ const Elf_Ehdr *e = ehdr; ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ grub_size_t arch_addralign = grub_arch_dl_min_alignment (); ++ grub_addr_t tgaddr; ++ grub_uint64_t tgsz; ++#endif ++ ++ grub_dprintf ("modules", "updating memory attributes for \"%s\"\n", ++ mod->name); ++ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) ++ { ++ grub_dl_segment_t seg; ++ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R; ++ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X; ++ ++ seg = grub_dl_find_segment(mod, i); ++ if (!seg) ++ continue; ++ ++ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ ++ if (s->sh_flags & SHF_WRITE) ++ { ++ set_attrs |= GRUB_MEM_ATTR_W; ++ clear_attrs &= ~GRUB_MEM_ATTR_W; ++ } ++ ++ if (s->sh_flags & SHF_EXECINSTR) ++ { ++ set_attrs |= GRUB_MEM_ATTR_X; ++ clear_attrs &= ~GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n", ++ grub_dl_get_section_name(e, s), ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs); ++ } ++ ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got); ++ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr; ++ ++ if (tgsz) ++ { ++ tgsz = ALIGN_UP(tgsz, arch_addralign); ++ ++ grub_dprintf ("modules", "updating attributes for GOT and trampolines\n", ++ mod->name); ++ grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X, ++ GRUB_MEM_ATTR_W); ++ } ++#endif ++ ++ grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n", ++ mod->name); ++ ++ return GRUB_ERR_NONE; ++} ++ + static void + grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) + { +@@ -753,6 +811,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + mod->ref_count = 1; + + grub_dprintf ("modules", "relocating to %p\n", mod); ++ + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally +@@ -766,7 +825,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + || grub_dl_resolve_dependencies (mod, e) + || grub_dl_load_segments (mod, e) + || grub_dl_resolve_symbols (mod, e) +- || grub_dl_relocate_symbols (mod, e)) ++ || grub_dl_relocate_symbols (mod, e) ++ || grub_dl_set_mem_attrs (mod, e)) + { + mod->fini = 0; + grub_dl_unload (mod); +diff --git a/include/grub/dl.h b/include/grub/dl.h +index f36ed5cb17..45ac8e339f 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #endif + + /* +@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod) + return mod->persistent; + } + ++static inline const char * ++grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s) ++{ ++ Elf_Shdr *str_s; ++ const char *str; ++ ++ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + str_s->sh_offset; ++ ++ return str + s->sh_name; ++} ++ ++static inline long ++grub_dl_find_section_index (Elf_Ehdr *e, const char *name) ++{ ++ Elf_Shdr *s; ++ const char *str; ++ unsigned i; ++ ++ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + s->sh_offset; ++ ++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) ++ if (grub_strcmp (str + s->sh_name, name) == 0) ++ return (long)i; ++ return -1; ++} ++ ++/* Return the segment for a section of index N */ ++static inline grub_dl_segment_t ++grub_dl_find_segment (grub_dl_t mod, unsigned n) ++{ ++ grub_dl_segment_t seg; ++ ++ for (seg = mod->segment; seg; seg = seg->next) ++ if (seg->section == n) ++ return seg; ++ ++ return NULL; ++} ++ + #endif + + void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); diff --git a/0263-nx-add-memory-attribute-get-set-API.patch b/0263-nx-add-memory-attribute-get-set-API.patch deleted file mode 100644 index 91c9d2f..0000000 --- a/0263-nx-add-memory-attribute-get-set-API.patch +++ /dev/null @@ -1,317 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 22 Mar 2022 10:56:21 -0400 -Subject: [PATCH] nx: add memory attribute get/set API - -For NX, we need to set the page access permission attributes for write -and execute permissions. - -This patch adds two new primitives, grub_set_mem_attrs() and -grub_clear_mem_attrs(), and associated constant definitions, to be used -for that purpose. - -For most platforms, it adds a dummy implementation that returns -GRUB_ERR_NONE. On EFI platforms, it adds a common helper function, -grub_efi_status_to_err(), which translates EFI error codes to grub error -codes, adds headers for the EFI Memory Attribute Protocol (still pending -standardization), and an implementation of the grub nx primitives using -it. - -Signed-off-by: Peter Jones -[rharwood: add pjones's none/nyi fixup] -Signed-off-by: Robbie Harwood ---- - grub-core/kern/efi/efi.c | 36 +++++++++++++ - grub-core/kern/efi/mm.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++ - include/grub/efi/api.h | 25 +++++++++ - include/grub/efi/efi.h | 2 + - include/grub/mm.h | 32 ++++++++++++ - 5 files changed, 226 insertions(+) - -diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c -index 7fcca69c17..4ac2b2754e 100644 ---- a/grub-core/kern/efi/efi.c -+++ b/grub-core/kern/efi/efi.c -@@ -1096,3 +1096,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1, - - return 0; - } -+ -+grub_err_t -+grub_efi_status_to_err (grub_efi_status_t status) -+{ -+ grub_err_t err; -+ switch (status) -+ { -+ case GRUB_EFI_SUCCESS: -+ err = GRUB_ERR_NONE; -+ break; -+ case GRUB_EFI_INVALID_PARAMETER: -+ default: -+ err = GRUB_ERR_BAD_ARGUMENT; -+ break; -+ case GRUB_EFI_OUT_OF_RESOURCES: -+ err = GRUB_ERR_OUT_OF_MEMORY; -+ break; -+ case GRUB_EFI_DEVICE_ERROR: -+ err = GRUB_ERR_IO; -+ break; -+ case GRUB_EFI_WRITE_PROTECTED: -+ err = GRUB_ERR_WRITE_ERROR; -+ break; -+ case GRUB_EFI_SECURITY_VIOLATION: -+ err = GRUB_ERR_ACCESS_DENIED; -+ break; -+ case GRUB_EFI_NOT_FOUND: -+ err = GRUB_ERR_FILE_NOT_FOUND; -+ break; -+ case GRUB_EFI_ABORTED: -+ err = GRUB_ERR_WAIT; -+ break; -+ } -+ -+ return err; -+} -diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c -index e84961d078..2c33758ed7 100644 ---- a/grub-core/kern/efi/mm.c -+++ b/grub-core/kern/efi/mm.c -@@ -738,3 +738,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) - return GRUB_ERR_NONE; - } - #endif -+ -+static inline grub_uint64_t -+grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs) -+{ -+ grub_uint64_t ret = GRUB_EFI_MEMORY_RP | -+ GRUB_EFI_MEMORY_RO | -+ GRUB_EFI_MEMORY_XP; -+ -+ if (attrs & GRUB_MEM_ATTR_R) -+ ret &= ~GRUB_EFI_MEMORY_RP; -+ -+ if (attrs & GRUB_MEM_ATTR_W) -+ ret &= ~GRUB_EFI_MEMORY_RO; -+ -+ if (attrs & GRUB_MEM_ATTR_X) -+ ret &= ~GRUB_EFI_MEMORY_XP; -+ -+ return ret; -+} -+ -+static inline grub_uint64_t -+uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs) -+{ -+ grub_uint64_t ret = GRUB_MEM_ATTR_R | -+ GRUB_MEM_ATTR_W | -+ GRUB_MEM_ATTR_X; -+ -+ if (attrs & GRUB_EFI_MEMORY_RP) -+ ret &= ~GRUB_MEM_ATTR_R; -+ -+ if (attrs & GRUB_EFI_MEMORY_RO) -+ ret &= ~GRUB_MEM_ATTR_W; -+ -+ if (attrs & GRUB_EFI_MEMORY_XP) -+ ret &= ~GRUB_MEM_ATTR_X; -+ -+ return ret; -+} -+ -+grub_err_t -+grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs) -+{ -+ grub_efi_memory_attribute_protocol_t *proto; -+ grub_efi_physical_address_t physaddr = addr; -+ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; -+ grub_efi_status_t efi_status; -+ -+ proto = grub_efi_locate_protocol (&protocol_guid, 0); -+ if (!proto) -+ return GRUB_ERR_NOT_IMPLEMENTED_YET; -+ -+ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) -+ { -+ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n", -+ __func__, physaddr, physaddr+size-1, attrs); -+ return 0; -+ } -+ -+ efi_status = efi_call_4(proto->get_memory_attributes, -+ proto, physaddr, size, attrs); -+ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs); -+ -+ return grub_efi_status_to_err (efi_status); -+} -+ -+grub_err_t -+grub_update_mem_attrs (grub_addr_t addr, grub_size_t size, -+ grub_uint64_t set_attrs, grub_uint64_t clear_attrs) -+{ -+ grub_efi_memory_attribute_protocol_t *proto; -+ grub_efi_physical_address_t physaddr = addr; -+ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; -+ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS; -+ grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; -+ grub_err_t err; -+ -+ proto = grub_efi_locate_protocol (&protocol_guid, 0); -+ if (!proto) -+ return GRUB_ERR_NONE; -+ -+ err = grub_get_mem_attrs (addr, size, &before); -+ if (err) -+ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", -+ addr, size, &before, err); -+ -+ if (physaddr & 0xfff || size & 0xfff || size == 0) -+ { -+ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n", -+ __func__, physaddr, physaddr + size - 1, -+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", -+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", -+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", -+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", -+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", -+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); -+ return 0; -+ } -+ -+ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs); -+ grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs); -+ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs); -+ grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); -+ if (uefi_set_attrs) -+ efi_status = efi_call_4(proto->set_memory_attributes, -+ proto, physaddr, size, uefi_set_attrs); -+ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs) -+ efi_status = efi_call_4(proto->clear_memory_attributes, -+ proto, physaddr, size, uefi_clear_attrs); -+ -+ err = grub_get_mem_attrs (addr, size, &after); -+ if (err) -+ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", -+ addr, size, &after, err); -+ -+ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n", -+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", -+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", -+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", -+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", -+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", -+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", -+ addr, addr + size - 1, -+ (before & GRUB_MEM_ATTR_R) ? 'r' : '-', -+ (before & GRUB_MEM_ATTR_W) ? 'w' : '-', -+ (before & GRUB_MEM_ATTR_X) ? 'x' : '-', -+ (after & GRUB_MEM_ATTR_R) ? 'r' : '-', -+ (after & GRUB_MEM_ATTR_W) ? 'w' : '-', -+ (after & GRUB_MEM_ATTR_X) ? 'x' : '-'); -+ -+ return grub_efi_status_to_err (efi_status); -+} -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index f431f49973..464842ba37 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -363,6 +363,11 @@ - { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ - } - -+#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \ -+ { 0xf4560cf6, 0x40ec, 0x4b4a, \ -+ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \ -+ } -+ - struct grub_efi_sal_system_table - { - grub_uint32_t signature; -@@ -2102,6 +2107,26 @@ struct grub_efi_ip6_config_manual_address { - }; - typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; - -+struct grub_efi_memory_attribute_protocol -+{ -+ grub_efi_status_t (*get_memory_attributes) ( -+ struct grub_efi_memory_attribute_protocol *this, -+ grub_efi_physical_address_t base_address, -+ grub_efi_uint64_t length, -+ grub_efi_uint64_t *attributes); -+ grub_efi_status_t (*set_memory_attributes) ( -+ struct grub_efi_memory_attribute_protocol *this, -+ grub_efi_physical_address_t base_address, -+ grub_efi_uint64_t length, -+ grub_efi_uint64_t attributes); -+ grub_efi_status_t (*clear_memory_attributes) ( -+ struct grub_efi_memory_attribute_protocol *this, -+ grub_efi_physical_address_t base_address, -+ grub_efi_uint64_t length, -+ grub_efi_uint64_t attributes); -+}; -+typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t; -+ - #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ - || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ - || defined(__riscv) -diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h -index ec52083c49..34825c4adc 100644 ---- a/include/grub/efi/efi.h -+++ b/include/grub/efi/efi.h -@@ -164,4 +164,6 @@ struct grub_net_card; - grub_efi_handle_t - grub_efinet_get_device_handle (struct grub_net_card *card); - -+grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status); -+ - #endif /* ! GRUB_EFI_EFI_HEADER */ -diff --git a/include/grub/mm.h b/include/grub/mm.h -index 9c38dd3ca5..d81623d226 100644 ---- a/include/grub/mm.h -+++ b/include/grub/mm.h -@@ -22,6 +22,7 @@ - - #include - #include -+#include - #include - - #ifndef NULL -@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); - void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); - #endif - -+#define GRUB_MEM_ATTR_R 0x0000000000000004LLU -+#define GRUB_MEM_ATTR_W 0x0000000000000002LLU -+#define GRUB_MEM_ATTR_X 0x0000000000000001LLU -+ -+#ifdef GRUB_MACHINE_EFI -+grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr, -+ grub_size_t size, -+ grub_uint64_t *attrs); -+grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr, -+ grub_size_t size, -+ grub_uint64_t set_attrs, -+ grub_uint64_t clear_attrs); -+#else /* !GRUB_MACHINE_EFI */ -+static inline grub_err_t -+grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)), -+ grub_size_t size __attribute__((__unused__)), -+ grub_uint64_t *attrs __attribute__((__unused__))) -+{ -+ return GRUB_ERR_NONE; -+} -+ -+static inline grub_err_t -+grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)), -+ grub_size_t size __attribute__((__unused__)), -+ grub_uint64_t set_attrs __attribute__((__unused__)), -+ grub_uint64_t clear_attrs __attribute__((__unused__))) -+{ -+ return GRUB_ERR_NONE; -+} -+#endif /* GRUB_MACHINE_EFI */ -+ - void grub_mm_check_real (const char *file, int line); - #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); - diff --git a/0263-nx-set-attrs-in-our-kernel-loaders.patch b/0263-nx-set-attrs-in-our-kernel-loaders.patch new file mode 100644 index 0000000..514df1f --- /dev/null +++ b/0263-nx-set-attrs-in-our-kernel-loaders.patch @@ -0,0 +1,565 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:57:07 -0400 +Subject: [PATCH] nx: set attrs in our kernel loaders + +For NX, our kernel loaders need to set write and execute page +permissions on allocated pages and the stack. + +This patch adds those calls. + +Signed-off-by: Peter Jones +[rharwood: fix stack_attrs undefined, fix aarch64 callsites] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/efi/mm.c | 77 +++++++++++++++++ + grub-core/loader/arm64/linux.c | 16 +++- + grub-core/loader/arm64/xen_boot.c | 4 +- + grub-core/loader/efi/chainloader.c | 11 +++ + grub-core/loader/efi/linux.c | 164 ++++++++++++++++++++++++++++++++++++- + grub-core/loader/i386/efi/linux.c | 26 +++++- + grub-core/loader/i386/linux.c | 5 ++ + include/grub/efi/efi.h | 6 +- + include/grub/efi/linux.h | 16 +++- + include/grub/efi/pe32.h | 2 + + 10 files changed, 312 insertions(+), 15 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 2c33758ed7..e460b072e6 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -610,6 +610,81 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + #endif + ++grub_addr_t grub_stack_addr = (grub_addr_t)-1ll; ++grub_size_t grub_stack_size = 0; ++ ++static void ++grub_nx_init (void) ++{ ++ grub_uint64_t attrs, stack_attrs; ++ grub_err_t err; ++ grub_addr_t stack_current, stack_end; ++ const grub_uint64_t page_size = 4096; ++ const grub_uint64_t page_mask = ~(page_size - 1); ++ ++ /* ++ * These are to confirm that the flags are working as expected when ++ * debugging. ++ */ ++ attrs = 0; ++ stack_current = (grub_addr_t)grub_nx_init & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n", ++ grub_dl_load_core, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ ++ stack_current = (grub_addr_t)&stack_current & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ { ++ attrs = stack_attrs; ++ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n", ++ &attrs, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ } ++ for (stack_end = stack_current + page_size ; ++ !(attrs & GRUB_MEM_ATTR_R); ++ stack_end += page_size) ++ { ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ break; ++ } ++ } ++ if (stack_end > stack_current) ++ { ++ grub_stack_addr = stack_current; ++ grub_stack_size = stack_end - stack_current; ++ grub_dprintf ("nx", ++ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1); ++ } ++} ++ + void + grub_efi_mm_init (void) + { +@@ -623,6 +698,8 @@ grub_efi_mm_init (void) + grub_efi_uint64_t required_pages; + int mm_status; + ++ grub_nx_init (); ++ + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index cc67f43906..de85583487 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -172,7 +172,8 @@ free_params (void) + } + + grub_err_t +-grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) ++grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args, ++ int nx_supported) + { + grub_err_t retval; + +@@ -182,7 +183,8 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) + + grub_dprintf ("linux", "linux command line: '%s'\n", args); + +- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr); ++ retval = grub_efi_linux_boot (addr, size, handover_offset, ++ (void *)addr, nx_supported); + + /* Never reached... */ + free_params(); +@@ -192,7 +194,10 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) + static grub_err_t + grub_linux_boot (void) + { +- return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args)); ++ return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, ++ (grub_size_t)kernel_size, ++ linux_args, ++ 0); + } + + static grub_err_t +@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_off_t filelen; + grub_uint32_t align; + void *kernel = NULL; ++ int nx_supported = 1; + + grub_dl_ref (my_mod); + +@@ -376,6 +382,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); + grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); + ++ err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ + grub_loader_unset(); + + kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); +diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c +index d9b7a9ba40..6e7e920416 100644 +--- a/grub-core/loader/arm64/xen_boot.c ++++ b/grub-core/loader/arm64/xen_boot.c +@@ -266,7 +266,9 @@ xen_boot (void) + return err; + + return grub_arch_efi_linux_boot_image (xen_hypervisor->start, +- xen_hypervisor->cmdline); ++ xen_hypervisor->size, ++ xen_hypervisor->cmdline, ++ 0); + } + + static void +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index fb874f1855..dd31ac9bb3 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -1070,6 +1070,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ /* ++ * The OS kernel is going to set its own permissions when it takes over ++ * paging a few million instructions from now, and load_image() will set up ++ * anything that's needed based on the section headers, so there's no point ++ * in doing anything but clearing the protection bits here. ++ */ ++ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n", ++ (void *)(grub_addr_t)address, fsize, 0llu); ++ grub_update_mem_attrs (address, fsize, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0); ++ + #if defined (__i386__) || defined (__x86_64__) + if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 9265cf4200..277f352e0c 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -26,16 +26,127 @@ + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" ++#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" ++ ++grub_err_t ++grub_efi_check_nx_image_support (grub_addr_t kernel_addr, ++ grub_size_t kernel_size, ++ int *nx_supported) ++{ ++ struct grub_dos_header *doshdr; ++ grub_size_t sz = sizeof (*doshdr); ++ ++ struct grub_pe32_header_32 *pe32; ++ struct grub_pe32_header_64 *pe64; ++ ++ int image_is_compatible = 0; ++ int is_64_bit; ++ ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ doshdr = (void *)kernel_addr; ++ ++ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid")); ++ ++ sz = doshdr->lfanew + sizeof (*pe32); ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew); ++ pe64 = (struct grub_pe32_header_64 *)pe32; ++ ++ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE, ++ GRUB_PE32_SIGNATURE_SIZE) != 0) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); ++ ++ switch (pe32->coff_header.machine) ++ { ++ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED: ++ case GRUB_PE32_MACHINE_I386: ++ case GRUB_PE32_MACHINE_RISCV32: ++ is_64_bit = 0; ++ break; ++ case GRUB_PE32_MACHINE_ARM64: ++ case GRUB_PE32_MACHINE_IA64: ++ case GRUB_PE32_MACHINE_RISCV64: ++ case GRUB_PE32_MACHINE_X86_64: ++ is_64_bit = 1; ++ break; ++ default: ++ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"), ++ pe32->coff_header.machine); ++ } ++ ++ if (is_64_bit) ++ { ++ sz = doshdr->lfanew + sizeof (*pe64); ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ else ++ { ++ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ ++ *nx_supported = image_is_compatible; ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_efi_check_nx_required (int *nx_required) ++{ ++ grub_efi_status_t status; ++ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID; ++ grub_size_t mok_policy_sz = 0; ++ char *mok_policy = NULL; ++ grub_uint32_t mok_policy_attrs = 0; ++ ++ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid, ++ &mok_policy_sz, ++ (void **)&mok_policy, ++ &mok_policy_attrs); ++ if (status == GRUB_EFI_NOT_FOUND || ++ mok_policy_sz == 0 || ++ mok_policy == NULL) ++ { ++ *nx_required = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ *nx_required = 0; ++ if (mok_policy_sz < 1 || ++ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) || ++ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED)) ++ *nx_required = 1; ++ ++ return GRUB_ERR_NONE; ++} + + typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + + grub_err_t +-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, +- void *kernel_params) ++grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, ++ grub_off_t handover_offset, void *kernel_params, ++ int nx_supported) + { + grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + int offset = 0; ++ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ grub_uint64_t stack_clear_attrs = 0; ++ grub_uint64_t kernel_set_attrs = stack_set_attrs; ++ grub_uint64_t kernel_clear_attrs = stack_clear_attrs; ++ grub_uint64_t attrs; ++ int nx_required = 0; + + #ifdef __x86_64__ + offset = 512; +@@ -48,12 +159,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + */ + loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (loaded_image) +- loaded_image->image_base = kernel_addr; ++ loaded_image->image_base = (void *)kernel_addr; + else + grub_dprintf ("linux", "Loaded Image base address could not be set\n"); + + grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", +- kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); ++ (void *)kernel_addr, (void *)handover_offset, kernel_params); ++ ++ ++ if (nx_required && !nx_supported) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy")); ++ ++ if (nx_supported) ++ { ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_W; ++ stack_set_attrs &= ~GRUB_MEM_ATTR_X; ++ stack_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n", ++ kernel_addr, kernel_addr + kernel_size - 1, ++ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-'); ++ grub_update_mem_attrs (kernel_addr, kernel_size, ++ kernel_set_attrs, kernel_clear_attrs); ++ ++ grub_get_mem_attrs (kernel_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ (grub_addr_t)kernel_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ if (grub_stack_addr != (grub_addr_t)-1ll) ++ { ++ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, ++ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, ++ stack_set_attrs, stack_clear_attrs); ++ ++ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ grub_stack_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++#if defined(__i386__) || defined(__x86_64__) ++ asm volatile ("cli"); ++#endif ++ + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 92b2fb5091..91ae274299 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -44,7 +44,7 @@ struct grub_linuxefi_context { + grub_uint32_t handover_offset; + struct linux_kernel_params *params; + char *cmdline; +- ++ int nx_supported; + void *initrd_mem; + }; + +@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size, + pages = BYTES_TO_PAGES(size); + grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", + (unsigned long)pages, (void *)(unsigned long)max); ++ size = pages * GRUB_EFI_PAGE_SIZE; + + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, + max_addresses[i].alloc_type, + memtype); + if (addr) +- grub_dprintf ("linux", "Allocated at %p\n", addr); ++ { ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ grub_update_mem_attrs ((grub_addr_t)addr, size, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, ++ GRUB_MEM_ATTR_X); ++ } + } + + while (grub_error_pop ()) +@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data) + + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)context->kernel_mem, ++ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem, ++ context->kernel_size, + context->handover_offset, +- context->params); ++ context->params, ++ context->nx_supported); + } + + static grub_err_t +@@ -304,7 +312,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_uint32_t handover_offset; + struct linux_kernel_params *params = 0; + char *cmdline = 0; ++ int nx_supported = 1; + struct grub_linuxefi_context *context = 0; ++ grub_err_t err; + + grub_dl_ref (my_mod); + +@@ -334,6 +344,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen, ++ &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ grub_dprintf ("linux", "nx is%s supported by this kernel\n", ++ nx_supported ? "" : " not"); ++ + lh = (struct linux_i386_kernel_header *)kernel; + grub_dprintf ("linux", "original lh is at %p\n", kernel); + +@@ -498,6 +515,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + context->handover_offset = handover_offset; + context->params = params; + context->cmdline = cmdline; ++ context->nx_supported = nx_supported; + + grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 4aeb0e4b9a..3c1ff64763 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -805,6 +805,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + kernel_offset += len; + } + ++ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n", ++ &linux_params, sizeof (lh) + len); ++ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X); ++ + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; + linux_params.kernel_alignment = (1 << align); + linux_params.ps_mouse = linux_params.padding11 = 0; +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 34825c4adc..449e55269f 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -140,12 +140,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, + char **device, + char **path); + ++extern grub_addr_t EXPORT_VAR(grub_stack_addr); ++extern grub_size_t EXPORT_VAR(grub_stack_size); ++ + #if defined(__arm__) || defined(__aarch64__) || defined(__riscv) + void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); + grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); + #include + grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); +-grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); ++grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, ++ char *args, int nx_enabled); + #endif + + grub_addr_t grub_efi_section_addr (const char *section); +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +index 887b02fd9f..b82f71006a 100644 +--- a/include/grub/efi/linux.h ++++ b/include/grub/efi/linux.h +@@ -22,8 +22,20 @@ + #include + #include + ++#define GRUB_MOK_POLICY_NX_REQUIRED 0x1 ++ + grub_err_t +-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, +- void *kernel_param); ++EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address, ++ grub_size_t kernel_size, ++ grub_off_t handover_offset, ++ void *kernel_param, int nx_enabled); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr, ++ grub_size_t kernel_size, ++ int *nx_supported); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required); + + #endif /* ! GRUB_EFI_LINUX_HEADER */ +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index 2a5e1ee003..a5e623eb04 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -181,6 +181,8 @@ struct grub_pe32_optional_header + struct grub_pe32_data_directory reserved_entry; + }; + ++#define GRUB_PE32_NX_COMPAT 0x0100 ++ + struct grub_pe64_optional_header + { + grub_uint16_t magic; diff --git a/0264-nx-set-page-permissions-for-loaded-modules.patch b/0264-nx-set-page-permissions-for-loaded-modules.patch deleted file mode 100644 index 9e0aebb..0000000 --- a/0264-nx-set-page-permissions-for-loaded-modules.patch +++ /dev/null @@ -1,263 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 21 Mar 2022 17:46:35 -0400 -Subject: [PATCH] nx: set page permissions for loaded modules. - -For NX, we need to set write and executable permissions on the sections -of grub modules when we load them. - -On sections with SHF_ALLOC set, which is typically everything except -.modname and the symbol and string tables, this patch clears the Read -Only flag on sections that have the ELF flag SHF_WRITE set, and clears -the No eXecute flag on sections with SHF_EXECINSTR set. In all other -cases it sets both flags. - -Signed-off-by: Peter Jones -[rharwood: arm tgptr -> tgaddr] -Signed-off-by: Robbie Harwood ---- - grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++------------- - include/grub/dl.h | 44 +++++++++++++++++++ - 2 files changed, 134 insertions(+), 30 deletions(-) - -diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c -index 8c7aacef39..d5de80186f 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -285,6 +285,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - #endif - char *ptr; - -+ grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name); -+ - arch_addralign = grub_arch_dl_min_alignment (); - - for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); -@@ -384,6 +386,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) - ptr += got; - #endif - -+ grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name); - return GRUB_ERR_NONE; - } - -@@ -517,23 +520,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name) - return s; - return NULL; - } --static long --grub_dl_find_section_index (Elf_Ehdr *e, const char *name) --{ -- Elf_Shdr *s; -- const char *str; -- unsigned i; -- -- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); -- str = (char *) e + s->sh_offset; -- -- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); -- i < e->e_shnum; -- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) -- if (grub_strcmp (str + s->sh_name, name) == 0) -- return (long)i; -- return -1; --} - - /* Me, Vladimir Serbinenko, hereby I add this module check as per new - GNU module policy. Note that this license check is informative only. -@@ -662,6 +648,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) - Elf_Shdr *s; - unsigned i; - -+ grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name); - for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); - i < e->e_shnum; - i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) -@@ -670,24 +657,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) - grub_dl_segment_t seg; - grub_err_t err; - -- /* Find the target segment. */ -- for (seg = mod->segment; seg; seg = seg->next) -- if (seg->section == s->sh_info) -- break; -+ seg = grub_dl_find_segment(mod, s->sh_info); -+ if (!seg) -+ continue; - -- if (seg) -- { -- if (!mod->symtab) -- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); -+ if (!mod->symtab) -+ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); - -- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); -- if (err) -- return err; -- } -+ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); -+ if (err) -+ return err; - } - -+ grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name); - return GRUB_ERR_NONE; - } -+ -+static grub_err_t -+grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) -+{ -+ unsigned i; -+ const Elf_Shdr *s; -+ const Elf_Ehdr *e = ehdr; -+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) -+ grub_size_t arch_addralign = grub_arch_dl_min_alignment (); -+ grub_addr_t tgaddr; -+ grub_uint64_t tgsz; -+#endif -+ -+ grub_dprintf ("modules", "updating memory attributes for \"%s\"\n", -+ mod->name); -+ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); -+ i < e->e_shnum; -+ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) -+ { -+ grub_dl_segment_t seg; -+ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R; -+ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X; -+ -+ seg = grub_dl_find_segment(mod, i); -+ if (!seg) -+ continue; -+ -+ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC)) -+ continue; -+ -+ if (s->sh_flags & SHF_WRITE) -+ { -+ set_attrs |= GRUB_MEM_ATTR_W; -+ clear_attrs &= ~GRUB_MEM_ATTR_W; -+ } -+ -+ if (s->sh_flags & SHF_EXECINSTR) -+ { -+ set_attrs |= GRUB_MEM_ATTR_X; -+ clear_attrs &= ~GRUB_MEM_ATTR_X; -+ } -+ -+ grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n", -+ grub_dl_get_section_name(e, s), -+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", -+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", -+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", -+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", -+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", -+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); -+ grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs); -+ } -+ -+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) -+ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got); -+ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr; -+ -+ if (tgsz) -+ { -+ tgsz = ALIGN_UP(tgsz, arch_addralign); -+ -+ grub_dprintf ("modules", "updating attributes for GOT and trampolines\n", -+ mod->name); -+ grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X, -+ GRUB_MEM_ATTR_W); -+ } -+#endif -+ -+ grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n", -+ mod->name); -+ -+ return GRUB_ERR_NONE; -+} -+ - static void - grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) - { -@@ -753,6 +811,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) - mod->ref_count = 1; - - grub_dprintf ("modules", "relocating to %p\n", mod); -+ - /* Me, Vladimir Serbinenko, hereby I add this module check as per new - GNU module policy. Note that this license check is informative only. - Modules have to be licensed under GPLv3 or GPLv3+ (optionally -@@ -766,7 +825,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) - || grub_dl_resolve_dependencies (mod, e) - || grub_dl_load_segments (mod, e) - || grub_dl_resolve_symbols (mod, e) -- || grub_dl_relocate_symbols (mod, e)) -+ || grub_dl_relocate_symbols (mod, e) -+ || grub_dl_set_mem_attrs (mod, e)) - { - mod->fini = 0; - grub_dl_unload (mod); -diff --git a/include/grub/dl.h b/include/grub/dl.h -index f36ed5cb17..45ac8e339f 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #endif - - /* -@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod) - return mod->persistent; - } - -+static inline const char * -+grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s) -+{ -+ Elf_Shdr *str_s; -+ const char *str; -+ -+ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); -+ str = (char *) e + str_s->sh_offset; -+ -+ return str + s->sh_name; -+} -+ -+static inline long -+grub_dl_find_section_index (Elf_Ehdr *e, const char *name) -+{ -+ Elf_Shdr *s; -+ const char *str; -+ unsigned i; -+ -+ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); -+ str = (char *) e + s->sh_offset; -+ -+ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); -+ i < e->e_shnum; -+ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) -+ if (grub_strcmp (str + s->sh_name, name) == 0) -+ return (long)i; -+ return -1; -+} -+ -+/* Return the segment for a section of index N */ -+static inline grub_dl_segment_t -+grub_dl_find_segment (grub_dl_t mod, unsigned n) -+{ -+ grub_dl_segment_t seg; -+ -+ for (seg = mod->segment; seg; seg = seg->next) -+ if (seg->section == n) -+ return seg; -+ -+ return NULL; -+} -+ - #endif - - void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); diff --git a/0264-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch b/0264-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch new file mode 100644 index 0000000..7da75a8 --- /dev/null +++ b/0264-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:57:20 -0400 +Subject: [PATCH] nx: set the nx compatible flag in EFI grub images + +For NX, we need the grub binary to announce that it is compatible with +the NX feature. This implies that when loading the executable grub +image, several attributes are true: + +- the binary doesn't need an executable stack +- the binary doesn't need sections to be both executable and writable +- the binary knows how to use the EFI Memory Attributes protocol on code + it is loading. + +This patch adds a definition for the PE DLL Characteristics flag +GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag. + +Signed-off-by: Peter Jones +--- + util/mkimage.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 8319e8dfbd..c3d33aaac8 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1418,6 +1418,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + section = (struct grub_pe32_section_table *)(o64 + 1); + } + ++ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT); + 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, image_base) = 0; diff --git a/0265-grub-probe-document-the-behavior-of-multiple-v.patch b/0265-grub-probe-document-the-behavior-of-multiple-v.patch new file mode 100644 index 0000000..4e9d7cc --- /dev/null +++ b/0265-grub-probe-document-the-behavior-of-multiple-v.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 15 Jul 2022 15:49:25 -0400 +Subject: [PATCH] grub-probe: document the behavior of multiple -v + +Signed-off-by: Robbie Harwood +(cherry picked from commit 51a55233eed08f7f12276afd6b3724b807a0b680) +--- + util/grub-probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/util/grub-probe.c b/util/grub-probe.c +index c6fac732b4..ba867319a7 100644 +--- a/util/grub-probe.c ++++ b/util/grub-probe.c +@@ -732,7 +732,8 @@ static struct argp_option options[] = { + {"device-map", 'm', N_("FILE"), 0, + N_("use FILE as the device map [default=%s]"), 0}, + {"target", 't', N_("TARGET"), 0, 0, 0}, +- {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, ++ {"verbose", 'v', 0, 0, ++ N_("print verbose messages (pass twice to enable debug printing)."), 0}, + {0, '0', 0, 0, N_("separate items in output using ASCII NUL characters"), 0}, + { 0, 0, 0, 0, 0, 0 } + }; diff --git a/0265-nx-set-attrs-in-our-kernel-loaders.patch b/0265-nx-set-attrs-in-our-kernel-loaders.patch deleted file mode 100644 index 514df1f..0000000 --- a/0265-nx-set-attrs-in-our-kernel-loaders.patch +++ /dev/null @@ -1,565 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 22 Mar 2022 10:57:07 -0400 -Subject: [PATCH] nx: set attrs in our kernel loaders - -For NX, our kernel loaders need to set write and execute page -permissions on allocated pages and the stack. - -This patch adds those calls. - -Signed-off-by: Peter Jones -[rharwood: fix stack_attrs undefined, fix aarch64 callsites] -Signed-off-by: Robbie Harwood ---- - grub-core/kern/efi/mm.c | 77 +++++++++++++++++ - grub-core/loader/arm64/linux.c | 16 +++- - grub-core/loader/arm64/xen_boot.c | 4 +- - grub-core/loader/efi/chainloader.c | 11 +++ - grub-core/loader/efi/linux.c | 164 ++++++++++++++++++++++++++++++++++++- - grub-core/loader/i386/efi/linux.c | 26 +++++- - grub-core/loader/i386/linux.c | 5 ++ - include/grub/efi/efi.h | 6 +- - include/grub/efi/linux.h | 16 +++- - include/grub/efi/pe32.h | 2 + - 10 files changed, 312 insertions(+), 15 deletions(-) - -diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c -index 2c33758ed7..e460b072e6 100644 ---- a/grub-core/kern/efi/mm.c -+++ b/grub-core/kern/efi/mm.c -@@ -610,6 +610,81 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, - } - #endif - -+grub_addr_t grub_stack_addr = (grub_addr_t)-1ll; -+grub_size_t grub_stack_size = 0; -+ -+static void -+grub_nx_init (void) -+{ -+ grub_uint64_t attrs, stack_attrs; -+ grub_err_t err; -+ grub_addr_t stack_current, stack_end; -+ const grub_uint64_t page_size = 4096; -+ const grub_uint64_t page_mask = ~(page_size - 1); -+ -+ /* -+ * These are to confirm that the flags are working as expected when -+ * debugging. -+ */ -+ attrs = 0; -+ stack_current = (grub_addr_t)grub_nx_init & page_mask; -+ err = grub_get_mem_attrs (stack_current, page_size, &attrs); -+ if (err) -+ { -+ grub_dprintf ("nx", -+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", -+ stack_current, err); -+ grub_error_pop (); -+ } -+ else -+ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n", -+ grub_dl_load_core, -+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', -+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', -+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); -+ -+ stack_current = (grub_addr_t)&stack_current & page_mask; -+ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs); -+ if (err) -+ { -+ grub_dprintf ("nx", -+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", -+ stack_current, err); -+ grub_error_pop (); -+ } -+ else -+ { -+ attrs = stack_attrs; -+ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n", -+ &attrs, -+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', -+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', -+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); -+ } -+ for (stack_end = stack_current + page_size ; -+ !(attrs & GRUB_MEM_ATTR_R); -+ stack_end += page_size) -+ { -+ err = grub_get_mem_attrs (stack_current, page_size, &attrs); -+ if (err) -+ { -+ grub_dprintf ("nx", -+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", -+ stack_current, err); -+ grub_error_pop (); -+ break; -+ } -+ } -+ if (stack_end > stack_current) -+ { -+ grub_stack_addr = stack_current; -+ grub_stack_size = stack_end - stack_current; -+ grub_dprintf ("nx", -+ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n", -+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1); -+ } -+} -+ - void - grub_efi_mm_init (void) - { -@@ -623,6 +698,8 @@ grub_efi_mm_init (void) - grub_efi_uint64_t required_pages; - int mm_status; - -+ grub_nx_init (); -+ - /* Prepare a memory region to store two memory maps. */ - memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); - if (! memory_map) -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index cc67f43906..de85583487 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -172,7 +172,8 @@ free_params (void) - } - - grub_err_t --grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) -+grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args, -+ int nx_supported) - { - grub_err_t retval; - -@@ -182,7 +183,8 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) - - grub_dprintf ("linux", "linux command line: '%s'\n", args); - -- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr); -+ retval = grub_efi_linux_boot (addr, size, handover_offset, -+ (void *)addr, nx_supported); - - /* Never reached... */ - free_params(); -@@ -192,7 +194,10 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) - static grub_err_t - grub_linux_boot (void) - { -- return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args)); -+ return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, -+ (grub_size_t)kernel_size, -+ linux_args, -+ 0); - } - - static grub_err_t -@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_off_t filelen; - grub_uint32_t align; - void *kernel = NULL; -+ int nx_supported = 1; - - grub_dl_ref (my_mod); - -@@ -376,6 +382,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); - grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); - -+ err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); -+ if (err != GRUB_ERR_NONE) -+ goto fail; -+ - grub_loader_unset(); - - kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); -diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c -index d9b7a9ba40..6e7e920416 100644 ---- a/grub-core/loader/arm64/xen_boot.c -+++ b/grub-core/loader/arm64/xen_boot.c -@@ -266,7 +266,9 @@ xen_boot (void) - return err; - - return grub_arch_efi_linux_boot_image (xen_hypervisor->start, -- xen_hypervisor->cmdline); -+ xen_hypervisor->size, -+ xen_hypervisor->cmdline, -+ 0); - } - - static void -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index fb874f1855..dd31ac9bb3 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -1070,6 +1070,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -+ /* -+ * The OS kernel is going to set its own permissions when it takes over -+ * paging a few million instructions from now, and load_image() will set up -+ * anything that's needed based on the section headers, so there's no point -+ * in doing anything but clearing the protection bits here. -+ */ -+ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n", -+ (void *)(grub_addr_t)address, fsize, 0llu); -+ grub_update_mem_attrs (address, fsize, -+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0); -+ - #if defined (__i386__) || defined (__x86_64__) - if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) - { -diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c -index 9265cf4200..277f352e0c 100644 ---- a/grub-core/loader/efi/linux.c -+++ b/grub-core/loader/efi/linux.c -@@ -26,16 +26,127 @@ - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" -+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" -+ -+grub_err_t -+grub_efi_check_nx_image_support (grub_addr_t kernel_addr, -+ grub_size_t kernel_size, -+ int *nx_supported) -+{ -+ struct grub_dos_header *doshdr; -+ grub_size_t sz = sizeof (*doshdr); -+ -+ struct grub_pe32_header_32 *pe32; -+ struct grub_pe32_header_64 *pe64; -+ -+ int image_is_compatible = 0; -+ int is_64_bit; -+ -+ if (kernel_size < sz) -+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); -+ -+ doshdr = (void *)kernel_addr; -+ -+ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC) -+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid")); -+ -+ sz = doshdr->lfanew + sizeof (*pe32); -+ if (kernel_size < sz) -+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); -+ -+ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew); -+ pe64 = (struct grub_pe32_header_64 *)pe32; -+ -+ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE, -+ GRUB_PE32_SIGNATURE_SIZE) != 0) -+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); -+ -+ switch (pe32->coff_header.machine) -+ { -+ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED: -+ case GRUB_PE32_MACHINE_I386: -+ case GRUB_PE32_MACHINE_RISCV32: -+ is_64_bit = 0; -+ break; -+ case GRUB_PE32_MACHINE_ARM64: -+ case GRUB_PE32_MACHINE_IA64: -+ case GRUB_PE32_MACHINE_RISCV64: -+ case GRUB_PE32_MACHINE_X86_64: -+ is_64_bit = 1; -+ break; -+ default: -+ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"), -+ pe32->coff_header.machine); -+ } -+ -+ if (is_64_bit) -+ { -+ sz = doshdr->lfanew + sizeof (*pe64); -+ if (kernel_size < sz) -+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); -+ -+ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) -+ image_is_compatible = 1; -+ } -+ else -+ { -+ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) -+ image_is_compatible = 1; -+ } -+ -+ *nx_supported = image_is_compatible; -+ return GRUB_ERR_NONE; -+} -+ -+grub_err_t -+grub_efi_check_nx_required (int *nx_required) -+{ -+ grub_efi_status_t status; -+ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID; -+ grub_size_t mok_policy_sz = 0; -+ char *mok_policy = NULL; -+ grub_uint32_t mok_policy_attrs = 0; -+ -+ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid, -+ &mok_policy_sz, -+ (void **)&mok_policy, -+ &mok_policy_attrs); -+ if (status == GRUB_EFI_NOT_FOUND || -+ mok_policy_sz == 0 || -+ mok_policy == NULL) -+ { -+ *nx_required = 0; -+ return GRUB_ERR_NONE; -+ } -+ -+ *nx_required = 0; -+ if (mok_policy_sz < 1 || -+ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | -+ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) || -+ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED)) -+ *nx_required = 1; -+ -+ return GRUB_ERR_NONE; -+} - - typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); - - grub_err_t --grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, -- void *kernel_params) -+grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, -+ grub_off_t handover_offset, void *kernel_params, -+ int nx_supported) - { - grub_efi_loaded_image_t *loaded_image = NULL; - handover_func hf; - int offset = 0; -+ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R | -+ GRUB_MEM_ATTR_W | -+ GRUB_MEM_ATTR_X; -+ grub_uint64_t stack_clear_attrs = 0; -+ grub_uint64_t kernel_set_attrs = stack_set_attrs; -+ grub_uint64_t kernel_clear_attrs = stack_clear_attrs; -+ grub_uint64_t attrs; -+ int nx_required = 0; - - #ifdef __x86_64__ - offset = 512; -@@ -48,12 +159,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, - */ - loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); - if (loaded_image) -- loaded_image->image_base = kernel_addr; -+ loaded_image->image_base = (void *)kernel_addr; - else - grub_dprintf ("linux", "Loaded Image base address could not be set\n"); - - grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", -- kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); -+ (void *)kernel_addr, (void *)handover_offset, kernel_params); -+ -+ -+ if (nx_required && !nx_supported) -+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy")); -+ -+ if (nx_supported) -+ { -+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; -+ kernel_clear_attrs |= GRUB_MEM_ATTR_W; -+ stack_set_attrs &= ~GRUB_MEM_ATTR_X; -+ stack_clear_attrs |= GRUB_MEM_ATTR_X; -+ } -+ -+ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n", -+ kernel_addr, kernel_addr + kernel_size - 1, -+ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-'); -+ grub_update_mem_attrs (kernel_addr, kernel_size, -+ kernel_set_attrs, kernel_clear_attrs); -+ -+ grub_get_mem_attrs (kernel_addr, 4096, &attrs); -+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", -+ (grub_addr_t)kernel_addr, -+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", -+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", -+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); -+ if (grub_stack_addr != (grub_addr_t)-1ll) -+ { -+ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", -+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, -+ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); -+ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, -+ stack_set_attrs, stack_clear_attrs); -+ -+ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); -+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", -+ grub_stack_addr, -+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", -+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", -+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); -+ } -+ -+#if defined(__i386__) || defined(__x86_64__) -+ asm volatile ("cli"); -+#endif -+ - hf = (handover_func)((char *)kernel_addr + handover_offset + offset); - hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 92b2fb5091..91ae274299 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -44,7 +44,7 @@ struct grub_linuxefi_context { - grub_uint32_t handover_offset; - struct linux_kernel_params *params; - char *cmdline; -- -+ int nx_supported; - void *initrd_mem; - }; - -@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size, - pages = BYTES_TO_PAGES(size); - grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", - (unsigned long)pages, (void *)(unsigned long)max); -+ size = pages * GRUB_EFI_PAGE_SIZE; - - prev_max = max; - addr = grub_efi_allocate_pages_real (max, pages, - max_addresses[i].alloc_type, - memtype); - if (addr) -- grub_dprintf ("linux", "Allocated at %p\n", addr); -+ { -+ grub_dprintf ("linux", "Allocated at %p\n", addr); -+ grub_update_mem_attrs ((grub_addr_t)addr, size, -+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, -+ GRUB_MEM_ATTR_X); -+ } - } - - while (grub_error_pop ()) -@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data) - - asm volatile ("cli"); - -- return grub_efi_linux_boot ((char *)context->kernel_mem, -+ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem, -+ context->kernel_size, - context->handover_offset, -- context->params); -+ context->params, -+ context->nx_supported); - } - - static grub_err_t -@@ -304,7 +312,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_uint32_t handover_offset; - struct linux_kernel_params *params = 0; - char *cmdline = 0; -+ int nx_supported = 1; - struct grub_linuxefi_context *context = 0; -+ grub_err_t err; - - grub_dl_ref (my_mod); - -@@ -334,6 +344,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -+ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen, -+ &nx_supported); -+ if (err != GRUB_ERR_NONE) -+ return err; -+ grub_dprintf ("linux", "nx is%s supported by this kernel\n", -+ nx_supported ? "" : " not"); -+ - lh = (struct linux_i386_kernel_header *)kernel; - grub_dprintf ("linux", "original lh is at %p\n", kernel); - -@@ -498,6 +515,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - context->handover_offset = handover_offset; - context->params = params; - context->cmdline = cmdline; -+ context->nx_supported = nx_supported; - - grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); - -diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c -index 4aeb0e4b9a..3c1ff64763 100644 ---- a/grub-core/loader/i386/linux.c -+++ b/grub-core/loader/i386/linux.c -@@ -805,6 +805,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - kernel_offset += len; - } - -+ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n", -+ &linux_params, sizeof (lh) + len); -+ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len, -+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X); -+ - linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; - linux_params.kernel_alignment = (1 << align); - linux_params.ps_mouse = linux_params.padding11 = 0; -diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h -index 34825c4adc..449e55269f 100644 ---- a/include/grub/efi/efi.h -+++ b/include/grub/efi/efi.h -@@ -140,12 +140,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, - char **device, - char **path); - -+extern grub_addr_t EXPORT_VAR(grub_stack_addr); -+extern grub_size_t EXPORT_VAR(grub_stack_size); -+ - #if defined(__arm__) || defined(__aarch64__) || defined(__riscv) - void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); - grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); - #include - grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); --grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); -+grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, -+ char *args, int nx_enabled); - #endif - - grub_addr_t grub_efi_section_addr (const char *section); -diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h -index 887b02fd9f..b82f71006a 100644 ---- a/include/grub/efi/linux.h -+++ b/include/grub/efi/linux.h -@@ -22,8 +22,20 @@ - #include - #include - -+#define GRUB_MOK_POLICY_NX_REQUIRED 0x1 -+ - grub_err_t --EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, -- void *kernel_param); -+EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address, -+ grub_size_t kernel_size, -+ grub_off_t handover_offset, -+ void *kernel_param, int nx_enabled); -+ -+grub_err_t -+EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr, -+ grub_size_t kernel_size, -+ int *nx_supported); -+ -+grub_err_t -+EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required); - - #endif /* ! GRUB_EFI_LINUX_HEADER */ -diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h -index 2a5e1ee003..a5e623eb04 100644 ---- a/include/grub/efi/pe32.h -+++ b/include/grub/efi/pe32.h -@@ -181,6 +181,8 @@ struct grub_pe32_optional_header - struct grub_pe32_data_directory reserved_entry; - }; - -+#define GRUB_PE32_NX_COMPAT 0x0100 -+ - struct grub_pe64_optional_header - { - grub_uint16_t magic; diff --git a/0266-grub_fs_probe-dprint-errors-from-filesystems.patch b/0266-grub_fs_probe-dprint-errors-from-filesystems.patch new file mode 100644 index 0000000..1455ae4 --- /dev/null +++ b/0266-grub_fs_probe-dprint-errors-from-filesystems.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 15 Jul 2022 15:39:41 -0400 +Subject: [PATCH] grub_fs_probe(): dprint errors from filesystems + +When filesystem detection fails, all that's currently debug-logged is a +series of messages like: + + grub-core/kern/fs.c:56:fs: Detecting ntfs... + grub-core/kern/fs.c:76:fs: ntfs detection failed. + +repeated for each filesystem. Any messages provided to grub_error() by +the filesystem are lost, and one has to break out gdb to figure out what +went wrong. + +With this change, one instead sees: + + grub-core/kern/fs.c:56:fs: Detecting fat... + grub-core/osdep/hostdisk.c:357:hostdisk: reusing open device + `/path/to/device' + grub-core/kern/fs.c:77:fs: error: invalid modification timestamp for /. + grub-core/kern/fs.c:79:fs: fat detection failed. + +in the debug prints. + +Signed-off-by: Robbie Harwood +(cherry picked from commit 838c79d658797d0662ee7f9e033e38ee88059e02) +--- + grub-core/kern/fs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c +index c698295bcb..b58e2ae1d2 100644 +--- a/grub-core/kern/fs.c ++++ b/grub-core/kern/fs.c +@@ -74,6 +74,7 @@ grub_fs_probe (grub_device_t device) + if (grub_errno == GRUB_ERR_NONE) + return p; + ++ grub_dprintf ("fs", _("error: %s.\n"), grub_errmsg); + grub_error_push (); + grub_dprintf ("fs", "%s detection failed.\n", p->name); + grub_error_pop (); diff --git a/0266-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch b/0266-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch deleted file mode 100644 index 7da75a8..0000000 --- a/0266-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 22 Mar 2022 10:57:20 -0400 -Subject: [PATCH] nx: set the nx compatible flag in EFI grub images - -For NX, we need the grub binary to announce that it is compatible with -the NX feature. This implies that when loading the executable grub -image, several attributes are true: - -- the binary doesn't need an executable stack -- the binary doesn't need sections to be both executable and writable -- the binary knows how to use the EFI Memory Attributes protocol on code - it is loading. - -This patch adds a definition for the PE DLL Characteristics flag -GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag. - -Signed-off-by: Peter Jones ---- - util/mkimage.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/util/mkimage.c b/util/mkimage.c -index 8319e8dfbd..c3d33aaac8 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -1418,6 +1418,7 @@ grub_install_generate_image (const char *dir, const char *prefix, - section = (struct grub_pe32_section_table *)(o64 + 1); - } - -+ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT); - 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, image_base) = 0; diff --git a/0267-fs-fat-don-t-error-when-mtime-is-0.patch b/0267-fs-fat-don-t-error-when-mtime-is-0.patch new file mode 100644 index 0000000..f014f6c --- /dev/null +++ b/0267-fs-fat-don-t-error-when-mtime-is-0.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 15 Jul 2022 15:42:41 -0400 +Subject: [PATCH] fs/fat: don't error when mtime is 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the wild, we occasionally see valid ESPs where some file modification times +are 0. For instance: + + ├── [Dec 31 1979] EFI + │ ├── [Dec 31 1979] BOOT + │ │ ├── [Dec 31 1979] BOOTX64.EFI + │ │ └── [Dec 31 1979] fbx64.efi + │ └── [Jun 27 02:41] fedora + │ ├── [Dec 31 1979] BOOTX64.CSV + │ ├── [Dec 31 1979] fonts + │ ├── [Mar 14 03:35] fw + │ │ ├── [Mar 14 03:35] fwupd-359c1169-abd6-4a0d-8bce-e4d4713335c1.cap + │ │ ├── [Mar 14 03:34] fwupd-9d255c4b-2d88-4861-860d-7ee52ade9463.cap + │ │ └── [Mar 14 03:34] fwupd-b36438d8-9128-49d2-b280-487be02d948b.cap + │ ├── [Dec 31 1979] fwupdx64.efi + │ ├── [May 10 10:47] grub.cfg + │ ├── [Jun 3 12:38] grub.cfg.new.new + │ ├── [May 10 10:41] grub.cfg.old + │ ├── [Jun 27 02:41] grubenv + │ ├── [Dec 31 1979] grubx64.efi + │ ├── [Dec 31 1979] mmx64.efi + │ ├── [Dec 31 1979] shim.efi + │ ├── [Dec 31 1979] shimx64.efi + │ └── [Dec 31 1979] shimx64-fedora.efi + └── [Dec 31 1979] FSCK0000.REC + + 5 directories, 17 files + +This causes grub-probe failure, which in turn causes grub-mkconfig +failure. They are valid filesystems that appear intact, and the Linux +FAT stack is able to mount and manipulate them without complaint. + +The check for mtime of 0 has been present since +20def1a3c3952982395cd7c3ea7e78638527962b ("fat: support file +modification times"). + +Signed-off-by: Robbie Harwood +(cherry picked from commit 0615c4887352e32d7bb7198e9ad0d695f9dc2c31) +--- + grub-core/fs/fat.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c +index dd82e4ee35..ff6200c5be 100644 +--- a/grub-core/fs/fat.c ++++ b/grub-core/fs/fat.c +@@ -1027,9 +1027,6 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, + grub_le_to_cpu16 (ctxt.dir.w_date), + &info.mtime); + #endif +- if (info.mtimeset == 0) +- grub_error (GRUB_ERR_OUT_OF_RANGE, +- "invalid modification timestamp for %s", path); + + if (hook (ctxt.filename, &info, hook_data)) + break; diff --git a/0267-grub-probe-document-the-behavior-of-multiple-v.patch b/0267-grub-probe-document-the-behavior-of-multiple-v.patch deleted file mode 100644 index 4e9d7cc..0000000 --- a/0267-grub-probe-document-the-behavior-of-multiple-v.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Fri, 15 Jul 2022 15:49:25 -0400 -Subject: [PATCH] grub-probe: document the behavior of multiple -v - -Signed-off-by: Robbie Harwood -(cherry picked from commit 51a55233eed08f7f12276afd6b3724b807a0b680) ---- - util/grub-probe.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/util/grub-probe.c b/util/grub-probe.c -index c6fac732b4..ba867319a7 100644 ---- a/util/grub-probe.c -+++ b/util/grub-probe.c -@@ -732,7 +732,8 @@ static struct argp_option options[] = { - {"device-map", 'm', N_("FILE"), 0, - N_("use FILE as the device map [default=%s]"), 0}, - {"target", 't', N_("TARGET"), 0, 0, 0}, -- {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, -+ {"verbose", 'v', 0, 0, -+ N_("print verbose messages (pass twice to enable debug printing)."), 0}, - {0, '0', 0, 0, N_("separate items in output using ASCII NUL characters"), 0}, - { 0, 0, 0, 0, 0, 0 } - }; diff --git a/0268-Make-debug-file-show-which-file-filters-get-run.patch b/0268-Make-debug-file-show-which-file-filters-get-run.patch new file mode 100644 index 0000000..4ac32cb --- /dev/null +++ b/0268-Make-debug-file-show-which-file-filters-get-run.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 29 Jul 2022 15:56:00 -0400 +Subject: [PATCH] Make debug=file show which file filters get run. + +If one of the file filters breaks things, it's hard to figure out where +it has happened. + +This makes grub log which filter is being run, which makes it easier to +figure out where you are in the sequence of events. + +Signed-off-by: Peter Jones +--- + grub-core/kern/file.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index ed69fc0f0f..20a4c839aa 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -30,6 +30,14 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void); + + grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; + ++static const char *filter_names[] = { ++ [GRUB_FILE_FILTER_VERIFY] = "GRUB_FILE_FILTER_VERIFY", ++ [GRUB_FILE_FILTER_GZIO] = "GRUB_FILE_FILTER_GZIO", ++ [GRUB_FILE_FILTER_XZIO] = "GRUB_FILE_FILTER_XZIO", ++ [GRUB_FILE_FILTER_LZOPIO] = "GRUB_FILE_FILTER_LZOPIO", ++ [GRUB_FILE_FILTER_MAX] = "GRUB_FILE_FILTER_MAX" ++}; ++ + /* Get the device part of the filename NAME. It is enclosed by parentheses. */ + char * + grub_file_get_device_name (const char *name) +@@ -121,6 +129,9 @@ grub_file_open (const char *name, enum grub_file_type type) + if (grub_file_filters[filter]) + { + last_file = file; ++ if (filter < GRUB_FILE_FILTER_MAX) ++ grub_dprintf ("file", "Running %s file filter\n", ++ filter_names[filter]); + file = grub_file_filters[filter] (file, type); + if (file && file != last_file) + { diff --git a/0268-grub_fs_probe-dprint-errors-from-filesystems.patch b/0268-grub_fs_probe-dprint-errors-from-filesystems.patch deleted file mode 100644 index 1455ae4..0000000 --- a/0268-grub_fs_probe-dprint-errors-from-filesystems.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Fri, 15 Jul 2022 15:39:41 -0400 -Subject: [PATCH] grub_fs_probe(): dprint errors from filesystems - -When filesystem detection fails, all that's currently debug-logged is a -series of messages like: - - grub-core/kern/fs.c:56:fs: Detecting ntfs... - grub-core/kern/fs.c:76:fs: ntfs detection failed. - -repeated for each filesystem. Any messages provided to grub_error() by -the filesystem are lost, and one has to break out gdb to figure out what -went wrong. - -With this change, one instead sees: - - grub-core/kern/fs.c:56:fs: Detecting fat... - grub-core/osdep/hostdisk.c:357:hostdisk: reusing open device - `/path/to/device' - grub-core/kern/fs.c:77:fs: error: invalid modification timestamp for /. - grub-core/kern/fs.c:79:fs: fat detection failed. - -in the debug prints. - -Signed-off-by: Robbie Harwood -(cherry picked from commit 838c79d658797d0662ee7f9e033e38ee88059e02) ---- - grub-core/kern/fs.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c -index c698295bcb..b58e2ae1d2 100644 ---- a/grub-core/kern/fs.c -+++ b/grub-core/kern/fs.c -@@ -74,6 +74,7 @@ grub_fs_probe (grub_device_t device) - if (grub_errno == GRUB_ERR_NONE) - return p; - -+ grub_dprintf ("fs", _("error: %s.\n"), grub_errmsg); - grub_error_push (); - grub_dprintf ("fs", "%s detection failed.\n", p->name); - grub_error_pop (); diff --git a/0269-efi-use-enumerated-array-positions-for-our-allocatio.patch b/0269-efi-use-enumerated-array-positions-for-our-allocatio.patch new file mode 100644 index 0000000..206e3a6 --- /dev/null +++ b/0269-efi-use-enumerated-array-positions-for-our-allocatio.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 14:06:30 -0400 +Subject: [PATCH] efi: use enumerated array positions for our allocation + choices + +In our kernel allocator on EFI systems, we currently have a growing +amount of code that references the various allocation policies by +position in the array, and of course maintenance of this code scales +very poorly. + +This patch changes them to be enumerated, so they're easier to refer to +farther along in the code without confusion. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 91ae274299..8daa070132 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -60,17 +60,26 @@ struct allocation_choice { + grub_efi_allocate_type_t alloc_type; + }; + +-static struct allocation_choice max_addresses[4] = ++enum { ++ KERNEL_PREF_ADDRESS, ++ KERNEL_4G_LIMIT, ++ KERNEL_NO_LIMIT, ++}; ++ ++static struct allocation_choice max_addresses[] = + { + /* the kernel overrides this one with pref_address and + * GRUB_EFI_ALLOCATE_ADDRESS */ +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ [KERNEL_PREF_ADDRESS] = ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* If the flag in params is set, this one gets changed to be above 4GB. */ ++ [KERNEL_4G_LIMIT] = ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + /* this one is always below 4GB, which we still *prefer* even if the flag + * is set. */ +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, +- /* If the flag in params is set, this one gets changed to be above 4GB. */ +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, +- { 0, 0 } ++ [KERNEL_NO_LIMIT] = ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { NO_MEM, 0, 0 } + }; + static struct allocation_choice saved_addresses[4]; + +@@ -405,7 +414,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) + { + grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); +- max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS; + } + else + { +@@ -478,11 +487,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); + if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { +- max_addresses[0].addr = lh->pref_address; +- max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; ++ max_addresses[KERNEL_PREF_ADDRESS].addr = lh->pref_address; ++ max_addresses[KERNEL_PREF_ADDRESS].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } +- max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; +- max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_size = lh->init_size; + kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, + N_("can't allocate kernel")); diff --git a/0269-fs-fat-don-t-error-when-mtime-is-0.patch b/0269-fs-fat-don-t-error-when-mtime-is-0.patch deleted file mode 100644 index f014f6c..0000000 --- a/0269-fs-fat-don-t-error-when-mtime-is-0.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Fri, 15 Jul 2022 15:42:41 -0400 -Subject: [PATCH] fs/fat: don't error when mtime is 0 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In the wild, we occasionally see valid ESPs where some file modification times -are 0. For instance: - - ├── [Dec 31 1979] EFI - │ ├── [Dec 31 1979] BOOT - │ │ ├── [Dec 31 1979] BOOTX64.EFI - │ │ └── [Dec 31 1979] fbx64.efi - │ └── [Jun 27 02:41] fedora - │ ├── [Dec 31 1979] BOOTX64.CSV - │ ├── [Dec 31 1979] fonts - │ ├── [Mar 14 03:35] fw - │ │ ├── [Mar 14 03:35] fwupd-359c1169-abd6-4a0d-8bce-e4d4713335c1.cap - │ │ ├── [Mar 14 03:34] fwupd-9d255c4b-2d88-4861-860d-7ee52ade9463.cap - │ │ └── [Mar 14 03:34] fwupd-b36438d8-9128-49d2-b280-487be02d948b.cap - │ ├── [Dec 31 1979] fwupdx64.efi - │ ├── [May 10 10:47] grub.cfg - │ ├── [Jun 3 12:38] grub.cfg.new.new - │ ├── [May 10 10:41] grub.cfg.old - │ ├── [Jun 27 02:41] grubenv - │ ├── [Dec 31 1979] grubx64.efi - │ ├── [Dec 31 1979] mmx64.efi - │ ├── [Dec 31 1979] shim.efi - │ ├── [Dec 31 1979] shimx64.efi - │ └── [Dec 31 1979] shimx64-fedora.efi - └── [Dec 31 1979] FSCK0000.REC - - 5 directories, 17 files - -This causes grub-probe failure, which in turn causes grub-mkconfig -failure. They are valid filesystems that appear intact, and the Linux -FAT stack is able to mount and manipulate them without complaint. - -The check for mtime of 0 has been present since -20def1a3c3952982395cd7c3ea7e78638527962b ("fat: support file -modification times"). - -Signed-off-by: Robbie Harwood -(cherry picked from commit 0615c4887352e32d7bb7198e9ad0d695f9dc2c31) ---- - grub-core/fs/fat.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c -index dd82e4ee35..ff6200c5be 100644 ---- a/grub-core/fs/fat.c -+++ b/grub-core/fs/fat.c -@@ -1027,9 +1027,6 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, - grub_le_to_cpu16 (ctxt.dir.w_date), - &info.mtime); - #endif -- if (info.mtimeset == 0) -- grub_error (GRUB_ERR_OUT_OF_RANGE, -- "invalid modification timestamp for %s", path); - - if (hook (ctxt.filename, &info, hook_data)) - break; diff --git a/0270-Make-debug-file-show-which-file-filters-get-run.patch b/0270-Make-debug-file-show-which-file-filters-get-run.patch deleted file mode 100644 index 4ac32cb..0000000 --- a/0270-Make-debug-file-show-which-file-filters-get-run.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Fri, 29 Jul 2022 15:56:00 -0400 -Subject: [PATCH] Make debug=file show which file filters get run. - -If one of the file filters breaks things, it's hard to figure out where -it has happened. - -This makes grub log which filter is being run, which makes it easier to -figure out where you are in the sequence of events. - -Signed-off-by: Peter Jones ---- - grub-core/kern/file.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c -index ed69fc0f0f..20a4c839aa 100644 ---- a/grub-core/kern/file.c -+++ b/grub-core/kern/file.c -@@ -30,6 +30,14 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void); - - grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; - -+static const char *filter_names[] = { -+ [GRUB_FILE_FILTER_VERIFY] = "GRUB_FILE_FILTER_VERIFY", -+ [GRUB_FILE_FILTER_GZIO] = "GRUB_FILE_FILTER_GZIO", -+ [GRUB_FILE_FILTER_XZIO] = "GRUB_FILE_FILTER_XZIO", -+ [GRUB_FILE_FILTER_LZOPIO] = "GRUB_FILE_FILTER_LZOPIO", -+ [GRUB_FILE_FILTER_MAX] = "GRUB_FILE_FILTER_MAX" -+}; -+ - /* Get the device part of the filename NAME. It is enclosed by parentheses. */ - char * - grub_file_get_device_name (const char *name) -@@ -121,6 +129,9 @@ grub_file_open (const char *name, enum grub_file_type type) - if (grub_file_filters[filter]) - { - last_file = file; -+ if (filter < GRUB_FILE_FILTER_MAX) -+ grub_dprintf ("file", "Running %s file filter\n", -+ filter_names[filter]); - file = grub_file_filters[filter] (file, type); - if (file && file != last_file) - { diff --git a/0270-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch b/0270-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch new file mode 100644 index 0000000..d25cf30 --- /dev/null +++ b/0270-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 14:24:39 -0400 +Subject: [PATCH] efi: split allocation policy for kernel vs initrd memories. + +Currently in our kernel allocator, we use the same set of choices for +all of our various kernel and initramfs allocations, though they do not +have exactly the same constraints. + +This patch adds the concept of an allocation purpose, which currently +can be KERNEL_MEM or INITRD_MEM, and updates kernel_alloc() calls +appropriately, but does not change any current policy decision. It +also adds a few debug prints. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 35 +++++++++++++++++++++++++++-------- + 1 file changed, 27 insertions(+), 8 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 8daa070132..e6b8998e5e 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -55,7 +55,14 @@ struct grub_linuxefi_context { + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + ++typedef enum { ++ NO_MEM, ++ KERNEL_MEM, ++ INITRD_MEM, ++} kernel_alloc_purpose_t; ++ + struct allocation_choice { ++ kernel_alloc_purpose_t purpose; + grub_efi_physical_address_t addr; + grub_efi_allocate_type_t alloc_type; + }; +@@ -64,6 +71,7 @@ enum { + KERNEL_PREF_ADDRESS, + KERNEL_4G_LIMIT, + KERNEL_NO_LIMIT, ++ INITRD_MAX_ADDRESS, + }; + + static struct allocation_choice max_addresses[] = +@@ -71,14 +79,17 @@ static struct allocation_choice max_addresses[] = + /* the kernel overrides this one with pref_address and + * GRUB_EFI_ALLOCATE_ADDRESS */ + [KERNEL_PREF_ADDRESS] = +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + /* If the flag in params is set, this one gets changed to be above 4GB. */ + [KERNEL_4G_LIMIT] = +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + /* this one is always below 4GB, which we still *prefer* even if the flag + * is set. */ + [KERNEL_NO_LIMIT] = +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this is for the initrd */ ++ [INITRD_MAX_ADDRESS] = ++ { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { NO_MEM, 0, 0 } + }; + static struct allocation_choice saved_addresses[4]; +@@ -95,7 +106,8 @@ kernel_free(void *addr, grub_efi_uintn_t size) + } + + static void * +-kernel_alloc(grub_efi_uintn_t size, ++kernel_alloc(kernel_alloc_purpose_t purpose, ++ grub_efi_uintn_t size, + grub_efi_memory_type_t memtype, + const char * const errmsg) + { +@@ -108,6 +120,9 @@ kernel_alloc(grub_efi_uintn_t size, + grub_uint64_t max = max_addresses[i].addr; + grub_efi_uintn_t pages; + ++ if (purpose != max_addresses[i].purpose) ++ continue; ++ + /* + * When we're *not* loading the kernel, or >4GB allocations aren't + * supported, these entries are basically all the same, so don't re-try +@@ -261,7 +276,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ grub_dprintf ("linux", "Trying to allocate initrd mem\n"); ++ initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA, + N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; +@@ -422,7 +438,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA, ++ params = kernel_alloc (KERNEL_MEM, sizeof(*params), ++ GRUB_EFI_RUNTIME_SERVICES_DATA, + "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -445,7 +462,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- cmdline = kernel_alloc (lh->cmdline_size + 1, ++ cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, + GRUB_EFI_RUNTIME_SERVICES_DATA, + N_("can't allocate cmdline")); + if (!cmdline) +@@ -493,7 +510,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_size = lh->init_size; +- kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, ++ grub_dprintf ("linux", "Trying to allocate kernel mem\n"); ++ kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size, ++ GRUB_EFI_RUNTIME_SERVICES_CODE, + N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) diff --git a/0271-efi-allocate-the-initrd-within-the-bounds-expressed-.patch b/0271-efi-allocate-the-initrd-within-the-bounds-expressed-.patch new file mode 100644 index 0000000..47e31e2 --- /dev/null +++ b/0271-efi-allocate-the-initrd-within-the-bounds-expressed-.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 14:07:50 -0400 +Subject: [PATCH] efi: allocate the initrd within the bounds expressed by the + kernel + +Currently on x86, only linux kernels built with CONFIG_RELOCATABLE for +x86_64 can be loaded above 4G, but the maximum address for the initramfs +is specified via a HdrS field. This allows us to utilize that value, +and unless loading the kernel above 4G, uses the value present there. +If loading kernel above 4G is allowed, we assume loading the initramfs +above 4G also works; in practice this has been true in the kernel code +for quite some time. + +Resolves: rhbz#2112134 + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index e6b8998e5e..d003b474ee 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -190,6 +190,8 @@ grub_linuxefi_unload (void *data) + cmd_initrdefi->data = 0; + grub_free (context); + ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ + return GRUB_ERR_NONE; + } + +@@ -426,11 +428,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ max_addresses[INITRD_MAX_ADDRESS].addr = lh->initrd_addr_max; + #if defined(__x86_64__) + if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) + { + grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); + max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_USABLE_ADDRESS; + } + else + { +@@ -560,6 +564,8 @@ fail: + + grub_dl_unref (my_mod); + ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ + if (lh) + kernel_free (cmdline, lh->cmdline_size + 1); + diff --git a/0271-efi-use-enumerated-array-positions-for-our-allocatio.patch b/0271-efi-use-enumerated-array-positions-for-our-allocatio.patch deleted file mode 100644 index 206e3a6..0000000 --- a/0271-efi-use-enumerated-array-positions-for-our-allocatio.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 1 Aug 2022 14:06:30 -0400 -Subject: [PATCH] efi: use enumerated array positions for our allocation - choices - -In our kernel allocator on EFI systems, we currently have a growing -amount of code that references the various allocation policies by -position in the array, and of course maintenance of this code scales -very poorly. - -This patch changes them to be enumerated, so they're easier to refer to -farther along in the code without confusion. - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 31 ++++++++++++++++++++----------- - 1 file changed, 20 insertions(+), 11 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 91ae274299..8daa070132 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -60,17 +60,26 @@ struct allocation_choice { - grub_efi_allocate_type_t alloc_type; - }; - --static struct allocation_choice max_addresses[4] = -+enum { -+ KERNEL_PREF_ADDRESS, -+ KERNEL_4G_LIMIT, -+ KERNEL_NO_LIMIT, -+}; -+ -+static struct allocation_choice max_addresses[] = - { - /* the kernel overrides this one with pref_address and - * GRUB_EFI_ALLOCATE_ADDRESS */ -- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ [KERNEL_PREF_ADDRESS] = -+ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ /* If the flag in params is set, this one gets changed to be above 4GB. */ -+ [KERNEL_4G_LIMIT] = -+ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, - /* this one is always below 4GB, which we still *prefer* even if the flag - * is set. */ -- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -- /* If the flag in params is set, this one gets changed to be above 4GB. */ -- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -- { 0, 0 } -+ [KERNEL_NO_LIMIT] = -+ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ { NO_MEM, 0, 0 } - }; - static struct allocation_choice saved_addresses[4]; - -@@ -405,7 +414,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) - { - grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); -- max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; -+ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS; - } - else - { -@@ -478,11 +487,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); - if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) - { -- max_addresses[0].addr = lh->pref_address; -- max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; -+ max_addresses[KERNEL_PREF_ADDRESS].addr = lh->pref_address; -+ max_addresses[KERNEL_PREF_ADDRESS].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; - } -- max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; -- max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; -+ max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; -+ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; - kernel_size = lh->init_size; - kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, - N_("can't allocate kernel")); diff --git a/0272-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch b/0272-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch deleted file mode 100644 index d25cf30..0000000 --- a/0272-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 1 Aug 2022 14:24:39 -0400 -Subject: [PATCH] efi: split allocation policy for kernel vs initrd memories. - -Currently in our kernel allocator, we use the same set of choices for -all of our various kernel and initramfs allocations, though they do not -have exactly the same constraints. - -This patch adds the concept of an allocation purpose, which currently -can be KERNEL_MEM or INITRD_MEM, and updates kernel_alloc() calls -appropriately, but does not change any current policy decision. It -also adds a few debug prints. - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 35 +++++++++++++++++++++++++++-------- - 1 file changed, 27 insertions(+), 8 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 8daa070132..e6b8998e5e 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -55,7 +55,14 @@ struct grub_linuxefi_context { - - #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) - -+typedef enum { -+ NO_MEM, -+ KERNEL_MEM, -+ INITRD_MEM, -+} kernel_alloc_purpose_t; -+ - struct allocation_choice { -+ kernel_alloc_purpose_t purpose; - grub_efi_physical_address_t addr; - grub_efi_allocate_type_t alloc_type; - }; -@@ -64,6 +71,7 @@ enum { - KERNEL_PREF_ADDRESS, - KERNEL_4G_LIMIT, - KERNEL_NO_LIMIT, -+ INITRD_MAX_ADDRESS, - }; - - static struct allocation_choice max_addresses[] = -@@ -71,14 +79,17 @@ static struct allocation_choice max_addresses[] = - /* the kernel overrides this one with pref_address and - * GRUB_EFI_ALLOCATE_ADDRESS */ - [KERNEL_PREF_ADDRESS] = -- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, - /* If the flag in params is set, this one gets changed to be above 4GB. */ - [KERNEL_4G_LIMIT] = -- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, - /* this one is always below 4GB, which we still *prefer* even if the flag - * is set. */ - [KERNEL_NO_LIMIT] = -- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, -+ /* this is for the initrd */ -+ [INITRD_MAX_ADDRESS] = -+ { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, - { NO_MEM, 0, 0 } - }; - static struct allocation_choice saved_addresses[4]; -@@ -95,7 +106,8 @@ kernel_free(void *addr, grub_efi_uintn_t size) - } - - static void * --kernel_alloc(grub_efi_uintn_t size, -+kernel_alloc(kernel_alloc_purpose_t purpose, -+ grub_efi_uintn_t size, - grub_efi_memory_type_t memtype, - const char * const errmsg) - { -@@ -108,6 +120,9 @@ kernel_alloc(grub_efi_uintn_t size, - grub_uint64_t max = max_addresses[i].addr; - grub_efi_uintn_t pages; - -+ if (purpose != max_addresses[i].purpose) -+ continue; -+ - /* - * When we're *not* loading the kernel, or >4GB allocations aren't - * supported, these entries are basically all the same, so don't re-try -@@ -261,7 +276,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - } - } - -- initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA, -+ grub_dprintf ("linux", "Trying to allocate initrd mem\n"); -+ initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA, - N_("can't allocate initrd")); - if (initrd_mem == NULL) - goto fail; -@@ -422,7 +438,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - #endif - -- params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA, -+ params = kernel_alloc (KERNEL_MEM, sizeof(*params), -+ GRUB_EFI_RUNTIME_SERVICES_DATA, - "cannot allocate kernel parameters"); - if (!params) - goto fail; -@@ -445,7 +462,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_dprintf ("linux", "new lh is at %p\n", lh); - - grub_dprintf ("linux", "setting up cmdline\n"); -- cmdline = kernel_alloc (lh->cmdline_size + 1, -+ cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, - GRUB_EFI_RUNTIME_SERVICES_DATA, - N_("can't allocate cmdline")); - if (!cmdline) -@@ -493,7 +510,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; - max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; - kernel_size = lh->init_size; -- kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, -+ grub_dprintf ("linux", "Trying to allocate kernel mem\n"); -+ kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size, -+ GRUB_EFI_RUNTIME_SERVICES_CODE, - N_("can't allocate kernel")); - restore_addresses(); - if (!kernel_mem) diff --git a/0272-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch b/0272-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch new file mode 100644 index 0000000..8451dbf --- /dev/null +++ b/0272-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 13:04:43 -0400 +Subject: [PATCH] efi: use EFI_LOADER_(CODE|DATA) for kernel and initrd + allocations + +At some point due to an erroneous kernel warning, we switched kernel and +initramfs to being loaded in EFI_RUNTIME_SERVICES_CODE and +EFI_RUNTIME_SERVICES_DATA memory pools. This doesn't appear to be +correct according to the spec, and that kernel warning has gone away. + +This patch puts them back in EFI_LOADER_CODE and EFI_LOADER_DATA +allocations, respectively. + +Resolves: rhbz#2108456 + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d003b474ee..ac5ef50bdb 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -279,7 +279,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + + grub_dprintf ("linux", "Trying to allocate initrd mem\n"); +- initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_LOADER_DATA, + N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; +@@ -443,7 +443,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + #endif + + params = kernel_alloc (KERNEL_MEM, sizeof(*params), +- GRUB_EFI_RUNTIME_SERVICES_DATA, ++ GRUB_EFI_LOADER_DATA, + "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -467,7 +467,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "setting up cmdline\n"); + cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, +- GRUB_EFI_RUNTIME_SERVICES_DATA, ++ GRUB_EFI_LOADER_DATA, + N_("can't allocate cmdline")); + if (!cmdline) + goto fail; +@@ -516,7 +516,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + kernel_size = lh->init_size; + grub_dprintf ("linux", "Trying to allocate kernel mem\n"); + kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size, +- GRUB_EFI_RUNTIME_SERVICES_CODE, ++ GRUB_EFI_LOADER_CODE, + N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) diff --git a/0273-BLS-create-etc-kernel-cmdline-during-mkconfig.patch b/0273-BLS-create-etc-kernel-cmdline-during-mkconfig.patch new file mode 100644 index 0000000..50ba0fb --- /dev/null +++ b/0273-BLS-create-etc-kernel-cmdline-during-mkconfig.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 2 Aug 2022 15:56:28 -0400 +Subject: [PATCH] BLS: create /etc/kernel/cmdline during mkconfig + +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_linux.in | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 865af3d6c4..9ebff661a9 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -161,6 +161,12 @@ update_bls_cmdline() + local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + local -a files=($(get_sorted_bls)) + ++ if [[ ! -f /etc/kernel/cmdline ]]; then ++ # anaconda has the correct information to do this during install; ++ # afterward, grubby will take care of syncing on updates. ++ echo "$cmdline rhgb quiet" > /etc/kernel/cmdline ++ fi ++ + for bls in "${files[@]}"; do + local options="${cmdline}" + if [ -z "${bls##*debug*}" ]; then diff --git a/0273-efi-allocate-the-initrd-within-the-bounds-expressed-.patch b/0273-efi-allocate-the-initrd-within-the-bounds-expressed-.patch deleted file mode 100644 index 47e31e2..0000000 --- a/0273-efi-allocate-the-initrd-within-the-bounds-expressed-.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 1 Aug 2022 14:07:50 -0400 -Subject: [PATCH] efi: allocate the initrd within the bounds expressed by the - kernel - -Currently on x86, only linux kernels built with CONFIG_RELOCATABLE for -x86_64 can be loaded above 4G, but the maximum address for the initramfs -is specified via a HdrS field. This allows us to utilize that value, -and unless loading the kernel above 4G, uses the value present there. -If loading kernel above 4G is allowed, we assume loading the initramfs -above 4G also works; in practice this has been true in the kernel code -for quite some time. - -Resolves: rhbz#2112134 - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index e6b8998e5e..d003b474ee 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -190,6 +190,8 @@ grub_linuxefi_unload (void *data) - cmd_initrdefi->data = 0; - grub_free (context); - -+ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; -+ - return GRUB_ERR_NONE; - } - -@@ -426,11 +428,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - } - #endif - -+ max_addresses[INITRD_MAX_ADDRESS].addr = lh->initrd_addr_max; - #if defined(__x86_64__) - if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) - { - grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); - max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS; -+ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_USABLE_ADDRESS; - } - else - { -@@ -560,6 +564,8 @@ fail: - - grub_dl_unref (my_mod); - -+ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; -+ - if (lh) - kernel_free (cmdline, lh->cmdline_size + 1); - diff --git a/0274-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch b/0274-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch deleted file mode 100644 index 8451dbf..0000000 --- a/0274-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Mon, 1 Aug 2022 13:04:43 -0400 -Subject: [PATCH] efi: use EFI_LOADER_(CODE|DATA) for kernel and initrd - allocations - -At some point due to an erroneous kernel warning, we switched kernel and -initramfs to being loaded in EFI_RUNTIME_SERVICES_CODE and -EFI_RUNTIME_SERVICES_DATA memory pools. This doesn't appear to be -correct according to the spec, and that kernel warning has gone away. - -This patch puts them back in EFI_LOADER_CODE and EFI_LOADER_DATA -allocations, respectively. - -Resolves: rhbz#2108456 - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index d003b474ee..ac5ef50bdb 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -279,7 +279,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) - } - - grub_dprintf ("linux", "Trying to allocate initrd mem\n"); -- initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA, -+ initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_LOADER_DATA, - N_("can't allocate initrd")); - if (initrd_mem == NULL) - goto fail; -@@ -443,7 +443,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - #endif - - params = kernel_alloc (KERNEL_MEM, sizeof(*params), -- GRUB_EFI_RUNTIME_SERVICES_DATA, -+ GRUB_EFI_LOADER_DATA, - "cannot allocate kernel parameters"); - if (!params) - goto fail; -@@ -467,7 +467,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - grub_dprintf ("linux", "setting up cmdline\n"); - cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, -- GRUB_EFI_RUNTIME_SERVICES_DATA, -+ GRUB_EFI_LOADER_DATA, - N_("can't allocate cmdline")); - if (!cmdline) - goto fail; -@@ -516,7 +516,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - kernel_size = lh->init_size; - grub_dprintf ("linux", "Trying to allocate kernel mem\n"); - kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size, -- GRUB_EFI_RUNTIME_SERVICES_CODE, -+ GRUB_EFI_LOADER_CODE, - N_("can't allocate kernel")); - restore_addresses(); - if (!kernel_mem) diff --git a/0274-squish-don-t-dup-rhgb-quiet-check-mtimes.patch b/0274-squish-don-t-dup-rhgb-quiet-check-mtimes.patch new file mode 100644 index 0000000..67073ec --- /dev/null +++ b/0274-squish-don-t-dup-rhgb-quiet-check-mtimes.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 17 Aug 2022 10:26:07 -0400 +Subject: [PATCH] squish: don't dup rhgb quiet, check mtimes + +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_linux.in | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 9ebff661a9..41c6cb1dc2 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -161,10 +161,16 @@ update_bls_cmdline() + local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + local -a files=($(get_sorted_bls)) + +- if [[ ! -f /etc/kernel/cmdline ]]; then +- # anaconda has the correct information to do this during install; +- # afterward, grubby will take care of syncing on updates. +- echo "$cmdline rhgb quiet" > /etc/kernel/cmdline ++ if [[ ! -f /etc/kernel/cmdline ]] || ++ [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then ++ # anaconda has the correct information to create this during install; ++ # afterward, grubby will take care of syncing on updates. If the user ++ # has modified /etc/default/grub, try to cope. ++ if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then ++ # ensure these only show up once ++ cmdline="$cmdline rhgb quiet" ++ fi ++ echo "$cmdline" > /etc/kernel/cmdline + fi + + for bls in "${files[@]}"; do diff --git a/0275-BLS-create-etc-kernel-cmdline-during-mkconfig.patch b/0275-BLS-create-etc-kernel-cmdline-during-mkconfig.patch deleted file mode 100644 index 7080b6f..0000000 --- a/0275-BLS-create-etc-kernel-cmdline-during-mkconfig.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Tue, 2 Aug 2022 15:56:28 -0400 -Subject: [PATCH] BLS: create /etc/kernel/cmdline during mkconfig - -Signed-off-by: Robbie Harwood ---- - util/grub.d/10_linux.in | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index 6af84b44e1..950a92f5e8 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -161,6 +161,12 @@ update_bls_cmdline() - local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" - local -a files=($(get_sorted_bls)) - -+ if [[ ! -f /etc/kernel/cmdline ]]; then -+ # anaconda has the correct information to do this during install; -+ # afterward, grubby will take care of syncing on updates. -+ echo "$cmdline rhgb quiet" > /etc/kernel/cmdline -+ fi -+ - for bls in "${files[@]}"; do - local options="${cmdline}" - if [ -z "${bls##*debug*}" ]; then diff --git a/0275-squish-give-up-on-rhgb-quiet.patch b/0275-squish-give-up-on-rhgb-quiet.patch new file mode 100644 index 0000000..5858c91 --- /dev/null +++ b/0275-squish-give-up-on-rhgb-quiet.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 17 Aug 2022 11:30:30 -0400 +Subject: [PATCH] squish: give up on rhgb quiet + +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_linux.in | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 41c6cb1dc2..5d1fa072f2 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -166,10 +166,6 @@ update_bls_cmdline() + # anaconda has the correct information to create this during install; + # afterward, grubby will take care of syncing on updates. If the user + # has modified /etc/default/grub, try to cope. +- if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then +- # ensure these only show up once +- cmdline="$cmdline rhgb quiet" +- fi + echo "$cmdline" > /etc/kernel/cmdline + fi + diff --git a/0276-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch b/0276-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch new file mode 100644 index 0000000..d5ac923 --- /dev/null +++ b/0276-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon +Date: Wed, 17 Aug 2022 10:26:03 -0400 +Subject: [PATCH] squish: BLS: only write /etc/kernel/cmdline if writable + +On OSTree systems, `grub2-mkconfig` is run with `/etc` mounted read-only +because as part of the promise of transactional updates, we want to make +sure that we're not modifying the current deployment's state (`/etc` or +`/var`). + +This conflicts with 0837dcdf1 ("BLS: create /etc/kernel/cmdline during +mkconfig") which wants to write to `/etc/kernel/cmdline`. I'm not +exactly sure on the background there, but based on the comment I think +the intent is to fulfill grubby's expectation that the file exists. + +However, in systems like Silverblue, kernel arguments are managed by the +rpm-ostree stack and grubby is not shipped at all. + +Adjust the script slightly so that we only write `/etc/kernel/cmdline` +if the parent directory is writable. + +In the future, we're hoping to simplify things further on rpm-ostree +systems by not running `grub2-mkconfig` at all since libostree already +directly writes BLS entries. Doing that would also have avoided this, +but ratcheting it into existing systems needs more careful thought. + +Signed-off-by: Jonathan Lebon + +Fixes: https://github.com/fedora-silverblue/issue-tracker/issues/322 +--- + util/grub.d/10_linux.in | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 5d1fa072f2..4795a63b4c 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -161,12 +161,13 @@ update_bls_cmdline() + local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + local -a files=($(get_sorted_bls)) + +- if [[ ! -f /etc/kernel/cmdline ]] || +- [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then +- # anaconda has the correct information to create this during install; +- # afterward, grubby will take care of syncing on updates. If the user +- # has modified /etc/default/grub, try to cope. +- echo "$cmdline" > /etc/kernel/cmdline ++ if [ -w /etc/kernel ] && ++ [[ ! -f /etc/kernel/cmdline || ++ /etc/kernel/cmdline -ot /etc/default/grub ]]; then ++ # anaconda has the correct information to create this during install; ++ # afterward, grubby will take care of syncing on updates. If the user ++ # has modified /etc/default/grub, try to cope. ++ echo "$cmdline" > /etc/kernel/cmdline + fi + + for bls in "${files[@]}"; do diff --git a/0276-squish-don-t-dup-rhgb-quiet-check-mtimes.patch b/0276-squish-don-t-dup-rhgb-quiet-check-mtimes.patch deleted file mode 100644 index 013b915..0000000 --- a/0276-squish-don-t-dup-rhgb-quiet-check-mtimes.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Wed, 17 Aug 2022 10:26:07 -0400 -Subject: [PATCH] squish: don't dup rhgb quiet, check mtimes - -Signed-off-by: Robbie Harwood ---- - util/grub.d/10_linux.in | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index 950a92f5e8..03f091a4dc 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -161,10 +161,16 @@ update_bls_cmdline() - local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" - local -a files=($(get_sorted_bls)) - -- if [[ ! -f /etc/kernel/cmdline ]]; then -- # anaconda has the correct information to do this during install; -- # afterward, grubby will take care of syncing on updates. -- echo "$cmdline rhgb quiet" > /etc/kernel/cmdline -+ if [[ ! -f /etc/kernel/cmdline ]] || -+ [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then -+ # anaconda has the correct information to create this during install; -+ # afterward, grubby will take care of syncing on updates. If the user -+ # has modified /etc/default/grub, try to cope. -+ if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then -+ # ensure these only show up once -+ cmdline="$cmdline rhgb quiet" -+ fi -+ echo "$cmdline" > /etc/kernel/cmdline - fi - - for bls in "${files[@]}"; do diff --git a/0277-ieee1275-implement-vec5-for-cas-negotiation.patch b/0277-ieee1275-implement-vec5-for-cas-negotiation.patch new file mode 100644 index 0000000..2749d10 --- /dev/null +++ b/0277-ieee1275-implement-vec5-for-cas-negotiation.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Thu, 25 Aug 2022 11:37:56 -0400 +Subject: [PATCH] ieee1275: implement vec5 for cas negotiation + +As a legacy support, if the vector 5 is not implemented, Power +Hypervisor will consider the max CPUs as 64 instead 256 currently +supported during client-architecture-support negotiation. + +This patch implements the vector 5 and set the MAX CPUs to 256 while +setting the others values to 0 (default). + +Signed-off-by: Diego Domingos +Signed-off-by: Robbie Harwood +--- + grub-core/kern/ieee1275/init.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index ef55107467..6a51c9efab 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -311,6 +311,18 @@ struct option_vector2 { + grub_uint8_t max_pft_size; + } __attribute__((packed)); + ++struct option_vector5 { ++ grub_uint8_t byte1; ++ grub_uint8_t byte2; ++ grub_uint8_t byte3; ++ grub_uint8_t cmo; ++ grub_uint8_t associativity; ++ grub_uint8_t bin_opts; ++ grub_uint8_t micro_checkpoint; ++ grub_uint8_t reserved0; ++ grub_uint32_t max_cpus; ++} __attribute__((packed)); ++ + struct pvr_entry { + grub_uint32_t mask; + grub_uint32_t entry; +@@ -329,6 +341,8 @@ struct cas_vector { + grub_uint16_t vec3; + grub_uint8_t vec4_size; + grub_uint16_t vec4; ++ grub_uint8_t vec5_size; ++ struct option_vector5 vec5; + } __attribute__((packed)); + + /* Call ibm,client-architecture-support to try to get more RMA. +@@ -349,7 +363,7 @@ grub_ieee1275_ibm_cas (void) + } args; + struct cas_vector vector = { + .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +- .num_vecs = 4 - 1, ++ .num_vecs = 5 - 1, + .vec1_size = 0, + .vec1 = 0x80, /* ignore */ + .vec2_size = 1 + sizeof(struct option_vector2) - 2, +@@ -360,6 +374,10 @@ grub_ieee1275_ibm_cas (void) + .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied + .vec4_size = 2 - 1, + .vec4 = 0x0001, // set required minimum capacity % to the lowest value ++ .vec5_size = 1 + sizeof(struct option_vector5) - 2, ++ .vec5 = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 256 ++ } + }; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); diff --git a/0277-squish-give-up-on-rhgb-quiet.patch b/0277-squish-give-up-on-rhgb-quiet.patch deleted file mode 100644 index bbead5e..0000000 --- a/0277-squish-give-up-on-rhgb-quiet.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Wed, 17 Aug 2022 11:30:30 -0400 -Subject: [PATCH] squish: give up on rhgb quiet - -Signed-off-by: Robbie Harwood ---- - util/grub.d/10_linux.in | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index 03f091a4dc..5ad624bfec 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -166,10 +166,6 @@ update_bls_cmdline() - # anaconda has the correct information to create this during install; - # afterward, grubby will take care of syncing on updates. If the user - # has modified /etc/default/grub, try to cope. -- if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then -- # ensure these only show up once -- cmdline="$cmdline rhgb quiet" -- fi - echo "$cmdline" > /etc/kernel/cmdline - fi - diff --git a/0278-blscfg-Don-t-root-device-in-emu-builds.patch b/0278-blscfg-Don-t-root-device-in-emu-builds.patch new file mode 100644 index 0000000..3fe8baf --- /dev/null +++ b/0278-blscfg-Don-t-root-device-in-emu-builds.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Thu, 25 Aug 2022 17:57:55 -0400 +Subject: [PATCH] blscfg: Don't root device in emu builds + +Otherwise, we end up looking for kernel/initrd in /boot/boot which +doesn't work at all. Non-emu builds need to be looking in +($root)/boot/, which is what this is for. + +Signed-off-by: Robbie Harwood +--- + grub-core/commands/blscfg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +index e907a6a5d2..dbd0899acf 100644 +--- a/grub-core/commands/blscfg.c ++++ b/grub-core/commands/blscfg.c +@@ -41,7 +41,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + #define GRUB_BLS_CONFIG_PATH "/loader/entries/" + #ifdef GRUB_MACHINE_EMU +-#define GRUB_BOOT_DEVICE "/boot" ++#define GRUB_BOOT_DEVICE "" + #else + #define GRUB_BOOT_DEVICE "($root)" + #endif diff --git a/0278-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch b/0278-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch deleted file mode 100644 index ed378b8..0000000 --- a/0278-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jonathan Lebon -Date: Wed, 17 Aug 2022 10:26:03 -0400 -Subject: [PATCH] squish: BLS: only write /etc/kernel/cmdline if writable - -On OSTree systems, `grub2-mkconfig` is run with `/etc` mounted read-only -because as part of the promise of transactional updates, we want to make -sure that we're not modifying the current deployment's state (`/etc` or -`/var`). - -This conflicts with 0837dcdf1 ("BLS: create /etc/kernel/cmdline during -mkconfig") which wants to write to `/etc/kernel/cmdline`. I'm not -exactly sure on the background there, but based on the comment I think -the intent is to fulfill grubby's expectation that the file exists. - -However, in systems like Silverblue, kernel arguments are managed by the -rpm-ostree stack and grubby is not shipped at all. - -Adjust the script slightly so that we only write `/etc/kernel/cmdline` -if the parent directory is writable. - -In the future, we're hoping to simplify things further on rpm-ostree -systems by not running `grub2-mkconfig` at all since libostree already -directly writes BLS entries. Doing that would also have avoided this, -but ratcheting it into existing systems needs more careful thought. - -Signed-off-by: Jonathan Lebon - -Fixes: https://github.com/fedora-silverblue/issue-tracker/issues/322 ---- - util/grub.d/10_linux.in | 13 +++++++------ - 1 file changed, 7 insertions(+), 6 deletions(-) - -diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in -index 5ad624bfec..e5e87a6d80 100644 ---- a/util/grub.d/10_linux.in -+++ b/util/grub.d/10_linux.in -@@ -161,12 +161,13 @@ update_bls_cmdline() - local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" - local -a files=($(get_sorted_bls)) - -- if [[ ! -f /etc/kernel/cmdline ]] || -- [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then -- # anaconda has the correct information to create this during install; -- # afterward, grubby will take care of syncing on updates. If the user -- # has modified /etc/default/grub, try to cope. -- echo "$cmdline" > /etc/kernel/cmdline -+ if [ -w /etc/kernel ] && -+ [[ ! -f /etc/kernel/cmdline || -+ /etc/kernel/cmdline -ot /etc/default/grub ]]; then -+ # anaconda has the correct information to create this during install; -+ # afterward, grubby will take care of syncing on updates. If the user -+ # has modified /etc/default/grub, try to cope. -+ echo "$cmdline" > /etc/kernel/cmdline - fi - - for bls in "${files[@]}"; do diff --git a/0279-ieee1275-implement-vec5-for-cas-negotiation.patch b/0279-ieee1275-implement-vec5-for-cas-negotiation.patch deleted file mode 100644 index 2749d10..0000000 --- a/0279-ieee1275-implement-vec5-for-cas-negotiation.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Diego Domingos -Date: Thu, 25 Aug 2022 11:37:56 -0400 -Subject: [PATCH] ieee1275: implement vec5 for cas negotiation - -As a legacy support, if the vector 5 is not implemented, Power -Hypervisor will consider the max CPUs as 64 instead 256 currently -supported during client-architecture-support negotiation. - -This patch implements the vector 5 and set the MAX CPUs to 256 while -setting the others values to 0 (default). - -Signed-off-by: Diego Domingos -Signed-off-by: Robbie Harwood ---- - grub-core/kern/ieee1275/init.c | 20 +++++++++++++++++++- - 1 file changed, 19 insertions(+), 1 deletion(-) - -diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c -index ef55107467..6a51c9efab 100644 ---- a/grub-core/kern/ieee1275/init.c -+++ b/grub-core/kern/ieee1275/init.c -@@ -311,6 +311,18 @@ struct option_vector2 { - grub_uint8_t max_pft_size; - } __attribute__((packed)); - -+struct option_vector5 { -+ grub_uint8_t byte1; -+ grub_uint8_t byte2; -+ grub_uint8_t byte3; -+ grub_uint8_t cmo; -+ grub_uint8_t associativity; -+ grub_uint8_t bin_opts; -+ grub_uint8_t micro_checkpoint; -+ grub_uint8_t reserved0; -+ grub_uint32_t max_cpus; -+} __attribute__((packed)); -+ - struct pvr_entry { - grub_uint32_t mask; - grub_uint32_t entry; -@@ -329,6 +341,8 @@ struct cas_vector { - grub_uint16_t vec3; - grub_uint8_t vec4_size; - grub_uint16_t vec4; -+ grub_uint8_t vec5_size; -+ struct option_vector5 vec5; - } __attribute__((packed)); - - /* Call ibm,client-architecture-support to try to get more RMA. -@@ -349,7 +363,7 @@ grub_ieee1275_ibm_cas (void) - } args; - struct cas_vector vector = { - .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ -- .num_vecs = 4 - 1, -+ .num_vecs = 5 - 1, - .vec1_size = 0, - .vec1 = 0x80, /* ignore */ - .vec2_size = 1 + sizeof(struct option_vector2) - 2, -@@ -360,6 +374,10 @@ grub_ieee1275_ibm_cas (void) - .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied - .vec4_size = 2 - 1, - .vec4 = 0x0001, // set required minimum capacity % to the lowest value -+ .vec5_size = 1 + sizeof(struct option_vector5) - 2, -+ .vec5 = { -+ 0, 0, 0, 0, 0, 0, 0, 0, 256 -+ } - }; - - INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); diff --git a/0279-loader-arm64-linux-Remove-magic-number-header-field-.patch b/0279-loader-arm64-linux-Remove-magic-number-header-field-.patch new file mode 100644 index 0000000..faaa071 --- /dev/null +++ b/0279-loader-arm64-linux-Remove-magic-number-header-field-.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Thu, 11 Aug 2022 16:51:57 +0200 +Subject: [PATCH] loader/arm64/linux: Remove magic number header field check + +The "ARM\x64" magic number in the file header identifies an image as one +that implements the bare metal boot protocol, allowing the loader to +simply move the file to a suitably aligned address in memory, with +sufficient headroom for the trailing .bss segment (the required memory +size is described in the header as well). + +Note of this matters for GRUB, as it only supports EFI boot. EFI does +not care about this magic number, and nor should GRUB: this prevents us +from booting other PE linux images, such as the generic EFI zboot +decompressor, which is a pure PE/COFF image, and does not implement the +bare metal boot protocol. + +So drop the magic number check. + +Signed-off-by: Ard Biesheuvel +Reviewed-by: Daniel Kiper +Resolves: rhbz#2125069 +Signed-off-by: Jeremy Linton +(cherry-picked from commit 69edb31205602c29293a8c6e67363bba2a4a1e66) +Signed-off-by: Robbie Harwood +--- + grub-core/loader/arm64/linux.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index de85583487..489d0c7173 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -55,9 +55,6 @@ static grub_addr_t initrd_end; + grub_err_t + grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) + { +- if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) +- return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); +- + if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); diff --git a/0280-Correct-BSS-zeroing-on-aarch64.patch b/0280-Correct-BSS-zeroing-on-aarch64.patch new file mode 100644 index 0000000..4f9a2b7 --- /dev/null +++ b/0280-Correct-BSS-zeroing-on-aarch64.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Linton +Date: Tue, 6 Sep 2022 15:33:03 -0500 +Subject: [PATCH] Correct BSS zeroing on aarch64 + +The aarch64 loader doesn't use efi bootservices, and +therefor it has a very minimal loader which makes a lot +of assumptions about the kernel layout. With the ZBOOT +changes, the layout has changed a bit and we not should +really be parsing the PE sections to determine how much +data to copy, otherwise the BSS won't be setup properly. + +This code still makes a lot of assumptions about the +the kernel layout, so its far from ideal, but it works. + +Resolves: rhbz#2125069 + +Signed-off-by: Jeremy Linton +--- + grub-core/loader/arm64/linux.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 489d0c7173..419f2201df 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -316,10 +316,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + static grub_err_t + parse_pe_header (void *kernel, grub_uint64_t *total_size, + grub_uint32_t *entry_offset, +- grub_uint32_t *alignment) ++ grub_uint32_t *alignment,grub_uint32_t *code_size) + { + struct linux_arch_kernel_header *lh = kernel; + struct grub_armxx_linux_pe_header *pe; ++ grub_uint16_t i; ++ struct grub_pe32_section_table *sections; + + pe = (void *)((unsigned long)kernel + lh->hdr_offset); + +@@ -329,6 +331,19 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size, + *total_size = pe->opt.image_size; + *entry_offset = pe->opt.entry_addr; + *alignment = pe->opt.section_alignment; ++ *code_size = pe->opt.section_alignment; ++ ++ sections = (struct grub_pe32_section_table *) ((char *)&pe->opt + ++ pe->coff.optional_header_size); ++ grub_dprintf ("linux", "num_sections : %d\n", pe->coff.num_sections ); ++ for (i = 0 ; i < pe->coff.num_sections; i++) ++ { ++ grub_dprintf ("linux", "raw_size : %lld\n", ++ (long long) sections[i].raw_data_size); ++ grub_dprintf ("linux", "virt_size : %lld\n", ++ (long long) sections[i].virtual_size); ++ *code_size += sections[i].raw_data_size; ++ } + + return GRUB_ERR_NONE; + } +@@ -341,6 +356,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_err_t err; + grub_off_t filelen; + grub_uint32_t align; ++ grub_uint32_t code_size; + void *kernel = NULL; + int nx_supported = 1; + +@@ -373,11 +389,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) + goto fail; +- if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) ++ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align, &code_size) != GRUB_ERR_NONE) + goto fail; + grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); + grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); + grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); ++ grub_dprintf ("linux", "kernel size : 0x%x\n", code_size); + + err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); + if (err != GRUB_ERR_NONE) +@@ -396,9 +413,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); +- grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size)); +- if (kernel_size > filelen) +- grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen); ++ grub_memcpy (kernel_addr, kernel, grub_min(code_size, kernel_size)); ++ if (kernel_size > code_size) ++ grub_memset ((char *)kernel_addr + code_size, 0, kernel_size - code_size); + grub_free(kernel); + kernel = NULL; + diff --git a/0280-blscfg-Don-t-root-device-in-emu-builds.patch b/0280-blscfg-Don-t-root-device-in-emu-builds.patch deleted file mode 100644 index 3fe8baf..0000000 --- a/0280-blscfg-Don-t-root-device-in-emu-builds.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Thu, 25 Aug 2022 17:57:55 -0400 -Subject: [PATCH] blscfg: Don't root device in emu builds - -Otherwise, we end up looking for kernel/initrd in /boot/boot which -doesn't work at all. Non-emu builds need to be looking in -($root)/boot/, which is what this is for. - -Signed-off-by: Robbie Harwood ---- - grub-core/commands/blscfg.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c -index e907a6a5d2..dbd0899acf 100644 ---- a/grub-core/commands/blscfg.c -+++ b/grub-core/commands/blscfg.c -@@ -41,7 +41,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); - - #define GRUB_BLS_CONFIG_PATH "/loader/entries/" - #ifdef GRUB_MACHINE_EMU --#define GRUB_BOOT_DEVICE "/boot" -+#define GRUB_BOOT_DEVICE "" - #else - #define GRUB_BOOT_DEVICE "($root)" - #endif diff --git a/0281-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch b/0281-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch new file mode 100644 index 0000000..eff155d --- /dev/null +++ b/0281-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dann frazier +Date: Thu, 25 Aug 2022 17:08:09 -0600 +Subject: [PATCH] linuxefi: Invalidate i-cache before starting the kernel + +We need to flush the memory range of the code we are about to execute +from the instruction cache before we can safely execute it. Not doing +so appears to be the source of rare synchronous exceptions a user +is seeing on a Cortex-A72-based platform while executing the Linux EFI +stub. Notably they seem to correlate with an instruction on a cache +line boundary. + +Signed-off-by: dann frazier +--- + grub-core/loader/efi/linux.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 277f352e0c..e413bdcc23 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -16,6 +16,7 @@ + * along with GRUB. If not, see . + */ + ++#include + #include + #include + #include +@@ -210,6 +211,9 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, + asm volatile ("cli"); + #endif + ++ /* Invalidate the instruction cache */ ++ grub_arch_sync_caches((void *)kernel_addr, kernel_size); ++ + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + diff --git a/0281-loader-arm64-linux-Remove-magic-number-header-field-.patch b/0281-loader-arm64-linux-Remove-magic-number-header-field-.patch deleted file mode 100644 index faaa071..0000000 --- a/0281-loader-arm64-linux-Remove-magic-number-header-field-.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ard Biesheuvel -Date: Thu, 11 Aug 2022 16:51:57 +0200 -Subject: [PATCH] loader/arm64/linux: Remove magic number header field check - -The "ARM\x64" magic number in the file header identifies an image as one -that implements the bare metal boot protocol, allowing the loader to -simply move the file to a suitably aligned address in memory, with -sufficient headroom for the trailing .bss segment (the required memory -size is described in the header as well). - -Note of this matters for GRUB, as it only supports EFI boot. EFI does -not care about this magic number, and nor should GRUB: this prevents us -from booting other PE linux images, such as the generic EFI zboot -decompressor, which is a pure PE/COFF image, and does not implement the -bare metal boot protocol. - -So drop the magic number check. - -Signed-off-by: Ard Biesheuvel -Reviewed-by: Daniel Kiper -Resolves: rhbz#2125069 -Signed-off-by: Jeremy Linton -(cherry-picked from commit 69edb31205602c29293a8c6e67363bba2a4a1e66) -Signed-off-by: Robbie Harwood ---- - grub-core/loader/arm64/linux.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index de85583487..489d0c7173 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -55,9 +55,6 @@ static grub_addr_t initrd_end; - grub_err_t - grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) - { -- if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) -- return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); -- - if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); diff --git a/0282-Correct-BSS-zeroing-on-aarch64.patch b/0282-Correct-BSS-zeroing-on-aarch64.patch deleted file mode 100644 index 4f9a2b7..0000000 --- a/0282-Correct-BSS-zeroing-on-aarch64.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeremy Linton -Date: Tue, 6 Sep 2022 15:33:03 -0500 -Subject: [PATCH] Correct BSS zeroing on aarch64 - -The aarch64 loader doesn't use efi bootservices, and -therefor it has a very minimal loader which makes a lot -of assumptions about the kernel layout. With the ZBOOT -changes, the layout has changed a bit and we not should -really be parsing the PE sections to determine how much -data to copy, otherwise the BSS won't be setup properly. - -This code still makes a lot of assumptions about the -the kernel layout, so its far from ideal, but it works. - -Resolves: rhbz#2125069 - -Signed-off-by: Jeremy Linton ---- - grub-core/loader/arm64/linux.c | 27 ++++++++++++++++++++++----- - 1 file changed, 22 insertions(+), 5 deletions(-) - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index 489d0c7173..419f2201df 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -316,10 +316,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - static grub_err_t - parse_pe_header (void *kernel, grub_uint64_t *total_size, - grub_uint32_t *entry_offset, -- grub_uint32_t *alignment) -+ grub_uint32_t *alignment,grub_uint32_t *code_size) - { - struct linux_arch_kernel_header *lh = kernel; - struct grub_armxx_linux_pe_header *pe; -+ grub_uint16_t i; -+ struct grub_pe32_section_table *sections; - - pe = (void *)((unsigned long)kernel + lh->hdr_offset); - -@@ -329,6 +331,19 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size, - *total_size = pe->opt.image_size; - *entry_offset = pe->opt.entry_addr; - *alignment = pe->opt.section_alignment; -+ *code_size = pe->opt.section_alignment; -+ -+ sections = (struct grub_pe32_section_table *) ((char *)&pe->opt + -+ pe->coff.optional_header_size); -+ grub_dprintf ("linux", "num_sections : %d\n", pe->coff.num_sections ); -+ for (i = 0 ; i < pe->coff.num_sections; i++) -+ { -+ grub_dprintf ("linux", "raw_size : %lld\n", -+ (long long) sections[i].raw_data_size); -+ grub_dprintf ("linux", "virt_size : %lld\n", -+ (long long) sections[i].virtual_size); -+ *code_size += sections[i].raw_data_size; -+ } - - return GRUB_ERR_NONE; - } -@@ -341,6 +356,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - grub_err_t err; - grub_off_t filelen; - grub_uint32_t align; -+ grub_uint32_t code_size; - void *kernel = NULL; - int nx_supported = 1; - -@@ -373,11 +389,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) - goto fail; -- if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) -+ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align, &code_size) != GRUB_ERR_NONE) - goto fail; - grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); - grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); - grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); -+ grub_dprintf ("linux", "kernel size : 0x%x\n", code_size); - - err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); - if (err != GRUB_ERR_NONE) -@@ -396,9 +413,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); - - grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); -- grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size)); -- if (kernel_size > filelen) -- grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen); -+ grub_memcpy (kernel_addr, kernel, grub_min(code_size, kernel_size)); -+ if (kernel_size > code_size) -+ grub_memset ((char *)kernel_addr + code_size, 0, kernel_size - code_size); - grub_free(kernel); - kernel = NULL; - diff --git a/0282-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch b/0282-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch new file mode 100644 index 0000000..0079750 --- /dev/null +++ b/0282-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 11 Oct 2022 17:00:50 -0400 +Subject: [PATCH] x86-efi: Fix an incorrect array size in kernel allocation + +In 81a6ebf62bbe166ddc968463df2e8bd481bf697c ("efi: split allocation +policy for kernel vs initrd memories."), I introduced a split in the +kernel allocator to allow for different dynamic policies for the kernel +and the initrd allocations. + +Unfortunately, that change increased the size of the policy data used to +make decisions, but did not change the size of the temporary storage we +use to back it up and restore. This results in some of .data getting +clobbered at runtime, and hilarity ensues. + +This patch makes the size of the backup storage be based on the size of +the initial policy data. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index ac5ef50bdb..9854b0defa 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -92,7 +92,7 @@ static struct allocation_choice max_addresses[] = + { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { NO_MEM, 0, 0 } + }; +-static struct allocation_choice saved_addresses[4]; ++static struct allocation_choice saved_addresses[sizeof(max_addresses) / sizeof(max_addresses[0])]; + + #define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) + #define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) diff --git a/0283-commands-efi-tpm-Refine-the-status-of-log-event.patch b/0283-commands-efi-tpm-Refine-the-status-of-log-event.patch new file mode 100644 index 0000000..896e49b --- /dev/null +++ b/0283-commands-efi-tpm-Refine-the-status-of-log-event.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:10 +0800 +Subject: [PATCH] commands/efi/tpm: Refine the status of log event + +1. Use macro GRUB_ERR_NONE instead of hard code 0. +2. Keep lowercase of the first char for the status string of log event. + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +(cherry picked from commit 922898573e37135f5dedc16f3e15a1d1d4c53f8a) +--- + grub-core/commands/efi/tpm.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index a97d85368a..7acf510499 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -135,17 +135,17 @@ grub_efi_log_event_status (grub_efi_status_t status) + switch (status) + { + case GRUB_EFI_SUCCESS: +- return 0; ++ return GRUB_ERR_NONE; + case GRUB_EFI_DEVICE_ERROR: +- return grub_error (GRUB_ERR_IO, N_("Command failed")); ++ return grub_error (GRUB_ERR_IO, N_("command failed")); + case GRUB_EFI_INVALID_PARAMETER: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("unknown TPM error")); + } + } + diff --git a/0283-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch b/0283-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch deleted file mode 100644 index eff155d..0000000 --- a/0283-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: dann frazier -Date: Thu, 25 Aug 2022 17:08:09 -0600 -Subject: [PATCH] linuxefi: Invalidate i-cache before starting the kernel - -We need to flush the memory range of the code we are about to execute -from the instruction cache before we can safely execute it. Not doing -so appears to be the source of rare synchronous exceptions a user -is seeing on a Cortex-A72-based platform while executing the Linux EFI -stub. Notably they seem to correlate with an instruction on a cache -line boundary. - -Signed-off-by: dann frazier ---- - grub-core/loader/efi/linux.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c -index 277f352e0c..e413bdcc23 100644 ---- a/grub-core/loader/efi/linux.c -+++ b/grub-core/loader/efi/linux.c -@@ -16,6 +16,7 @@ - * along with GRUB. If not, see . - */ - -+#include - #include - #include - #include -@@ -210,6 +211,9 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, - asm volatile ("cli"); - #endif - -+ /* Invalidate the instruction cache */ -+ grub_arch_sync_caches((void *)kernel_addr, kernel_size); -+ - hf = (handover_func)((char *)kernel_addr + handover_offset + offset); - hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); - diff --git a/0284-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/0284-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch new file mode 100644 index 0000000..e04dcbc --- /dev/null +++ b/0284-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:11 +0800 +Subject: [PATCH] commands/efi/tpm: Use grub_strcpy() instead of grub_memcpy() + +The event description is a string, so using grub_strcpy() is cleaner than +using grub_memcpy(). + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +(cherry picked from commit ef8679b645a63eb9eb191bb9539d7d25a9d6ff3b) +--- + grub-core/commands/efi/tpm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index 7acf510499..bb59599721 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -175,7 +175,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->PCRIndex = pcr; + event->EventType = EV_IPL; + event->EventSize = grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, event->EventSize); ++ grub_strcpy ((char *) event->Event, description); + + algorithm = TCG_ALG_SHA; + status = efi_call_7 (tpm->log_extend_event, tpm, (grub_addr_t) buf, (grub_uint64_t) size, +@@ -212,7 +212,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->Header.EventType = EV_IPL; + event->Size = + sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, grub_strlen (description) + 1); ++ grub_strcpy ((char *) event->Event, description); + + status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_addr_t) buf, + (grub_uint64_t) size, event); diff --git a/0284-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch b/0284-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch deleted file mode 100644 index 0079750..0000000 --- a/0284-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 11 Oct 2022 17:00:50 -0400 -Subject: [PATCH] x86-efi: Fix an incorrect array size in kernel allocation - -In 81a6ebf62bbe166ddc968463df2e8bd481bf697c ("efi: split allocation -policy for kernel vs initrd memories."), I introduced a split in the -kernel allocator to allow for different dynamic policies for the kernel -and the initrd allocations. - -Unfortunately, that change increased the size of the policy data used to -make decisions, but did not change the size of the temporary storage we -use to back it up and restore. This results in some of .data getting -clobbered at runtime, and hilarity ensues. - -This patch makes the size of the backup storage be based on the size of -the initial policy data. - -Signed-off-by: Peter Jones ---- - grub-core/loader/i386/efi/linux.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index ac5ef50bdb..9854b0defa 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -92,7 +92,7 @@ static struct allocation_choice max_addresses[] = - { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, - { NO_MEM, 0, 0 } - }; --static struct allocation_choice saved_addresses[4]; -+static struct allocation_choice saved_addresses[sizeof(max_addresses) / sizeof(max_addresses[0])]; - - #define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) - #define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) diff --git a/0285-commands-efi-tpm-Refine-the-status-of-log-event.patch b/0285-commands-efi-tpm-Refine-the-status-of-log-event.patch deleted file mode 100644 index 896e49b..0000000 --- a/0285-commands-efi-tpm-Refine-the-status-of-log-event.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lu Ken -Date: Wed, 13 Jul 2022 10:06:10 +0800 -Subject: [PATCH] commands/efi/tpm: Refine the status of log event - -1. Use macro GRUB_ERR_NONE instead of hard code 0. -2. Keep lowercase of the first char for the status string of log event. - -Signed-off-by: Lu Ken -Reviewed-by: Daniel Kiper -(cherry picked from commit 922898573e37135f5dedc16f3e15a1d1d4c53f8a) ---- - grub-core/commands/efi/tpm.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c -index a97d85368a..7acf510499 100644 ---- a/grub-core/commands/efi/tpm.c -+++ b/grub-core/commands/efi/tpm.c -@@ -135,17 +135,17 @@ grub_efi_log_event_status (grub_efi_status_t status) - switch (status) - { - case GRUB_EFI_SUCCESS: -- return 0; -+ return GRUB_ERR_NONE; - case GRUB_EFI_DEVICE_ERROR: -- return grub_error (GRUB_ERR_IO, N_("Command failed")); -+ return grub_error (GRUB_ERR_IO, N_("command failed")); - case GRUB_EFI_INVALID_PARAMETER: -- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter")); - case GRUB_EFI_BUFFER_TOO_SMALL: -- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("output buffer too small")); - case GRUB_EFI_NOT_FOUND: - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); - default: -- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); -+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("unknown TPM error")); - } - } - diff --git a/0285-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/0285-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch new file mode 100644 index 0000000..610c81a --- /dev/null +++ b/0285-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch @@ -0,0 +1,258 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:12 +0800 +Subject: [PATCH] efi/tpm: Add EFI_CC_MEASUREMENT_PROTOCOL support + +The EFI_CC_MEASUREMENT_PROTOCOL abstracts the measurement for virtual firmware +in confidential computing environment. It is similar to the EFI_TCG2_PROTOCOL. +It was proposed by Intel and ARM and approved by UEFI organization. + +It is defined in Intel GHCI specification: https://cdrdv2.intel.com/v1/dl/getContent/726790 . +The EDKII header file is available at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/CcMeasurement.h . + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +(cherry picked from commit 4c76565b6cb885b7e144dc27f3612066844e2d19) +--- + grub-core/commands/efi/tpm.c | 48 ++++++++++++++ + include/grub/efi/cc.h | 151 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 199 insertions(+) + create mode 100644 include/grub/efi/cc.h + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index bb59599721..ae09c1bf8b 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,6 +32,7 @@ typedef TCG_PCR_EVENT grub_tpm_event_t; + + static grub_efi_guid_t tpm_guid = EFI_TPM_GUID; + static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; ++static grub_efi_guid_t cc_measurement_guid = GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID; + + static grub_efi_handle_t *grub_tpm_handle; + static grub_uint8_t grub_tpm_version; +@@ -221,6 +223,50 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + return grub_efi_log_event_status (status); + } + ++static void ++grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ grub_efi_cc_event_t *event; ++ grub_efi_status_t status; ++ grub_efi_cc_protocol_t *cc; ++ grub_efi_cc_mr_index_t mr; ++ ++ cc = grub_efi_locate_protocol (&cc_measurement_guid, NULL); ++ if (cc == NULL) ++ return; ++ ++ status = efi_call_3 (cc->map_pcr_to_mr_index, cc, pcr, &mr); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_efi_log_event_status (status); ++ return; ++ } ++ ++ event = grub_zalloc (sizeof (grub_efi_cc_event_t) + ++ grub_strlen (description) + 1); ++ if (event == NULL) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate CC event buffer")); ++ return; ++ } ++ ++ event->Header.HeaderSize = sizeof (grub_efi_cc_event_header_t); ++ event->Header.HeaderVersion = GRUB_EFI_CC_EVENT_HEADER_VERSION; ++ event->Header.MrIndex = mr; ++ event->Header.EventType = EV_IPL; ++ event->Size = sizeof (*event) + grub_strlen (description) + 1; ++ grub_strcpy ((char *) event->Event, description); ++ ++ status = efi_call_5 (cc->hash_log_extend_event, cc, 0, ++ (grub_efi_physical_address_t)(grub_addr_t) buf, ++ (grub_efi_uint64_t) size, event); ++ grub_free (event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_efi_log_event_status (status); ++} ++ + grub_err_t + grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) +@@ -228,6 +274,8 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + grub_efi_handle_t tpm_handle; + grub_efi_uint8_t protocol_version; + ++ grub_cc_log_event(buf, size, pcr, description); ++ + if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) + return 0; + +diff --git a/include/grub/efi/cc.h b/include/grub/efi/cc.h +new file mode 100644 +index 0000000000..8960306890 +--- /dev/null ++++ b/include/grub/efi/cc.h +@@ -0,0 +1,151 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_CC_H ++#define GRUB_EFI_CC_H 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID \ ++ { 0x96751a3d, 0x72f4, 0x41a6, \ ++ { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } \ ++ }; ++ ++struct grub_efi_cc_version ++{ ++ grub_efi_uint8_t Major; ++ grub_efi_uint8_t Minor; ++}; ++typedef struct grub_efi_cc_version grub_efi_cc_version_t; ++ ++/* EFI_CC Type/SubType definition. */ ++#define GRUB_EFI_CC_TYPE_NONE 0 ++#define GRUB_EFI_CC_TYPE_SEV 1 ++#define GRUB_EFI_CC_TYPE_TDX 2 ++ ++struct grub_efi_cc_type ++{ ++ grub_efi_uint8_t Type; ++ grub_efi_uint8_t SubType; ++}; ++typedef struct grub_efi_cc_type grub_efi_cc_type_t; ++ ++typedef grub_efi_uint32_t grub_efi_cc_event_log_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_log_format_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_algorithm_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_mr_index_t; ++ ++/* Intel TDX measure register index. */ ++#define GRUB_TDX_MR_INDEX_MRTD 0 ++#define GRUB_TDX_MR_INDEX_RTMR0 1 ++#define GRUB_TDX_MR_INDEX_RTMR1 2 ++#define GRUB_TDX_MR_INDEX_RTMR2 3 ++#define GRUB_TDX_MR_INDEX_RTMR3 4 ++ ++#define GRUB_EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 ++#define GRUB_EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define GRUB_EFI_CC_EVENT_HEADER_VERSION 1 ++ ++struct grub_efi_cc_event_header ++{ ++ /* Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)). */ ++ grub_efi_uint32_t HeaderSize; ++ ++ /* ++ * Header version. For this version of this specification, ++ * the value shall be 1. ++ */ ++ grub_efi_uint16_t HeaderVersion; ++ ++ /* Index of the MR that shall be extended. */ ++ grub_efi_cc_mr_index_t MrIndex; ++ ++ /* Type of the event that shall be extended (and optionally logged). */ ++ grub_efi_uint32_t EventType; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event_header grub_efi_cc_event_header_t; ++ ++struct grub_efi_cc_event ++{ ++ /* Total size of the event including the Size component, the header and the Event data. */ ++ grub_efi_uint32_t Size; ++ grub_efi_cc_event_header_t Header; ++ grub_efi_uint8_t Event[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event grub_efi_cc_event_t; ++ ++struct grub_efi_cc_boot_service_capability ++{ ++ /* Allocated size of the structure. */ ++ grub_efi_uint8_t Size; ++ ++ /* ++ * Version of the grub_efi_cc_boot_service_capability_t structure itself. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t StructureVersion; ++ ++ /* ++ * Version of the EFI TD protocol. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t ProtocolVersion; ++ ++ /* Supported hash algorithms. */ ++ grub_efi_cc_event_algorithm_bitmap_t HashAlgorithmBitmap; ++ ++ /* Bitmap of supported event log formats. */ ++ grub_efi_cc_event_log_bitmap_t SupportedEventLogs; ++ ++ /* Indicates the CC type. */ ++ grub_efi_cc_type_t CcType; ++}; ++typedef struct grub_efi_cc_boot_service_capability grub_efi_cc_boot_service_capability_t; ++ ++struct grub_efi_cc_protocol ++{ ++ grub_efi_status_t ++ (*get_capability) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_boot_service_capability_t *ProtocolCapability); ++ ++ grub_efi_status_t ++ (*get_event_log) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_event_log_format_t EventLogFormat, ++ grub_efi_physical_address_t *EventLogLocation, ++ grub_efi_physical_address_t *EventLogLastEntry, ++ grub_efi_boolean_t *EventLogTruncated); ++ ++ grub_efi_status_t ++ (*hash_log_extend_event) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint64_t Flags, ++ grub_efi_physical_address_t DataToHash, ++ grub_efi_uint64_t DataToHashLen, ++ grub_efi_cc_event_t *EfiCcEvent); ++ ++ grub_efi_status_t ++ (*map_pcr_to_mr_index) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint32_t PcrIndex, ++ grub_efi_cc_mr_index_t *MrIndex); ++}; ++typedef struct grub_efi_cc_protocol grub_efi_cc_protocol_t; ++ ++#endif diff --git a/0286-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/0286-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch deleted file mode 100644 index e04dcbc..0000000 --- a/0286-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lu Ken -Date: Wed, 13 Jul 2022 10:06:11 +0800 -Subject: [PATCH] commands/efi/tpm: Use grub_strcpy() instead of grub_memcpy() - -The event description is a string, so using grub_strcpy() is cleaner than -using grub_memcpy(). - -Signed-off-by: Lu Ken -Reviewed-by: Daniel Kiper -(cherry picked from commit ef8679b645a63eb9eb191bb9539d7d25a9d6ff3b) ---- - grub-core/commands/efi/tpm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c -index 7acf510499..bb59599721 100644 ---- a/grub-core/commands/efi/tpm.c -+++ b/grub-core/commands/efi/tpm.c -@@ -175,7 +175,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, - event->PCRIndex = pcr; - event->EventType = EV_IPL; - event->EventSize = grub_strlen (description) + 1; -- grub_memcpy (event->Event, description, event->EventSize); -+ grub_strcpy ((char *) event->Event, description); - - algorithm = TCG_ALG_SHA; - status = efi_call_7 (tpm->log_extend_event, tpm, (grub_addr_t) buf, (grub_uint64_t) size, -@@ -212,7 +212,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, - event->Header.EventType = EV_IPL; - event->Size = - sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1; -- grub_memcpy (event->Event, description, grub_strlen (description) + 1); -+ grub_strcpy ((char *) event->Event, description); - - status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_addr_t) buf, - (grub_uint64_t) size, event); diff --git a/0287-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/0287-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch deleted file mode 100644 index 610c81a..0000000 --- a/0287-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +++ /dev/null @@ -1,258 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lu Ken -Date: Wed, 13 Jul 2022 10:06:12 +0800 -Subject: [PATCH] efi/tpm: Add EFI_CC_MEASUREMENT_PROTOCOL support - -The EFI_CC_MEASUREMENT_PROTOCOL abstracts the measurement for virtual firmware -in confidential computing environment. It is similar to the EFI_TCG2_PROTOCOL. -It was proposed by Intel and ARM and approved by UEFI organization. - -It is defined in Intel GHCI specification: https://cdrdv2.intel.com/v1/dl/getContent/726790 . -The EDKII header file is available at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/CcMeasurement.h . - -Signed-off-by: Lu Ken -Reviewed-by: Daniel Kiper -(cherry picked from commit 4c76565b6cb885b7e144dc27f3612066844e2d19) ---- - grub-core/commands/efi/tpm.c | 48 ++++++++++++++ - include/grub/efi/cc.h | 151 +++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 199 insertions(+) - create mode 100644 include/grub/efi/cc.h - -diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c -index bb59599721..ae09c1bf8b 100644 ---- a/grub-core/commands/efi/tpm.c -+++ b/grub-core/commands/efi/tpm.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -31,6 +32,7 @@ typedef TCG_PCR_EVENT grub_tpm_event_t; - - static grub_efi_guid_t tpm_guid = EFI_TPM_GUID; - static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; -+static grub_efi_guid_t cc_measurement_guid = GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID; - - static grub_efi_handle_t *grub_tpm_handle; - static grub_uint8_t grub_tpm_version; -@@ -221,6 +223,50 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, - return grub_efi_log_event_status (status); - } - -+static void -+grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, -+ const char *description) -+{ -+ grub_efi_cc_event_t *event; -+ grub_efi_status_t status; -+ grub_efi_cc_protocol_t *cc; -+ grub_efi_cc_mr_index_t mr; -+ -+ cc = grub_efi_locate_protocol (&cc_measurement_guid, NULL); -+ if (cc == NULL) -+ return; -+ -+ status = efi_call_3 (cc->map_pcr_to_mr_index, cc, pcr, &mr); -+ if (status != GRUB_EFI_SUCCESS) -+ { -+ grub_efi_log_event_status (status); -+ return; -+ } -+ -+ event = grub_zalloc (sizeof (grub_efi_cc_event_t) + -+ grub_strlen (description) + 1); -+ if (event == NULL) -+ { -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate CC event buffer")); -+ return; -+ } -+ -+ event->Header.HeaderSize = sizeof (grub_efi_cc_event_header_t); -+ event->Header.HeaderVersion = GRUB_EFI_CC_EVENT_HEADER_VERSION; -+ event->Header.MrIndex = mr; -+ event->Header.EventType = EV_IPL; -+ event->Size = sizeof (*event) + grub_strlen (description) + 1; -+ grub_strcpy ((char *) event->Event, description); -+ -+ status = efi_call_5 (cc->hash_log_extend_event, cc, 0, -+ (grub_efi_physical_address_t)(grub_addr_t) buf, -+ (grub_efi_uint64_t) size, event); -+ grub_free (event); -+ -+ if (status != GRUB_EFI_SUCCESS) -+ grub_efi_log_event_status (status); -+} -+ - grub_err_t - grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, - const char *description) -@@ -228,6 +274,8 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, - grub_efi_handle_t tpm_handle; - grub_efi_uint8_t protocol_version; - -+ grub_cc_log_event(buf, size, pcr, description); -+ - if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) - return 0; - -diff --git a/include/grub/efi/cc.h b/include/grub/efi/cc.h -new file mode 100644 -index 0000000000..8960306890 ---- /dev/null -+++ b/include/grub/efi/cc.h -@@ -0,0 +1,151 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2022 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_EFI_CC_H -+#define GRUB_EFI_CC_H 1 -+ -+#include -+#include -+#include -+ -+#define GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID \ -+ { 0x96751a3d, 0x72f4, 0x41a6, \ -+ { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } \ -+ }; -+ -+struct grub_efi_cc_version -+{ -+ grub_efi_uint8_t Major; -+ grub_efi_uint8_t Minor; -+}; -+typedef struct grub_efi_cc_version grub_efi_cc_version_t; -+ -+/* EFI_CC Type/SubType definition. */ -+#define GRUB_EFI_CC_TYPE_NONE 0 -+#define GRUB_EFI_CC_TYPE_SEV 1 -+#define GRUB_EFI_CC_TYPE_TDX 2 -+ -+struct grub_efi_cc_type -+{ -+ grub_efi_uint8_t Type; -+ grub_efi_uint8_t SubType; -+}; -+typedef struct grub_efi_cc_type grub_efi_cc_type_t; -+ -+typedef grub_efi_uint32_t grub_efi_cc_event_log_bitmap_t; -+typedef grub_efi_uint32_t grub_efi_cc_event_log_format_t; -+typedef grub_efi_uint32_t grub_efi_cc_event_algorithm_bitmap_t; -+typedef grub_efi_uint32_t grub_efi_cc_mr_index_t; -+ -+/* Intel TDX measure register index. */ -+#define GRUB_TDX_MR_INDEX_MRTD 0 -+#define GRUB_TDX_MR_INDEX_RTMR0 1 -+#define GRUB_TDX_MR_INDEX_RTMR1 2 -+#define GRUB_TDX_MR_INDEX_RTMR2 3 -+#define GRUB_TDX_MR_INDEX_RTMR3 4 -+ -+#define GRUB_EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 -+#define GRUB_EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 -+#define GRUB_EFI_CC_EVENT_HEADER_VERSION 1 -+ -+struct grub_efi_cc_event_header -+{ -+ /* Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)). */ -+ grub_efi_uint32_t HeaderSize; -+ -+ /* -+ * Header version. For this version of this specification, -+ * the value shall be 1. -+ */ -+ grub_efi_uint16_t HeaderVersion; -+ -+ /* Index of the MR that shall be extended. */ -+ grub_efi_cc_mr_index_t MrIndex; -+ -+ /* Type of the event that shall be extended (and optionally logged). */ -+ grub_efi_uint32_t EventType; -+} GRUB_PACKED; -+typedef struct grub_efi_cc_event_header grub_efi_cc_event_header_t; -+ -+struct grub_efi_cc_event -+{ -+ /* Total size of the event including the Size component, the header and the Event data. */ -+ grub_efi_uint32_t Size; -+ grub_efi_cc_event_header_t Header; -+ grub_efi_uint8_t Event[0]; -+} GRUB_PACKED; -+typedef struct grub_efi_cc_event grub_efi_cc_event_t; -+ -+struct grub_efi_cc_boot_service_capability -+{ -+ /* Allocated size of the structure. */ -+ grub_efi_uint8_t Size; -+ -+ /* -+ * Version of the grub_efi_cc_boot_service_capability_t structure itself. -+ * For this version of the protocol, the Major version shall be set to 1 -+ * and the Minor version shall be set to 1. -+ */ -+ grub_efi_cc_version_t StructureVersion; -+ -+ /* -+ * Version of the EFI TD protocol. -+ * For this version of the protocol, the Major version shall be set to 1 -+ * and the Minor version shall be set to 1. -+ */ -+ grub_efi_cc_version_t ProtocolVersion; -+ -+ /* Supported hash algorithms. */ -+ grub_efi_cc_event_algorithm_bitmap_t HashAlgorithmBitmap; -+ -+ /* Bitmap of supported event log formats. */ -+ grub_efi_cc_event_log_bitmap_t SupportedEventLogs; -+ -+ /* Indicates the CC type. */ -+ grub_efi_cc_type_t CcType; -+}; -+typedef struct grub_efi_cc_boot_service_capability grub_efi_cc_boot_service_capability_t; -+ -+struct grub_efi_cc_protocol -+{ -+ grub_efi_status_t -+ (*get_capability) (struct grub_efi_cc_protocol *this, -+ grub_efi_cc_boot_service_capability_t *ProtocolCapability); -+ -+ grub_efi_status_t -+ (*get_event_log) (struct grub_efi_cc_protocol *this, -+ grub_efi_cc_event_log_format_t EventLogFormat, -+ grub_efi_physical_address_t *EventLogLocation, -+ grub_efi_physical_address_t *EventLogLastEntry, -+ grub_efi_boolean_t *EventLogTruncated); -+ -+ grub_efi_status_t -+ (*hash_log_extend_event) (struct grub_efi_cc_protocol *this, -+ grub_efi_uint64_t Flags, -+ grub_efi_physical_address_t DataToHash, -+ grub_efi_uint64_t DataToHashLen, -+ grub_efi_cc_event_t *EfiCcEvent); -+ -+ grub_efi_status_t -+ (*map_pcr_to_mr_index) (struct grub_efi_cc_protocol *this, -+ grub_efi_uint32_t PcrIndex, -+ grub_efi_cc_mr_index_t *MrIndex); -+}; -+typedef struct grub_efi_cc_protocol grub_efi_cc_protocol_t; -+ -+#endif diff --git a/grub.patches b/grub.patches index ebbd8ac..a90e921 100644 --- a/grub.patches +++ b/grub.patches @@ -29,259 +29,257 @@ Patch0028: 0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch Patch0029: 0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch Patch0030: 0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch Patch0031: 0031-Try-prefix-if-fw_path-doesn-t-work.patch -Patch0032: 0032-Use-rpm-s-sort-for-grub2-mkconfig.patch -Patch0033: 0033-Make-grub2-mkconfig-construct-titles-that-look-like-.patch -Patch0034: 0034-Add-friendly-grub2-password-config-tool-985962.patch -Patch0035: 0035-tcp-add-window-scaling-support.patch -Patch0036: 0036-efinet-and-bootp-add-support-for-dhcpv6.patch -Patch0037: 0037-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch -Patch0038: 0038-bz1374141-fix-incorrect-mask-for-ppc64.patch -Patch0039: 0039-Make-grub_fatal-also-backtrace.patch -Patch0040: 0040-Make-our-info-pages-say-grub2-where-appropriate.patch -Patch0041: 0041-macos-just-build-chainloader-entries-don-t-try-any-x.patch -Patch0042: 0042-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch -Patch0043: 0043-export-btrfs_subvol-and-btrfs_subvolid.patch -Patch0044: 0044-grub2-btrfs-03-follow_default.patch -Patch0045: 0045-grub2-btrfs-04-grub2-install.patch -Patch0046: 0046-grub2-btrfs-05-grub2-mkconfig.patch -Patch0047: 0047-grub2-btrfs-06-subvol-mount.patch -Patch0048: 0048-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch -Patch0049: 0049-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch -Patch0050: 0050-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch -Patch0051: 0051-Use-grub_efi_.-memory-helpers-where-reasonable.patch -Patch0052: 0052-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch -Patch0053: 0053-don-t-use-int-for-efi-status.patch -Patch0054: 0054-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch -Patch0055: 0055-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch -Patch0056: 0056-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch -Patch0057: 0057-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch -Patch0058: 0058-align-struct-efi_variable-better.patch -Patch0059: 0059-Add-BLS-support-to-grub-mkconfig.patch -Patch0060: 0060-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch -Patch0061: 0061-Add-linux-and-initrd-commands-for-grub-emu.patch -Patch0062: 0062-Add-grub2-switch-to-blscfg.patch -Patch0063: 0063-make-better-backtraces.patch -Patch0064: 0064-normal-don-t-draw-our-startup-message-if-debug-is-se.patch -Patch0065: 0065-Work-around-some-minor-include-path-weirdnesses.patch -Patch0066: 0066-Make-it-possible-to-enabled-build-id-sha1.patch -Patch0067: 0067-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch -Patch0068: 0068-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch -Patch0069: 0069-Fixup-for-newer-compiler.patch -Patch0070: 0070-Don-t-attempt-to-export-the-start-and-_start-symbols.patch -Patch0071: 0071-Fixup-for-newer-compiler.patch -Patch0072: 0072-Add-support-for-non-Ethernet-network-cards.patch -Patch0073: 0073-net-read-bracketed-ipv6-addrs-and-port-numbers.patch -Patch0074: 0074-bootp-New-net_bootp6-command.patch -Patch0075: 0075-efinet-UEFI-IPv6-PXE-support.patch -Patch0076: 0076-grub.texi-Add-net_bootp6-doument.patch -Patch0077: 0077-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch -Patch0078: 0078-efinet-Setting-network-from-UEFI-device-path.patch -Patch0079: 0079-efinet-Setting-DNS-server-from-UEFI-protocol.patch -Patch0080: 0080-Support-UEFI-networking-protocols.patch -Patch0081: 0081-AUDIT-0-http-boot-tracker-bug.patch -Patch0082: 0082-grub-editenv-Add-incr-command-to-increment-integer-v.patch -Patch0083: 0083-Add-auto-hide-menu-support.patch -Patch0084: 0084-Add-grub-set-bootflag-utility.patch -Patch0085: 0085-docs-Add-grub-boot-indeterminate.service-example.patch -Patch0086: 0086-gentpl-add-disable-support.patch -Patch0087: 0087-gentpl-add-pc-firmware-type.patch -Patch0088: 0088-efinet-also-use-the-firmware-acceleration-for-http.patch -Patch0089: 0089-efi-http-Make-root_url-reflect-the-protocol-hostname.patch -Patch0090: 0090-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch -Patch0091: 0091-module-verifier-make-it-possible-to-run-checkers-on-.patch -Patch0092: 0092-Rework-how-the-fdt-command-builds.patch -Patch0093: 0093-Disable-non-wordsize-allocations-on-arm.patch -Patch0094: 0094-Prepend-prefix-when-HTTP-path-is-relative.patch -Patch0095: 0095-Make-grub_error-more-verbose.patch -Patch0096: 0096-Make-reset-an-alias-for-the-reboot-command.patch -Patch0097: 0097-Add-a-version-command.patch -Patch0098: 0098-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch -Patch0099: 0099-arm-arm64-loader-Better-memory-allocation-and-error-.patch -Patch0100: 0100-Try-to-pick-better-locations-for-kernel-and-initrd.patch -Patch0101: 0101-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch -Patch0102: 0102-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch -Patch0103: 0103-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch -Patch0104: 0104-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch -Patch0105: 0105-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch -Patch0106: 0106-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch -Patch0107: 0107-Fix-getroot.c-s-trampolines.patch -Patch0108: 0108-Do-not-allow-stack-trampolines-anywhere.patch -Patch0109: 0109-Reimplement-boot_counter.patch -Patch0110: 0110-Fix-menu-entry-selection-based-on-ID-and-title.patch -Patch0111: 0111-Make-the-menu-entry-users-option-argument-to-be-opti.patch -Patch0112: 0112-Add-efi-export-env-and-efi-load-env-commands.patch -Patch0113: 0113-Make-it-possible-to-subtract-conditions-from-debug.patch -Patch0114: 0114-Export-all-variables-from-the-initial-context-when-c.patch -Patch0115: 0115-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch -Patch0116: 0116-Fix-systemctl-kexec-exit-status-check.patch -Patch0117: 0117-Print-grub-emu-linux-loader-messages-as-debug.patch -Patch0118: 0118-Don-t-assume-that-boot-commands-will-only-return-on-.patch -Patch0119: 0119-grub-set-bootflag-Update-comment-about-running-as-ro.patch -Patch0120: 0120-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch -Patch0121: 0121-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch -Patch0122: 0122-Add-start-symbol-for-RISC-V.patch -Patch0123: 0123-bootstrap.conf-Force-autogen.sh-to-use-python3.patch -Patch0124: 0124-efi-http-Export-fw-http-_path-variables-to-make-them.patch -Patch0125: 0125-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch -Patch0126: 0126-efi-net-Allow-to-specify-a-port-number-in-addresses.patch -Patch0127: 0127-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch -Patch0128: 0128-efi-net-Print-a-debug-message-if-parsing-the-address.patch -Patch0129: 0129-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch -Patch0130: 0130-efi-Set-image-base-address-before-jumping-to-the-PE-.patch -Patch0131: 0131-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch -Patch0132: 0132-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch -Patch0133: 0133-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch -Patch0134: 0134-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch -Patch0135: 0135-efi-dhcp-fix-some-allocation-error-checking.patch -Patch0136: 0136-efi-http-fix-some-allocation-error-checking.patch -Patch0137: 0137-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch -Patch0138: 0138-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch -Patch0139: 0139-linuxefi-fail-kernel-validation-without-shim-protoco.patch -Patch0140: 0140-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch -Patch0141: 0141-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch -Patch0142: 0142-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch -Patch0143: 0143-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch -Patch0144: 0144-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch -Patch0145: 0145-Add-systemd-integration-scripts-to-make-systemctl-re.patch -Patch0146: 0146-systemd-integration.sh-Also-set-old-menu_show_once-g.patch -Patch0147: 0147-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch -Patch0148: 0148-grub-install-disable-support-for-EFI-platforms.patch -Patch0149: 0149-New-with-debug-timestamps-configure-flag-to-prepend-.patch -Patch0150: 0150-Added-debug-statements-to-grub_disk_open-and-grub_di.patch -Patch0151: 0151-Introduce-function-grub_debug_is_enabled-void-return.patch -Patch0152: 0152-Don-t-clear-screen-when-debugging-is-enabled.patch -Patch0153: 0153-grub_file_-instrumentation-new-file-debug-tag.patch -Patch0154: 0154-ieee1275-Avoiding-many-unecessary-open-close.patch -Patch0155: 0155-ieee1275-powerpc-implements-fibre-channel-discovery-.patch -Patch0156: 0156-ieee1275-powerpc-enables-device-mapper-discovery.patch -Patch0157: 0157-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch -Patch0158: 0158-Add-suport-for-signing-grub-with-an-appended-signatu.patch -Patch0159: 0159-docs-grub-Document-signing-grub-under-UEFI.patch -Patch0160: 0160-docs-grub-Document-signing-grub-with-an-appended-sig.patch -Patch0161: 0161-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch -Patch0162: 0162-pgp-factor-out-rsa_pad.patch -Patch0163: 0163-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch -Patch0164: 0164-posix_wrap-tweaks-in-preparation-for-libtasn1.patch -Patch0165: 0165-libtasn1-import-libtasn1-4.16.0.patch -Patch0166: 0166-libtasn1-disable-code-not-needed-in-grub.patch -Patch0167: 0167-libtasn1-changes-for-grub-compatibility.patch -Patch0168: 0168-libtasn1-compile-into-asn1-module.patch -Patch0169: 0169-test_asn1-test-module-for-libtasn1.patch -Patch0170: 0170-grub-install-support-embedding-x509-certificates.patch -Patch0171: 0171-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch -Patch0172: 0172-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch -Patch0173: 0173-appended-signatures-support-verifying-appended-signa.patch -Patch0174: 0174-appended-signatures-verification-tests.patch -Patch0175: 0175-appended-signatures-documentation.patch -Patch0176: 0176-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch -Patch0177: 0177-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch -Patch0178: 0178-ieee1275-claim-more-memory.patch -Patch0179: 0179-ieee1275-request-memory-with-ibm-client-architecture.patch -Patch0180: 0180-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch -Patch0181: 0181-ieee1275-ofdisk-retry-on-open-failure.patch -Patch0182: 0182-Allow-chainloading-EFI-apps-from-loop-mounts.patch -Patch0183: 0183-efinet-Add-DHCP-proxy-support.patch -Patch0184: 0184-fs-ext2-Ignore-checksum-seed-incompat-feature.patch -Patch0185: 0185-Don-t-update-the-cmdline-when-generating-legacy-menu.patch -Patch0186: 0186-Suppress-gettext-error-message.patch -Patch0187: 0187-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch -Patch0188: 0188-templates-Check-for-EFI-at-runtime-instead-of-config.patch -Patch0189: 0189-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch -Patch0190: 0190-arm64-Fix-EFI-loader-kernel-image-allocation.patch -Patch0191: 0191-normal-main-Discover-the-device-to-read-the-config-f.patch -Patch0192: 0192-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch -Patch0193: 0193-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch -Patch0194: 0194-Print-module-name-on-license-check-failure.patch -Patch0195: 0195-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch -Patch0196: 0196-grub-mkconfig-restore-umask-for-grub.cfg.patch -Patch0197: 0197-fs-btrfs-Use-full-btrfs-bootloader-area.patch -Patch0198: 0198-Add-Fedora-location-of-DejaVu-SANS-font.patch -Patch0199: 0199-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch -Patch0200: 0200-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch -Patch0201: 0201-EFI-console-Do-not-set-colorstate-until-the-first-te.patch -Patch0202: 0202-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch -Patch0203: 0203-Use-visual-indentation-in-config.h.in.patch -Patch0204: 0204-Where-present-ensure-config-util.h-precedes-config.h.patch -Patch0205: 0205-Drop-gnulib-fix-base64.patch.patch -Patch0206: 0206-Drop-gnulib-no-abort.patch.patch -Patch0207: 0207-Update-gnulib-version-and-drop-most-gnulib-patches.patch -Patch0208: 0208-commands-search-Fix-bug-stopping-iteration-when-no-f.patch -Patch0209: 0209-search-new-efidisk-only-option-on-EFI-systems.patch -Patch0210: 0210-efi-new-connectefi-command.patch -Patch0211: 0211-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch -Patch0212: 0212-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch -Patch0213: 0213-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch -Patch0214: 0214-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch -Patch0215: 0215-powerpc-do-CAS-in-a-more-compatible-way.patch -Patch0216: 0216-powerpc-prefix-detection-support-device-names-with-c.patch -Patch0217: 0217-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch -Patch0218: 0218-rpm-sort-add-prereqs-for-declaration-of-strchrnul.patch -Patch0219: 0219-make-ofdisk_retries-optional.patch -Patch0220: 0220-loader-efi-chainloader-grub_load_and_start_image-doe.patch -Patch0221: 0221-loader-efi-chainloader-simplify-the-loader-state.patch -Patch0222: 0222-commands-boot-Add-API-to-pass-context-to-loader.patch -Patch0223: 0223-loader-efi-chainloader-Use-grub_loader_set_ex.patch -Patch0224: 0224-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch -Patch0225: 0225-loader-i386-efi-linux-Use-grub_loader_set_ex.patch -Patch0226: 0226-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch -Patch0227: 0227-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch -Patch0228: 0228-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch -Patch0229: 0229-video-readers-png-Abort-sooner-if-a-read-operation-f.patch -Patch0230: 0230-video-readers-png-Refuse-to-handle-multiple-image-he.patch -Patch0231: 0231-video-readers-png-Drop-greyscale-support-to-fix-heap.patch -Patch0232: 0232-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch -Patch0233: 0233-video-readers-png-Sanity-check-some-huffman-codes.patch -Patch0234: 0234-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch -Patch0235: 0235-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch -Patch0236: 0236-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch -Patch0237: 0237-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch -Patch0238: 0238-normal-charset-Fix-array-out-of-bounds-formatting-un.patch -Patch0239: 0239-net-netbuff-Block-overly-large-netbuff-allocs.patch -Patch0240: 0240-net-ip-Do-IP-fragment-maths-safely.patch -Patch0241: 0241-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch -Patch0242: 0242-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch -Patch0243: 0243-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch -Patch0244: 0244-net-tftp-Avoid-a-trivial-UAF.patch -Patch0245: 0245-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch -Patch0246: 0246-net-http-Fix-OOB-write-for-split-http-headers.patch -Patch0247: 0247-net-http-Error-out-on-headers-with-LF-without-CR.patch -Patch0248: 0248-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch -Patch0249: 0249-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch -Patch0250: 0250-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch -Patch0251: 0251-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch -Patch0252: 0252-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch -Patch0253: 0253-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch -Patch0254: 0254-misc-Make-grub_min-and-grub_max-more-resilient.patch -Patch0255: 0255-ReiserFS-switch-to-using-grub_min-grub_max.patch -Patch0256: 0256-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch -Patch0257: 0257-modules-make-.module_license-read-only.patch -Patch0258: 0258-modules-strip-.llvm_addrsig-sections-and-similar.patch -Patch0259: 0259-modules-Don-t-allocate-space-for-non-allocable-secti.patch -Patch0260: 0260-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch -Patch0261: 0261-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch -Patch0262: 0262-modules-load-module-sections-at-page-aligned-address.patch -Patch0263: 0263-nx-add-memory-attribute-get-set-API.patch -Patch0264: 0264-nx-set-page-permissions-for-loaded-modules.patch -Patch0265: 0265-nx-set-attrs-in-our-kernel-loaders.patch -Patch0266: 0266-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch -Patch0267: 0267-grub-probe-document-the-behavior-of-multiple-v.patch -Patch0268: 0268-grub_fs_probe-dprint-errors-from-filesystems.patch -Patch0269: 0269-fs-fat-don-t-error-when-mtime-is-0.patch -Patch0270: 0270-Make-debug-file-show-which-file-filters-get-run.patch -Patch0271: 0271-efi-use-enumerated-array-positions-for-our-allocatio.patch -Patch0272: 0272-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch -Patch0273: 0273-efi-allocate-the-initrd-within-the-bounds-expressed-.patch -Patch0274: 0274-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch -Patch0275: 0275-BLS-create-etc-kernel-cmdline-during-mkconfig.patch -Patch0276: 0276-squish-don-t-dup-rhgb-quiet-check-mtimes.patch -Patch0277: 0277-squish-give-up-on-rhgb-quiet.patch -Patch0278: 0278-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch -Patch0279: 0279-ieee1275-implement-vec5-for-cas-negotiation.patch -Patch0280: 0280-blscfg-Don-t-root-device-in-emu-builds.patch -Patch0281: 0281-loader-arm64-linux-Remove-magic-number-header-field-.patch -Patch0282: 0282-Correct-BSS-zeroing-on-aarch64.patch -Patch0283: 0283-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch -Patch0284: 0284-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch -Patch0285: 0285-commands-efi-tpm-Refine-the-status-of-log-event.patch -Patch0286: 0286-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch -Patch0287: 0287-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +Patch0032: 0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch +Patch0033: 0033-Add-friendly-grub2-password-config-tool-985962.patch +Patch0034: 0034-tcp-add-window-scaling-support.patch +Patch0035: 0035-efinet-and-bootp-add-support-for-dhcpv6.patch +Patch0036: 0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch +Patch0037: 0037-bz1374141-fix-incorrect-mask-for-ppc64.patch +Patch0038: 0038-Make-grub_fatal-also-backtrace.patch +Patch0039: 0039-Make-our-info-pages-say-grub2-where-appropriate.patch +Patch0040: 0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch +Patch0041: 0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch +Patch0042: 0042-export-btrfs_subvol-and-btrfs_subvolid.patch +Patch0043: 0043-grub2-btrfs-03-follow_default.patch +Patch0044: 0044-grub2-btrfs-04-grub2-install.patch +Patch0045: 0045-grub2-btrfs-05-grub2-mkconfig.patch +Patch0046: 0046-grub2-btrfs-06-subvol-mount.patch +Patch0047: 0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch +Patch0048: 0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch +Patch0049: 0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch +Patch0050: 0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch +Patch0051: 0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch +Patch0052: 0052-don-t-use-int-for-efi-status.patch +Patch0053: 0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch +Patch0054: 0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch +Patch0055: 0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch +Patch0056: 0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch +Patch0057: 0057-align-struct-efi_variable-better.patch +Patch0058: 0058-Add-BLS-support-to-grub-mkconfig.patch +Patch0059: 0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch +Patch0060: 0060-Add-linux-and-initrd-commands-for-grub-emu.patch +Patch0061: 0061-Add-grub2-switch-to-blscfg.patch +Patch0062: 0062-make-better-backtraces.patch +Patch0063: 0063-normal-don-t-draw-our-startup-message-if-debug-is-se.patch +Patch0064: 0064-Work-around-some-minor-include-path-weirdnesses.patch +Patch0065: 0065-Make-it-possible-to-enabled-build-id-sha1.patch +Patch0066: 0066-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch +Patch0067: 0067-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch +Patch0068: 0068-Fixup-for-newer-compiler.patch +Patch0069: 0069-Don-t-attempt-to-export-the-start-and-_start-symbols.patch +Patch0070: 0070-Fixup-for-newer-compiler.patch +Patch0071: 0071-Add-support-for-non-Ethernet-network-cards.patch +Patch0072: 0072-net-read-bracketed-ipv6-addrs-and-port-numbers.patch +Patch0073: 0073-bootp-New-net_bootp6-command.patch +Patch0074: 0074-efinet-UEFI-IPv6-PXE-support.patch +Patch0075: 0075-grub.texi-Add-net_bootp6-doument.patch +Patch0076: 0076-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch +Patch0077: 0077-efinet-Setting-network-from-UEFI-device-path.patch +Patch0078: 0078-efinet-Setting-DNS-server-from-UEFI-protocol.patch +Patch0079: 0079-Support-UEFI-networking-protocols.patch +Patch0080: 0080-AUDIT-0-http-boot-tracker-bug.patch +Patch0081: 0081-grub-editenv-Add-incr-command-to-increment-integer-v.patch +Patch0082: 0082-Add-auto-hide-menu-support.patch +Patch0083: 0083-Add-grub-set-bootflag-utility.patch +Patch0084: 0084-docs-Add-grub-boot-indeterminate.service-example.patch +Patch0085: 0085-gentpl-add-disable-support.patch +Patch0086: 0086-gentpl-add-pc-firmware-type.patch +Patch0087: 0087-efinet-also-use-the-firmware-acceleration-for-http.patch +Patch0088: 0088-efi-http-Make-root_url-reflect-the-protocol-hostname.patch +Patch0089: 0089-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch +Patch0090: 0090-module-verifier-make-it-possible-to-run-checkers-on-.patch +Patch0091: 0091-Rework-how-the-fdt-command-builds.patch +Patch0092: 0092-Disable-non-wordsize-allocations-on-arm.patch +Patch0093: 0093-Prepend-prefix-when-HTTP-path-is-relative.patch +Patch0094: 0094-Make-grub_error-more-verbose.patch +Patch0095: 0095-Make-reset-an-alias-for-the-reboot-command.patch +Patch0096: 0096-Add-a-version-command.patch +Patch0097: 0097-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch +Patch0098: 0098-arm-arm64-loader-Better-memory-allocation-and-error-.patch +Patch0099: 0099-Try-to-pick-better-locations-for-kernel-and-initrd.patch +Patch0100: 0100-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch +Patch0101: 0101-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch +Patch0102: 0102-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch +Patch0103: 0103-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch +Patch0104: 0104-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch +Patch0105: 0105-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch +Patch0106: 0106-Fix-getroot.c-s-trampolines.patch +Patch0107: 0107-Do-not-allow-stack-trampolines-anywhere.patch +Patch0108: 0108-Reimplement-boot_counter.patch +Patch0109: 0109-Fix-menu-entry-selection-based-on-ID-and-title.patch +Patch0110: 0110-Make-the-menu-entry-users-option-argument-to-be-opti.patch +Patch0111: 0111-Add-efi-export-env-and-efi-load-env-commands.patch +Patch0112: 0112-Make-it-possible-to-subtract-conditions-from-debug.patch +Patch0113: 0113-Export-all-variables-from-the-initial-context-when-c.patch +Patch0114: 0114-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch +Patch0115: 0115-Fix-systemctl-kexec-exit-status-check.patch +Patch0116: 0116-Print-grub-emu-linux-loader-messages-as-debug.patch +Patch0117: 0117-Don-t-assume-that-boot-commands-will-only-return-on-.patch +Patch0118: 0118-grub-set-bootflag-Update-comment-about-running-as-ro.patch +Patch0119: 0119-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch +Patch0120: 0120-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch +Patch0121: 0121-Add-start-symbol-for-RISC-V.patch +Patch0122: 0122-bootstrap.conf-Force-autogen.sh-to-use-python3.patch +Patch0123: 0123-efi-http-Export-fw-http-_path-variables-to-make-them.patch +Patch0124: 0124-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch +Patch0125: 0125-efi-net-Allow-to-specify-a-port-number-in-addresses.patch +Patch0126: 0126-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch +Patch0127: 0127-efi-net-Print-a-debug-message-if-parsing-the-address.patch +Patch0128: 0128-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch +Patch0129: 0129-efi-Set-image-base-address-before-jumping-to-the-PE-.patch +Patch0130: 0130-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch +Patch0131: 0131-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch +Patch0132: 0132-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch +Patch0133: 0133-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch +Patch0134: 0134-efi-dhcp-fix-some-allocation-error-checking.patch +Patch0135: 0135-efi-http-fix-some-allocation-error-checking.patch +Patch0136: 0136-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch +Patch0137: 0137-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch +Patch0138: 0138-linuxefi-fail-kernel-validation-without-shim-protoco.patch +Patch0139: 0139-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch +Patch0140: 0140-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch +Patch0141: 0141-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch +Patch0142: 0142-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch +Patch0143: 0143-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch +Patch0144: 0144-Add-systemd-integration-scripts-to-make-systemctl-re.patch +Patch0145: 0145-systemd-integration.sh-Also-set-old-menu_show_once-g.patch +Patch0146: 0146-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch +Patch0147: 0147-grub-install-disable-support-for-EFI-platforms.patch +Patch0148: 0148-New-with-debug-timestamps-configure-flag-to-prepend-.patch +Patch0149: 0149-Added-debug-statements-to-grub_disk_open-and-grub_di.patch +Patch0150: 0150-Introduce-function-grub_debug_is_enabled-void-return.patch +Patch0151: 0151-Don-t-clear-screen-when-debugging-is-enabled.patch +Patch0152: 0152-grub_file_-instrumentation-new-file-debug-tag.patch +Patch0153: 0153-ieee1275-Avoiding-many-unecessary-open-close.patch +Patch0154: 0154-ieee1275-powerpc-implements-fibre-channel-discovery-.patch +Patch0155: 0155-ieee1275-powerpc-enables-device-mapper-discovery.patch +Patch0156: 0156-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch +Patch0157: 0157-Add-suport-for-signing-grub-with-an-appended-signatu.patch +Patch0158: 0158-docs-grub-Document-signing-grub-under-UEFI.patch +Patch0159: 0159-docs-grub-Document-signing-grub-with-an-appended-sig.patch +Patch0160: 0160-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch +Patch0161: 0161-pgp-factor-out-rsa_pad.patch +Patch0162: 0162-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch +Patch0163: 0163-posix_wrap-tweaks-in-preparation-for-libtasn1.patch +Patch0164: 0164-libtasn1-import-libtasn1-4.16.0.patch +Patch0165: 0165-libtasn1-disable-code-not-needed-in-grub.patch +Patch0166: 0166-libtasn1-changes-for-grub-compatibility.patch +Patch0167: 0167-libtasn1-compile-into-asn1-module.patch +Patch0168: 0168-test_asn1-test-module-for-libtasn1.patch +Patch0169: 0169-grub-install-support-embedding-x509-certificates.patch +Patch0170: 0170-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch +Patch0171: 0171-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch +Patch0172: 0172-appended-signatures-support-verifying-appended-signa.patch +Patch0173: 0173-appended-signatures-verification-tests.patch +Patch0174: 0174-appended-signatures-documentation.patch +Patch0175: 0175-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch +Patch0176: 0176-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch +Patch0177: 0177-ieee1275-claim-more-memory.patch +Patch0178: 0178-ieee1275-request-memory-with-ibm-client-architecture.patch +Patch0179: 0179-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch +Patch0180: 0180-ieee1275-ofdisk-retry-on-open-failure.patch +Patch0181: 0181-Allow-chainloading-EFI-apps-from-loop-mounts.patch +Patch0182: 0182-efinet-Add-DHCP-proxy-support.patch +Patch0183: 0183-fs-ext2-Ignore-checksum-seed-incompat-feature.patch +Patch0184: 0184-Don-t-update-the-cmdline-when-generating-legacy-menu.patch +Patch0185: 0185-Suppress-gettext-error-message.patch +Patch0186: 0186-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch +Patch0187: 0187-templates-Check-for-EFI-at-runtime-instead-of-config.patch +Patch0188: 0188-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch +Patch0189: 0189-arm64-Fix-EFI-loader-kernel-image-allocation.patch +Patch0190: 0190-normal-main-Discover-the-device-to-read-the-config-f.patch +Patch0191: 0191-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch +Patch0192: 0192-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch +Patch0193: 0193-Print-module-name-on-license-check-failure.patch +Patch0194: 0194-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch +Patch0195: 0195-grub-mkconfig-restore-umask-for-grub.cfg.patch +Patch0196: 0196-fs-btrfs-Use-full-btrfs-bootloader-area.patch +Patch0197: 0197-Add-Fedora-location-of-DejaVu-SANS-font.patch +Patch0198: 0198-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch +Patch0199: 0199-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch +Patch0200: 0200-EFI-console-Do-not-set-colorstate-until-the-first-te.patch +Patch0201: 0201-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch +Patch0202: 0202-Use-visual-indentation-in-config.h.in.patch +Patch0203: 0203-Where-present-ensure-config-util.h-precedes-config.h.patch +Patch0204: 0204-Drop-gnulib-fix-base64.patch.patch +Patch0205: 0205-Drop-gnulib-no-abort.patch.patch +Patch0206: 0206-Update-gnulib-version-and-drop-most-gnulib-patches.patch +Patch0207: 0207-commands-search-Fix-bug-stopping-iteration-when-no-f.patch +Patch0208: 0208-search-new-efidisk-only-option-on-EFI-systems.patch +Patch0209: 0209-efi-new-connectefi-command.patch +Patch0210: 0210-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch +Patch0211: 0211-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch +Patch0212: 0212-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch +Patch0213: 0213-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch +Patch0214: 0214-powerpc-do-CAS-in-a-more-compatible-way.patch +Patch0215: 0215-powerpc-prefix-detection-support-device-names-with-c.patch +Patch0216: 0216-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch +Patch0217: 0217-make-ofdisk_retries-optional.patch +Patch0218: 0218-loader-efi-chainloader-grub_load_and_start_image-doe.patch +Patch0219: 0219-loader-efi-chainloader-simplify-the-loader-state.patch +Patch0220: 0220-commands-boot-Add-API-to-pass-context-to-loader.patch +Patch0221: 0221-loader-efi-chainloader-Use-grub_loader_set_ex.patch +Patch0222: 0222-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch +Patch0223: 0223-loader-i386-efi-linux-Use-grub_loader_set_ex.patch +Patch0224: 0224-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch +Patch0225: 0225-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch +Patch0226: 0226-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch +Patch0227: 0227-video-readers-png-Abort-sooner-if-a-read-operation-f.patch +Patch0228: 0228-video-readers-png-Refuse-to-handle-multiple-image-he.patch +Patch0229: 0229-video-readers-png-Drop-greyscale-support-to-fix-heap.patch +Patch0230: 0230-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch +Patch0231: 0231-video-readers-png-Sanity-check-some-huffman-codes.patch +Patch0232: 0232-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch +Patch0233: 0233-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch +Patch0234: 0234-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch +Patch0235: 0235-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch +Patch0236: 0236-normal-charset-Fix-array-out-of-bounds-formatting-un.patch +Patch0237: 0237-net-netbuff-Block-overly-large-netbuff-allocs.patch +Patch0238: 0238-net-ip-Do-IP-fragment-maths-safely.patch +Patch0239: 0239-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch +Patch0240: 0240-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch +Patch0241: 0241-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch +Patch0242: 0242-net-tftp-Avoid-a-trivial-UAF.patch +Patch0243: 0243-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch +Patch0244: 0244-net-http-Fix-OOB-write-for-split-http-headers.patch +Patch0245: 0245-net-http-Error-out-on-headers-with-LF-without-CR.patch +Patch0246: 0246-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch +Patch0247: 0247-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch +Patch0248: 0248-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch +Patch0249: 0249-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch +Patch0250: 0250-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch +Patch0251: 0251-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch +Patch0252: 0252-misc-Make-grub_min-and-grub_max-more-resilient.patch +Patch0253: 0253-ReiserFS-switch-to-using-grub_min-grub_max.patch +Patch0254: 0254-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch +Patch0255: 0255-modules-make-.module_license-read-only.patch +Patch0256: 0256-modules-strip-.llvm_addrsig-sections-and-similar.patch +Patch0257: 0257-modules-Don-t-allocate-space-for-non-allocable-secti.patch +Patch0258: 0258-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch +Patch0259: 0259-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch +Patch0260: 0260-modules-load-module-sections-at-page-aligned-address.patch +Patch0261: 0261-nx-add-memory-attribute-get-set-API.patch +Patch0262: 0262-nx-set-page-permissions-for-loaded-modules.patch +Patch0263: 0263-nx-set-attrs-in-our-kernel-loaders.patch +Patch0264: 0264-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch +Patch0265: 0265-grub-probe-document-the-behavior-of-multiple-v.patch +Patch0266: 0266-grub_fs_probe-dprint-errors-from-filesystems.patch +Patch0267: 0267-fs-fat-don-t-error-when-mtime-is-0.patch +Patch0268: 0268-Make-debug-file-show-which-file-filters-get-run.patch +Patch0269: 0269-efi-use-enumerated-array-positions-for-our-allocatio.patch +Patch0270: 0270-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch +Patch0271: 0271-efi-allocate-the-initrd-within-the-bounds-expressed-.patch +Patch0272: 0272-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch +Patch0273: 0273-BLS-create-etc-kernel-cmdline-during-mkconfig.patch +Patch0274: 0274-squish-don-t-dup-rhgb-quiet-check-mtimes.patch +Patch0275: 0275-squish-give-up-on-rhgb-quiet.patch +Patch0276: 0276-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch +Patch0277: 0277-ieee1275-implement-vec5-for-cas-negotiation.patch +Patch0278: 0278-blscfg-Don-t-root-device-in-emu-builds.patch +Patch0279: 0279-loader-arm64-linux-Remove-magic-number-header-field-.patch +Patch0280: 0280-Correct-BSS-zeroing-on-aarch64.patch +Patch0281: 0281-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch +Patch0282: 0282-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch +Patch0283: 0283-commands-efi-tpm-Refine-the-status-of-log-event.patch +Patch0284: 0284-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch +Patch0285: 0285-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch diff --git a/grub2.spec b/grub2.spec index 23c0c55..0e504c2 100644 --- a/grub2.spec +++ b/grub2.spec @@ -17,7 +17,7 @@ Name: grub2 Epoch: 1 Version: 2.06 -Release: 61%{?dist} +Release: 62%{?dist} Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -426,7 +426,6 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %{_datarootdir}/bash-completion/completions/grub %{_sbindir}/grub2-mkconfig %{_sbindir}/grub2-switch-to-blscfg -%{_sbindir}/grub2-rpm-sort %{_sbindir}/grub2-reboot %{_bindir}/grub2-file %{_bindir}/grub2-menulst2cfg @@ -530,6 +529,10 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %endif %changelog +* Tue Nov 01 2022 Robbie Harwood - 1:2.06-62 +- Try dropping custom sort again +- See-also: https://github.com/rpm-software-management/rpm/pull/2249 + * Fri Oct 28 2022 Robbie Harwood - 2.06-61 - TDX measurements to RTMR