summaryrefslogtreecommitdiffstats
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch119
-rw-r--r--debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch158
-rw-r--r--debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch75
-rw-r--r--debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch99
-rw-r--r--debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch37
-rw-r--r--debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch197
-rw-r--r--debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch27
-rw-r--r--debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch168
-rw-r--r--debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch38
-rw-r--r--debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch39
-rw-r--r--debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch254
-rw-r--r--debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch28
-rw-r--r--debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch42
-rw-r--r--debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch73
-rw-r--r--debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch33
-rw-r--r--debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch45
-rw-r--r--debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch43
-rw-r--r--debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch55
-rw-r--r--debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch69
-rw-r--r--debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch111
-rw-r--r--debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch34
-rw-r--r--debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch40
-rw-r--r--debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch45
-rw-r--r--debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch47
-rw-r--r--debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch71
-rw-r--r--debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch131
-rw-r--r--debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch37
-rw-r--r--debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch75
-rw-r--r--debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch133
-rw-r--r--debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch75
-rw-r--r--debian/patches/987008-lvrename-boot-fail.patch35
-rw-r--r--debian/patches/arm64-handover-to-kernel-if-sb-enabled.patch152
-rw-r--r--debian/patches/arm64_remove_magic_number_check.patch37
-rw-r--r--debian/patches/at_keyboard-module-init.patch44
-rw-r--r--debian/patches/bash-completion-drop-have-checks.patch143
-rw-r--r--debian/patches/blacklist-1440x900x32.patch34
-rw-r--r--debian/patches/bootp-new-net_bootp6-command.patch1119
-rw-r--r--debian/patches/bootp-process-dhcpack-http-boot.patch124
-rw-r--r--debian/patches/core-in-fs.patch45
-rw-r--r--debian/patches/cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch109
-rw-r--r--debian/patches/cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch33
-rw-r--r--debian/patches/cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch110
-rw-r--r--debian/patches/cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch81
-rw-r--r--debian/patches/cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch42
-rw-r--r--debian/patches/cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch48
-rw-r--r--debian/patches/cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch65
-rw-r--r--debian/patches/cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch86
-rw-r--r--debian/patches/cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch54
-rw-r--r--debian/patches/cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch85
-rw-r--r--debian/patches/cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch91
-rw-r--r--debian/patches/cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch75
-rw-r--r--debian/patches/cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch36
-rw-r--r--debian/patches/cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch55
-rw-r--r--debian/patches/debug_verifiers.patch28
-rw-r--r--debian/patches/default-grub-d.patch209
-rw-r--r--debian/patches/dejavu-font-path.patch23
-rw-r--r--debian/patches/disable-floppies.patch37
-rw-r--r--debian/patches/disk-cryptodisk-when-cheatmounting-use-the-sector-info-of-the-cheat-device.patch72
-rw-r--r--debian/patches/dpkg-version-comparison.patch38
-rw-r--r--debian/patches/efi-variable-storage-minimise-writes.patch895
-rw-r--r--debian/patches/efinet-set-dns-from-uefi-proto.patch341
-rw-r--r--debian/patches/efinet-set-network-from-uefi-devpath.patch388
-rw-r--r--debian/patches/efinet-uefi-ipv6-pxe-support.patch126
-rw-r--r--debian/patches/fix-lockdown.patch45
-rw-r--r--debian/patches/font-Try-opening-fonts-from-the-bundled-memdisk.patch76
-rw-r--r--debian/patches/fs-tester-time-fail.patch27
-rw-r--r--debian/patches/gcc12_build_array_bounds.patch493
-rw-r--r--debian/patches/gcc12_build_array_bounds2.patch46
-rw-r--r--debian/patches/gcc12_build_dangling_pointer.patch67
-rw-r--r--debian/patches/gettext-quiet.patch30
-rw-r--r--debian/patches/gfxpayload-dynamic.patch290
-rw-r--r--debian/patches/gfxpayload-keep-default.patch39
-rw-r--r--debian/patches/grub-install-extra-removable.patch202
-rw-r--r--debian/patches/grub-install-pvxen-paths.patch71
-rw-r--r--debian/patches/grub-install-removable-shim.patch196
-rw-r--r--debian/patches/grub-legacy-0-based-partitions.patch39
-rw-r--r--debian/patches/grub.cfg-400.patch25
-rw-r--r--debian/patches/grub_mkconfig_restore_umask.patch36
-rw-r--r--debian/patches/grub_os-prober.patch22
-rw-r--r--debian/patches/ieee1275-clear-reset.patch32
-rw-r--r--debian/patches/ignore-grub_func_test-failures.patch29
-rw-r--r--debian/patches/ignore_checksum_seed_incompat_feature.patch54
-rw-r--r--debian/patches/ignore_the_large_dir_incompat_feature.patch53
-rw-r--r--debian/patches/insmod-xzio-and-lzopio-on-xen.patch33
-rw-r--r--debian/patches/install-efi-adjust-distributor.patch34
-rw-r--r--debian/patches/install-efi-fallback.patch91
-rw-r--r--debian/patches/install-locale-langpack.patch116
-rw-r--r--debian/patches/install-powerpc-machtypes.patch220
-rw-r--r--debian/patches/install-signed.patch309
-rw-r--r--debian/patches/install-stage2-confusion.patch46
-rw-r--r--debian/patches/kern-file-Fix-error-handling-in-grub_file_open.patch37
-rw-r--r--debian/patches/linuxefi.patch552
-rw-r--r--debian/patches/maybe-quiet.patch386
-rw-r--r--debian/patches/minilzo-2.10.patch2539
-rw-r--r--debian/patches/mkconfig-loopback.patch96
-rw-r--r--debian/patches/mkconfig-nonexistent-loopback.patch55
-rw-r--r--debian/patches/mkconfig-other-inits.patch90
-rw-r--r--debian/patches/mkconfig-recovery-title.patch130
-rw-r--r--debian/patches/mkconfig-signed-kernel.patch48
-rw-r--r--debian/patches/mkconfig-ubuntu-distributor.patch37
-rw-r--r--debian/patches/mkconfig-ubuntu-recovery.patch107
-rw-r--r--debian/patches/mkimage-fix-section-sizes.patch109
-rw-r--r--debian/patches/mkrescue-efi-modules.patch35
-rw-r--r--debian/patches/net-read-bracketed-ipv6-addr.patch255
-rw-r--r--debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch57
-rw-r--r--debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch46
-rw-r--r--debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch69
-rw-r--r--debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch54
-rw-r--r--debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch89
-rw-r--r--debian/patches/ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch155
-rw-r--r--debian/patches/olpc-prefix-hack.patch51
-rw-r--r--debian/patches/os-prober-Allow-initrd-to-contain-spaces.patch50
-rw-r--r--debian/patches/osdep-devmapper-getroot-have-devmapper-recognize-luks2.patch54
-rw-r--r--debian/patches/osdep-devmapper-getroot-set-up-cheated-luks2-cryptodisk-mount-from-dm-parameters.patch154
-rw-r--r--debian/patches/pc-verifiers-module.patch167
-rw-r--r--debian/patches/ppc64el-disable-vsx.patch52
-rw-r--r--debian/patches/probe-fusionio.patch76
-rw-r--r--debian/patches/quick-boot-lvm.patch77
-rw-r--r--debian/patches/quick-boot.patch358
-rw-r--r--debian/patches/restore-mkdevicemap.patch1326
-rw-r--r--debian/patches/series129
-rw-r--r--debian/patches/skip-grub_cmd_set_date.patch27
-rw-r--r--debian/patches/tests-ahci-update-qemu-device-name.patch34
-rw-r--r--debian/patches/tpm-unknown-error-non-fatal.patch31
-rw-r--r--debian/patches/uefi-secure-boot-cryptomount.patch48
-rw-r--r--debian/patches/vt-handoff.patch101
-rw-r--r--debian/patches/wubi-no-windows.patch57
-rw-r--r--debian/patches/xen-no-xsm-policy-in-non-xsm-options.patch35
-rw-r--r--debian/patches/xfs-fix-v4-superblock.patch122
-rw-r--r--debian/patches/zpool-full-device-name.patch33
130 files changed, 17907 insertions, 0 deletions
diff --git a/debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch b/debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch
new file mode 100644
index 0000000..51a7b68
--- /dev/null
+++ b/debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch
@@ -0,0 +1,119 @@
+From 9c8e1c85ec9971f2c6bb9a8a7530e94f7dbec14a Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Tue, 5 Apr 2022 10:02:04 +0100
+Subject: loader/efi/chainloader: Simplify the loader state
+
+The chainloader command retains the source buffer and device path passed
+to LoadImage(), requiring the unload hook passed to grub_loader_set() to
+free them. It isn't required to retain this state though - they aren't
+required by StartImage() or anything else in the boot hook, so clean them
+up before grub_cmd_chainloader() finishes.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/loader/efi/chainloader.c | 38 +++++++++++++++++-------------
+ 1 file changed, 21 insertions(+), 17 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 2bd80f4db..d1602c89b 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -44,25 +44,20 @@ 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_efi_device_path_t *file_path;
+ static grub_efi_handle_t image_handle;
+-static grub_efi_char16_t *cmdline;
+
+ static grub_err_t
+ grub_chainloader_unload (void)
+ {
++ grub_efi_loaded_image_t *loaded_image;
+ grub_efi_boot_services_t *b;
+
++ loaded_image = grub_efi_get_loaded_image (image_handle);
++ if (loaded_image != NULL)
++ grub_free (loaded_image->load_options);
++
+ b = grub_efi_system_table->boot_services;
+ efi_call_1 (b->unload_image, image_handle);
+- efi_call_2 (b->free_pages, address, pages);
+-
+- grub_free (file_path);
+- grub_free (cmdline);
+- cmdline = 0;
+- file_path = 0;
+
+ grub_dl_unref (my_mod);
+ return GRUB_ERR_NONE;
+@@ -140,7 +135,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)
+@@ -222,11 +217,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ grub_efi_status_t status;
+ grub_efi_boot_services_t *b;
+ grub_device_t dev = 0;
+- grub_efi_device_path_t *dp = 0;
++ grub_efi_device_path_t *dp = NULL, *file_path = NULL;
+ grub_efi_loaded_image_t *loaded_image;
+ char *filename;
+ void *boot_image = 0;
+ grub_efi_handle_t dev_handle = 0;
++ grub_efi_physical_address_t address = 0;
++ grub_efi_uintn_t pages = 0;
++ grub_efi_char16_t *cmdline = NULL;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+@@ -234,11 +232,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;
+-
+ b = grub_efi_system_table->boot_services;
+
+ file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE);
+@@ -408,6 +401,10 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ grub_file_close (file);
+ grub_device_close (dev);
+
++ /* We're finished with the source image buffer and file path now. */
++ efi_call_2 (b->free_pages, address, pages);
++ grub_free (file_path);
++
+ grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
+ return 0;
+
+@@ -419,11 +416,18 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ if (file)
+ grub_file_close (file);
+
++ grub_free (cmdline);
+ grub_free (file_path);
+
+ if (address)
+ efi_call_2 (b->free_pages, address, pages);
+
++ if (image_handle != NULL)
++ {
++ efi_call_1 (b->unload_image, image_handle);
++ image_handle = NULL;
++ }
++
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
diff --git a/debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch b/debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch
new file mode 100644
index 0000000..47caba2
--- /dev/null
+++ b/debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch
@@ -0,0 +1,158 @@
+From bb35dbb9bf213bc9dde9a5a653e93b4c4d2bbf22 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Fri, 29 Apr 2022 21:16:02 +0100
+Subject: 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 <chris.coulson@canonical.com>
+(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 bbca81e94..53691a62d 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 b20864282..1846fa6c5 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/debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch
new file mode 100644
index 0000000..4a4a0e7
--- /dev/null
+++ b/debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch
@@ -0,0 +1,75 @@
+From 19b4f19cfea30655032c978e228d78e056f55f1a Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Tue, 5 Apr 2022 11:48:58 +0100
+Subject: loader/efi/chainloader: Use grub_loader_set_ex()
+
+This ports the EFI chainloader to use grub_loader_set_ex() in order to fix
+a use-after-free bug that occurs when grub_cmd_chainloader() is executed
+more than once before a boot attempt is performed.
+
+Fixes: CVE-2022-28736
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/loader/efi/chainloader.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index d1602c89b..7557eb269 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -44,11 +44,10 @@ GRUB_MOD_LICENSE ("GPLv3+");
+
+ static grub_dl_t my_mod;
+
+-static grub_efi_handle_t image_handle;
+-
+ static grub_err_t
+-grub_chainloader_unload (void)
++grub_chainloader_unload (void *context)
+ {
++ grub_efi_handle_t image_handle = (grub_efi_handle_t) context;
+ grub_efi_loaded_image_t *loaded_image;
+ grub_efi_boot_services_t *b;
+
+@@ -64,8 +63,9 @@ grub_chainloader_unload (void)
+ }
+
+ static grub_err_t
+-grub_chainloader_boot (void)
++grub_chainloader_boot (void *context)
+ {
++ grub_efi_handle_t image_handle = (grub_efi_handle_t) context;
+ grub_efi_boot_services_t *b;
+ grub_efi_status_t status;
+ grub_efi_uintn_t exit_data_size;
+@@ -225,6 +225,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ grub_efi_physical_address_t address = 0;
+ grub_efi_uintn_t pages = 0;
+ grub_efi_char16_t *cmdline = NULL;
++ grub_efi_handle_t image_handle = NULL;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+@@ -405,7 +406,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ efi_call_2 (b->free_pages, address, pages);
+ grub_free (file_path);
+
+- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0);
+ return 0;
+
+ fail:
+@@ -423,10 +424,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ efi_call_2 (b->free_pages, address, pages);
+
+ if (image_handle != NULL)
+- {
+- efi_call_1 (b->unload_image, image_handle);
+- image_handle = NULL;
+- }
++ efi_call_1 (b->unload_image, image_handle);
+
+ grub_dl_unref (my_mod);
+
diff --git a/debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
new file mode 100644
index 0000000..18ecc25
--- /dev/null
+++ b/debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
@@ -0,0 +1,99 @@
+From 24e6d59ac676791507ff5267bf3bef6cbaff6aef Mon Sep 17 00:00:00 2001
+From: Julian Andres Klode <julian.klode@canonical.com>
+Date: Thu, 2 Dec 2021 15:03:53 +0100
+Subject: 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 <julian.klode@canonical.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 c52ec6226..89c4bb3fd 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 6fde244fc..67448165f 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/debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
new file mode 100644
index 0000000..d319507
--- /dev/null
+++ b/debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
@@ -0,0 +1,37 @@
+From c15fa5fb039cd5062dfa02a03efd924422c4a8ed Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 25 Jun 2021 02:19:05 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 58454458c..ffdcaba05 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -79,6 +79,7 @@ grub_file_open (const char *name, enum grub_file_type type)
+
+ device = grub_device_open (device_name);
+ grub_free (device_name);
++ device_name = NULL;
+ if (! device)
+ goto fail;
+
+@@ -131,6 +132,7 @@ grub_file_open (const char *name, enum grub_file_type type)
+ return file;
+
+ fail:
++ grub_free (device_name);
+ if (device)
+ grub_device_close (device);
+
diff --git a/debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
new file mode 100644
index 0000000..58e6e50
--- /dev/null
+++ b/debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
@@ -0,0 +1,197 @@
+From 907f100c841f39e37e4801f726f6b47c2aa9191f Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 14:02:55 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 0157ff742..e2a6b1cf3 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/debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch
new file mode 100644
index 0000000..1c0aba1
--- /dev/null
+++ b/debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch
@@ -0,0 +1,27 @@
+From 5e496e28b3c76666c98b737153f9b0c2bedf489d Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 14:13:40 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 e2a6b1cf3..8955b8ecf 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/debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
new file mode 100644
index 0000000..08c33f8
--- /dev/null
+++ b/debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
@@ -0,0 +1,168 @@
+From 558c69b5d36d14d55bff21e6570205fe73a02ca2 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 18:51:35 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/video/readers/png.c | 87 +++--------------------------------
+ 1 file changed, 7 insertions(+), 80 deletions(-)
+
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index 8955b8ecf..a3161e25b 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/debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
new file mode 100644
index 0000000..7f73935
--- /dev/null
+++ b/debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
@@ -0,0 +1,38 @@
+From 21e3b255f91d9b7711f8346f1e4acf8cc19bf4fb Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 23:25:07 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 a3161e25b..d7ed5aa6c 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/debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch b/debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch
new file mode 100644
index 0000000..b355584
--- /dev/null
+++ b/debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch
@@ -0,0 +1,39 @@
+From e1c0a986e39ab93954436bcf6e6a9a7ea465e4e7 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 19:19:11 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 d7ed5aa6c..7f2ba7849 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/debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
new file mode 100644
index 0000000..1f5b558
--- /dev/null
+++ b/debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
@@ -0,0 +1,254 @@
+From 40be99c5f8162887d1922fb9428b39de4cdad3af Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Jun 2021 14:16:14 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 e31602f76..10225abd5 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/debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
new file mode 100644
index 0000000..c4228f9
--- /dev/null
+++ b/debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
@@ -0,0 +1,28 @@
+From 610c5986058312cfc0375fc04f88fcc116bdd043 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Jun 2021 14:16:58 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 10225abd5..caa211f06 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/debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
new file mode 100644
index 0000000..07fd802
--- /dev/null
+++ b/debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
@@ -0,0 +1,42 @@
+From 9286f0009b922571c247012e699c3ed5f6e918bc Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Jun 2021 14:25:17 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 caa211f06..1df1171d7 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/debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
new file mode 100644
index 0000000..b292cbc
--- /dev/null
+++ b/debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
@@ -0,0 +1,73 @@
+From a10c2350a766f9b315735931a49499a7e2c77bf3 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 7 Jul 2021 15:38:19 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/video/readers/jpeg.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
+index 1df1171d7..97a533b24 100644
+--- a/grub-core/video/readers/jpeg.c
++++ b/grub-core/video/readers/jpeg.c
+@@ -23,6 +23,7 @@
+ #include <grub/mm.h>
+ #include <grub/misc.h>
+ #include <grub/bufio.h>
++#include <grub/safemath.h>
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+@@ -693,6 +694,7 @@ static grub_err_t
+ grub_jpeg_decode_data (struct grub_jpeg_data *data)
+ {
+ unsigned c1, vb, hb, nr1, nc1;
++ unsigned stride_a, stride_b, stride;
+ int rst = data->dri;
+ grub_err_t err = GRUB_ERR_NONE;
+
+@@ -705,8 +707,14 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: attempted to decode data before start of stream");
+
++ if (grub_mul(vb, data->image_width, &stride_a) ||
++ grub_mul(hb, nc1, &stride_b) ||
++ grub_sub(stride_a, stride_b, &stride))
++ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++ "jpeg: cannot decode image with these dimensions");
++
+ for (; data->r1 < nr1 && (!data->dri || rst);
+- data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
++ data->r1++, data->bitmap_ptr += stride * 3)
+ for (c1 = 0; c1 < nc1 && (!data->dri || rst);
+ c1++, rst--, data->bitmap_ptr += hb * 3)
+ {
diff --git a/debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
new file mode 100644
index 0000000..066775a
--- /dev/null
+++ b/debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
@@ -0,0 +1,33 @@
+From 557370849b914110a9efbd7256dc3942a8af8b99 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 13 Jul 2021 13:24:38 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 4dfcc3107..7a5a7c153 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/debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch b/debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch
new file mode 100644
index 0000000..150f101
--- /dev/null
+++ b/debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch
@@ -0,0 +1,45 @@
+From 4ea64c827f8bc57180772fd5671ddd010cb7b2ed Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 8 Mar 2022 23:47:46 +1100
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 dbeeefe47..d5e9e9a0d 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/debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch b/debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch
new file mode 100644
index 0000000..7c5d8dc
--- /dev/null
+++ b/debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch
@@ -0,0 +1,43 @@
+From 2a4f87df650fd2ef639b48b43fc834b97b6b2bfa Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 20 Dec 2021 19:41:21 +1100
+Subject: net/ip: Do IP fragment maths safely
+
+This avoids an underflow and subsequent unpleasantness.
+
+Fixes: CVE-2022-28733
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 01410798b..937be8767 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -25,6 +25,7 @@
+ #include <grub/net/netbuff.h>
+ #include <grub/mm.h>
+ #include <grub/priority_queue.h>
++#include <grub/safemath.h>
+ #include <grub/time.h>
+
+ 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/debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
new file mode 100644
index 0000000..0f3cdc7
--- /dev/null
+++ b/debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
@@ -0,0 +1,55 @@
+From 21158c5dfb5e0c5015277346128903397d498da4 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 16 Sep 2021 01:29:54 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 906ec7d67..135faac03 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/debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
new file mode 100644
index 0000000..0fc28a9
--- /dev/null
+++ b/debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
@@ -0,0 +1,69 @@
+From 968febf3a4de5df0f91cc13bc6b6053fc22575e1 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 20 Dec 2021 21:55:43 +1100
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 135faac03..17961a9f1 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/debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
new file mode 100644
index 0000000..bb4cd8c
--- /dev/null
+++ b/debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
@@ -0,0 +1,111 @@
+From e7573be61b3cf005cdf0a068652153437daca4b3 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 20 Sep 2021 01:12:24 +1000
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 15a2f29a9..af7440776 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1548,7 +1548,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;
+ }
+@@ -1770,7 +1771,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;
+ }
+@@ -1779,6 +1783,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 f3e787938..d1afa2535 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -404,6 +404,7 @@ tftp_open (struct grub_file *file, const char *filename)
+ {
+ grub_net_udp_close (data->sock);
+ grub_free (data);
++ file->data = NULL;
+ return grub_errno;
+ }
+
+diff --git a/include/grub/net.h b/include/grub/net.h
+index cbcae79b1..8d71ca6cc 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -277,6 +277,7 @@ typedef struct grub_net
+ grub_fs_t fs;
+ int eof;
+ int stall;
++ int broken;
+ } *grub_net_t;
+
+ extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
diff --git a/debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch b/debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch
new file mode 100644
index 0000000..8e42215
--- /dev/null
+++ b/debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch
@@ -0,0 +1,34 @@
+From fb66f40ba67b88408a43cb38492053985bfe4968 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 18 Jan 2022 14:29:20 +1100
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 d1afa2535..4222d93b6 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/debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
new file mode 100644
index 0000000..763e46a
--- /dev/null
+++ b/debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
@@ -0,0 +1,40 @@
+From 6df718714dea5043243e367750b5c6abebcf79fe Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 1 Mar 2022 23:14:15 +1100
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 3fe155f1b..ef6eaff0d 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -422,7 +422,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);
+@@ -430,7 +430,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/debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch b/debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch
new file mode 100644
index 0000000..3b6ff59
--- /dev/null
+++ b/debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch
@@ -0,0 +1,45 @@
+From f407a45bd3483f6bbf58c5e9386a44caa14287e3 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 8 Mar 2022 18:17:03 +1100
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 ef6eaff0d..9f45ad4e8 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -190,9 +190,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/debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch b/debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch
new file mode 100644
index 0000000..5b7ede1
--- /dev/null
+++ b/debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch
@@ -0,0 +1,47 @@
+From 870b94755b6a341d21632293677b346ff033e5f0 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 8 Mar 2022 19:04:40 +1100
+Subject: 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 <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 9f45ad4e8..6988d38fb 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -68,7 +68,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/debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
new file mode 100644
index 0000000..cc6520e
--- /dev/null
+++ b/debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
@@ -0,0 +1,71 @@
+From 2d014248d540c7e087934a94b6e7a2aa7fc2c704 Mon Sep 17 00:00:00 2001
+From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Date: Wed, 6 Apr 2022 18:03:37 +0530
+Subject: 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 <sudhakar@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 8a9992ca9..63702214b 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/debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
new file mode 100644
index 0000000..5f06bd4
--- /dev/null
+++ b/debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
@@ -0,0 +1,131 @@
+From 9561d7ef621e5e68f12bcd916252ef1c11e60366 Mon Sep 17 00:00:00 2001
+From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Date: Wed, 6 Apr 2022 18:49:09 +0530
+Subject: 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 <sudhakar@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 63702214b..8898b235e 100644
+--- a/grub-core/fs/f2fs.c
++++ b/grub-core/fs/f2fs.c
+@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */
+
+ #define MAX_VOLUME_NAME 512
++#define MAX_NAT_BITMAP_SIZE 3900
+
+ enum FILE_TYPE
+ {
+@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
+ grub_uint32_t checksum_offset;
+ grub_uint64_t elapsed_time;
+ grub_uint8_t alloc_type[MAX_ACTIVE_LOGS];
+- grub_uint8_t sit_nat_version_bitmap[3900];
++ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
+ grub_uint32_t checksum;
+ } GRUB_PACKED;
+
+@@ -302,6 +303,7 @@ struct grub_f2fs_data
+
+ struct grub_f2fs_nat_journal nat_j;
+ char *nat_bitmap;
++ grub_uint32_t nat_bitmap_size;
+
+ grub_disk_t disk;
+ struct grub_f2fs_node *inode;
+@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
+ }
+
+ static void *
+-nat_bitmap_ptr (struct grub_f2fs_data *data)
++nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
+ {
+ struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
+ grub_uint32_t offset;
++ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
+
+ if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
+ return ckpt->sit_nat_version_bitmap;
+
+ offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
++ if (offset >= MAX_NAT_BITMAP_SIZE)
++ return NULL;
++
++ *nat_bitmap_size = *nat_bitmap_size - offset;
+
+ return ckpt->sit_nat_version_bitmap + offset;
+ }
+@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
+ }
+
+ static int
+-grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
++grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
+ {
+ int mask;
++ grub_uint32_t shifted_nr = (nr >> 3);
++
++ if (shifted_nr >= len)
++ return -1;
+
+- p += (nr >> 3);
++ p += shifted_nr;
+ mask = 1 << (7 - (nr & 0x07));
+
+ return mask & *p;
+@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
+ grub_uint32_t seg_off, block_off, entry_off, block_addr;
+ grub_uint32_t blkaddr = 0;
+ grub_err_t err;
++ int result_bit;
+
+ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
+ if (err != GRUB_ERR_NONE)
+@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
+ ((seg_off * data->blocks_per_seg) << 1) +
+ (block_off & (data->blocks_per_seg - 1));
+
+- if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
++ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
++ data->nat_bitmap_size);
++ if (result_bit > 0)
+ block_addr += data->blocks_per_seg;
++ else if (result_bit == -1)
++ {
++ grub_free (nat_block);
++ return 0;
++ }
+
+ err = grub_f2fs_block_read (data, block_addr, nat_block);
+ if (err)
+@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk)
+ if (err)
+ goto fail;
+
+- data->nat_bitmap = nat_bitmap_ptr (data);
++ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
++ if (data->nat_bitmap == NULL)
++ goto fail;
+
+ err = get_nat_journal (data);
+ if (err)
diff --git a/debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
new file mode 100644
index 0000000..cf71b38
--- /dev/null
+++ b/debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
@@ -0,0 +1,37 @@
+From 998bd74c11c0e00f69fe2f37a8200381faf51061 Mon Sep 17 00:00:00 2001
+From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Date: Wed, 6 Apr 2022 18:17:43 +0530
+Subject: 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 <sudhakar@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 8898b235e..df6beb544 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/debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
new file mode 100644
index 0000000..d02cbe2
--- /dev/null
+++ b/debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
@@ -0,0 +1,75 @@
+From 23c785c3e965731ac440f9c150fdfeec6dd433e7 Mon Sep 17 00:00:00 2001
+From: Darren Kenny <darren.kenny@oracle.com>
+Date: Tue, 29 Mar 2022 10:49:56 +0000
+Subject: 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 <darren.kenny@oracle.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 63203034d..eb9857d74 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -1961,6 +1961,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
+ int r = 0;
+ grub_uint64_t tree;
+ grub_uint8_t type;
++ grub_size_t est_size = 0;
+
+ if (!data)
+ return grub_errno;
+@@ -2019,6 +2020,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;
+@@ -2029,6 +2042,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/debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
new file mode 100644
index 0000000..4ae22c9
--- /dev/null
+++ b/debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
@@ -0,0 +1,133 @@
+From 22976cf1b9864455173e1bfc617bc63f13fbecf7 Mon Sep 17 00:00:00 2001
+From: Darren Kenny <darren.kenny@oracle.com>
+Date: Tue, 29 Mar 2022 15:52:46 +0000
+Subject: 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 <darren.kenny@oracle.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 eb9857d74..b3d71cd9e 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -912,6 +912,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;
+@@ -970,6 +976,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);
+@@ -989,6 +1005,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:
+@@ -1025,6 +1054,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:
+@@ -1124,6 +1167,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 %"
+@@ -1136,6 +1181,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/debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
new file mode 100644
index 0000000..30c2dad
--- /dev/null
+++ b/debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
@@ -0,0 +1,75 @@
+From 589500ad3777d1335c8e5cb139f7c0c6089112a8 Mon Sep 17 00:00:00 2001
+From: Darren Kenny <darren.kenny@oracle.com>
+Date: Thu, 7 Apr 2022 15:18:12 +0000
+Subject: fs/btrfs: Fix more fuzz issues related to chunks
+
+The corpus was generating issues in grub_btrfs_read_logical() when
+attempting to iterate over stripe entries in the superblock's
+bootmapping.
+
+In most cases the reason for the failure was that the number of stripes
+in chunk->nstripes exceeded the possible space statically allocated in
+superblock bootmapping space. Each stripe entry in the bootmapping block
+consists of a grub_btrfs_key followed by a grub_btrfs_chunk_stripe.
+
+Another issue that came up was that while calculating the chunk size,
+in an earlier piece of code in that function, depending on the data
+provided in the btrfs file system, it would end up calculating a size
+that was too small to contain even 1 grub_btrfs_chunk_item, which is
+obviously invalid too.
+
+Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ 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 b3d71cd9e..54a46b8f8 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -918,6 +918,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;
+@@ -1165,6 +1176,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;
+@@ -1191,6 +1209,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/debian/patches/987008-lvrename-boot-fail.patch b/debian/patches/987008-lvrename-boot-fail.patch
new file mode 100644
index 0000000..5d5df3e
--- /dev/null
+++ b/debian/patches/987008-lvrename-boot-fail.patch
@@ -0,0 +1,35 @@
+Description: fix renamed LV detection
+ It looks like the detection of the LVM logical volumes fails in
+ certain edge conditions. In particular, it was reported that
+ renaming an LV will make grub fail to boot from the system as it
+ cannot properly detect it anymore.
+ .
+ I have looked at the code surrounding the patch and cannot claim to
+ understand the entire function here, as it is huge and quite
+ cryptic. But it seems sane: the `ptr` we're inspecting here starts
+ at the `rlocn->offset`, but we were adding `mda_size` to the
+ (somewhat) unrelated metadatabuf instead. Now we're marking the
+ `mda_end` correctly, based on the rlocn->offsite and ->size.
+ .
+ I have not tested this myself as the test setup is quite involved,
+ but it seems others (e.g. "Hoyer, David" <David.Hoyer@netapp.com>)
+ have tested the patch and confirmed it worked.
+Author: Rogier <rogier777@gmail.com>
+Origin: other
+Bug: https://savannah.gnu.org/bugs/index.php?61620
+Bug-Debian: https://bugs.debian.org/987008
+Forwarded: https://savannah.gnu.org/bugs/index.php?61620
+Reviewed-By: Antoine Beaupré
+Last-Update: 2023-02-25
+
+--- grub2-2.06.orig/grub-core/disk/lvm.c
++++ grub2-2.06/grub-core/disk/lvm.c
+@@ -290,7 +290,7 @@ grub_lvm_detect (grub_disk_t disk,
+
+ p = q = (char *)ptr;
+
+- if (grub_add ((grub_size_t)metadatabuf, (grub_size_t)mda_size, &ptr))
++ if (grub_add (ptr, (grub_size_t)grub_le_to_cpu64 (rlocn->size), &ptr))
+ goto error_parsing_metadata;
+
+ mda_end = (char *)ptr;
diff --git a/debian/patches/arm64-handover-to-kernel-if-sb-enabled.patch b/debian/patches/arm64-handover-to-kernel-if-sb-enabled.patch
new file mode 100644
index 0000000..e20d4ad
--- /dev/null
+++ b/debian/patches/arm64-handover-to-kernel-if-sb-enabled.patch
@@ -0,0 +1,152 @@
+From: Emanuele Rocca <ema@debian.org>
+Date: Fri, 31 Mar 2023 12:38:52 +0200
+Subject: Cherry-pick parts of "Load arm with SB enabled."
+
+Fix Secure Boot on arm64 by cherry-picking the relevant parts of upstream patch
+"Load arm with SB enabled."
+
+Signed-off-by: Emanuele Rocca <ema@debian.org>
+
+Origin: vendor, https://github.com/rhboot/grub2/commit/2786ab864cf00c15123320671f653e9a36ba12b4
+---
+
+Index: grub.git/grub-core/loader/arm64/linux.c
+===================================================================
+--- grub.git.orig/grub-core/loader/arm64/linux.c
++++ grub.git/grub-core/loader/arm64/linux.c
+@@ -16,6 +16,7 @@
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
++#include <grub/cache.h>
+ #include <grub/charset.h>
+ #include <grub/command.h>
+ #include <grub/err.h>
+@@ -33,6 +34,7 @@
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+ #include <grub/verify.h>
++#include <grub/efi/sb.h>
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+@@ -41,6 +43,7 @@ static int loaded;
+
+ static void *kernel_addr;
+ static grub_uint64_t kernel_size;
++static grub_uint32_t handover_offset;
+
+ static char *linux_args;
+ static grub_uint32_t cmdline_size;
+@@ -48,6 +51,15 @@ static grub_uint32_t cmdline_size;
+ static grub_addr_t initrd_start;
+ static grub_addr_t initrd_end;
+
++struct grub_arm64_linux_pe_header
++{
++ grub_uint32_t magic;
++ struct grub_pe32_coff_header coff;
++ struct grub_pe64_optional_header opt;
++};
++
++typedef void (*handover_func) (void *, grub_efi_system_table_t *);
++
+ grub_err_t
+ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh)
+ {
+@@ -64,7 +76,8 @@ grub_arch_efi_linux_check_image (struct
+ static grub_err_t
+ finalize_params_linux (void)
+ {
+- int node, retval;
++ grub_efi_loaded_image_t *loaded_image = NULL;
++ int node, retval, len;
+
+ void *fdt;
+
+@@ -99,6 +112,27 @@ finalize_params_linux (void)
+ if (grub_fdt_install() != GRUB_ERR_NONE)
+ goto failure;
+
++ grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
++ fdt);
++
++ /* Convert command line to UCS-2 */
++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
++ if (!loaded_image) {
++ grub_dprintf ("linux", "Error loading image with grub_efi_get_loaded_image()\n");
++ goto failure;
++ }
++
++ loaded_image->load_options_size = len =
++ (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
++ loaded_image->load_options =
++ grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
++ if (!loaded_image->load_options)
++ return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
++
++ loaded_image->load_options_size =
++ 2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
++ (grub_uint8_t *) linux_args, len, NULL);
++
+ return GRUB_ERR_NONE;
+
+ failure:
+@@ -116,6 +150,39 @@ grub_arch_efi_linux_boot_image (grub_add
+ grub_efi_loaded_image_t *loaded_image;
+ int len;
+
++#ifdef __aarch64__ /* SB only enabled for arm64 */
++ handover_func hf;
++
++ if (grub_efi_get_secureboot() == GRUB_EFI_SECUREBOOT_MODE_ENABLED) {
++ grub_dprintf ("linux", "GRUB_EFI_SECUREBOOT_MODE enabled\n");
++ /*
++ * 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;
++ grub_dprintf ("linux", "Loaded Image base address set to %p\n", kernel_addr);
++ }
++ else
++ grub_dprintf ("linux", "Loaded Image base address could not be set\n");
++
++ grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p\n",
++ kernel_addr, (void *)(grub_efi_uintn_t)handover_offset);
++
++ /* Invalidate the instruction cache */
++ grub_arch_sync_caches((void *)kernel_addr, kernel_size);
++
++ hf = (handover_func)((char *)kernel_addr + handover_offset);
++ hf (grub_efi_image_handle, grub_efi_system_table);
++
++ return GRUB_ERR_BUG;
++ }
++
++ grub_dprintf ("linux", "GRUB_EFI_SECUREBOOT_MODE is NOT enabled\n");
++#endif
++
+ mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
+ if (!mempath)
+ return grub_errno;
+@@ -285,6 +352,7 @@ grub_cmd_linux (grub_command_t cmd __att
+ {
+ grub_file_t file = 0;
+ struct linux_arch_kernel_header lh;
++ struct grub_arm64_linux_pe_header *pe;
+ grub_err_t err;
+
+ grub_dl_ref (my_mod);
+@@ -330,6 +398,9 @@ grub_cmd_linux (grub_command_t cmd __att
+
+ grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
+
++ pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
++ handover_offset = pe->opt.entry_addr;
++
+ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
+ linux_args = grub_malloc (cmdline_size);
+ if (!linux_args)
diff --git a/debian/patches/arm64_remove_magic_number_check.patch b/debian/patches/arm64_remove_magic_number_check.patch
new file mode 100644
index 0000000..acc0897
--- /dev/null
+++ b/debian/patches/arm64_remove_magic_number_check.patch
@@ -0,0 +1,37 @@
+commit 69edb31205602c29293a8c6e67363bba2a4a1e66
+Author: Ard Biesheuvel <ardb@kernel.org>
+Date: Thu Aug 11 16:51:57 2022 +0200
+
+ 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 <ardb@kernel.org>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index ef3e9f944..4c92e48ac 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -51,9 +51,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_PE32_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/debian/patches/at_keyboard-module-init.patch b/debian/patches/at_keyboard-module-init.patch
new file mode 100644
index 0000000..deb713d
--- /dev/null
+++ b/debian/patches/at_keyboard-module-init.patch
@@ -0,0 +1,44 @@
+From e619f11201a4d93ce36d384221c899f88f7618c9 Mon Sep 17 00:00:00 2001
+From: Jeroen Dekkers <jeroen@dekkers.ch>
+Date: Sat, 12 Jan 2019 21:02:18 +0100
+Subject: at_keyboard: initialize keyboard in module init if keyboard is ready
+
+The change in 0c62a5b2 caused at_keyboard to fail on some
+machines. Immediately initializing the keyboard in the module init if
+the keyboard is ready makes the problem go away.
+
+Bug-Debian: https://bugs.debian.org/741464
+Last-Update: 2019-02-09
+
+Patch-Name: at_keyboard-module-init.patch
+---
+ grub-core/term/at_keyboard.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index 597111077..beb007002 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -244,6 +244,14 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
+ return ret;
+ }
+
++static grub_err_t
++grub_keyboard_controller_mod_init (struct grub_term_input *term __attribute__ ((unused))) {
++ if (KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS)))
++ grub_keyboard_controller_init ();
++
++ return GRUB_ERR_NONE;
++}
++
+ static void
+ grub_keyboard_controller_init (void)
+ {
+@@ -314,6 +322,7 @@ grub_at_restore_hw (void)
+ static struct grub_term_input grub_at_keyboard_term =
+ {
+ .name = "at_keyboard",
++ .init = grub_keyboard_controller_mod_init,
+ .fini = grub_keyboard_controller_fini,
+ .getkey = grub_at_keyboard_getkey
+ };
diff --git a/debian/patches/bash-completion-drop-have-checks.patch b/debian/patches/bash-completion-drop-have-checks.patch
new file mode 100644
index 0000000..c425471
--- /dev/null
+++ b/debian/patches/bash-completion-drop-have-checks.patch
@@ -0,0 +1,143 @@
+From c543561137513e37ae17879366ebf4e10348daa2 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Fri, 16 Nov 2018 16:37:02 +0000
+Subject: bash-completion: Drop "have" checks
+
+These don't work with and aren't needed by dynamically-loaded
+completions.
+
+Bug-Debian: https://bugs.debian.org/912852
+Forwarded: no
+Last-Update: 2018-11-16
+
+Patch-Name: bash-completion-drop-have-checks.patch
+---
+ .../bash-completion.d/grub-completion.bash.in | 39 +++++++------------
+ 1 file changed, 13 insertions(+), 26 deletions(-)
+
+diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in
+index 44bf135b9..d4235e7ef 100644
+--- a/util/bash-completion.d/grub-completion.bash.in
++++ b/util/bash-completion.d/grub-completion.bash.in
+@@ -166,13 +166,11 @@ _grub_set_entry () {
+ }
+
+ __grub_set_default_program="@grub_set_default@"
+-have ${__grub_set_default_program} && \
+- complete -F _grub_set_entry -o filenames ${__grub_set_default_program}
++complete -F _grub_set_entry -o filenames ${__grub_set_default_program}
+ unset __grub_set_default_program
+
+ __grub_reboot_program="@grub_reboot@"
+-have ${__grub_reboot_program} && \
+- complete -F _grub_set_entry -o filenames ${__grub_reboot_program}
++complete -F _grub_set_entry -o filenames ${__grub_reboot_program}
+ unset __grub_reboot_program
+
+
+@@ -198,8 +196,7 @@ _grub_editenv () {
+ }
+
+ __grub_editenv_program="@grub_editenv@"
+-have ${__grub_editenv_program} && \
+- complete -F _grub_editenv -o filenames ${__grub_editenv_program}
++complete -F _grub_editenv -o filenames ${__grub_editenv_program}
+ unset __grub_editenv_program
+
+
+@@ -219,8 +216,7 @@ _grub_mkconfig () {
+ fi
+ }
+ __grub_mkconfig_program="@grub_mkconfig@"
+-have ${__grub_mkconfig_program} && \
+- complete -F _grub_mkconfig -o filenames ${__grub_mkconfig_program}
++complete -F _grub_mkconfig -o filenames ${__grub_mkconfig_program}
+ unset __grub_mkconfig_program
+
+
+@@ -254,13 +250,11 @@ _grub_setup () {
+ }
+
+ __grub_bios_setup_program="@grub_bios_setup@"
+-have ${__grub_bios_setup_program} && \
+- complete -F _grub_setup -o filenames ${__grub_bios_setup_program}
++complete -F _grub_setup -o filenames ${__grub_bios_setup_program}
+ unset __grub_bios_setup_program
+
+ __grub_sparc64_setup_program="@grub_sparc64_setup@"
+-have ${__grub_sparc64_setup_program} && \
+- complete -F _grub_setup -o filenames ${__grub_sparc64_setup_program}
++complete -F _grub_setup -o filenames ${__grub_sparc64_setup_program}
+ unset __grub_sparc64_setup_program
+
+
+@@ -305,8 +299,7 @@ _grub_install () {
+ fi
+ }
+ __grub_install_program="@grub_install@"
+-have ${__grub_install_program} && \
+- complete -F _grub_install -o filenames ${__grub_install_program}
++complete -F _grub_install -o filenames ${__grub_install_program}
+ unset __grub_install_program
+
+
+@@ -327,8 +320,7 @@ _grub_mkfont () {
+ fi
+ }
+ __grub_mkfont_program="@grub_mkfont@"
+-have ${__grub_mkfont_program} && \
+- complete -F _grub_mkfont -o filenames ${__grub_mkfont_program}
++complete -F _grub_mkfont -o filenames ${__grub_mkfont_program}
+ unset __grub_mkfont_program
+
+
+@@ -358,8 +350,7 @@ _grub_mkrescue () {
+ fi
+ }
+ __grub_mkrescue_program="@grub_mkrescue@"
+-have ${__grub_mkrescue_program} && \
+- complete -F _grub_mkrescue -o filenames ${__grub_mkrescue_program}
++complete -F _grub_mkrescue -o filenames ${__grub_mkrescue_program}
+ unset __grub_mkrescue_program
+
+
+@@ -400,8 +391,7 @@ _grub_mkimage () {
+ fi
+ }
+ __grub_mkimage_program="@grub_mkimage@"
+-have ${__grub_mkimage_program} && \
+- complete -F _grub_mkimage -o filenames ${__grub_mkimage_program}
++complete -F _grub_mkimage -o filenames ${__grub_mkimage_program}
+ unset __grub_mkimage_program
+
+
+@@ -422,8 +412,7 @@ _grub_mkpasswd_pbkdf2 () {
+ fi
+ }
+ __grub_mkpasswd_pbkdf2_program="@grub_mkpasswd_pbkdf2@"
+-have ${__grub_mkpasswd_pbkdf2_program} && \
+- complete -F _grub_mkpasswd_pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program}
++complete -F _grub_mkpasswd_pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program}
+ unset __grub_mkpasswd_pbkdf2_program
+
+
+@@ -460,8 +449,7 @@ _grub_probe () {
+ fi
+ }
+ __grub_probe_program="@grub_probe@"
+-have ${__grub_probe_program} && \
+- complete -F _grub_probe -o filenames ${__grub_probe_program}
++complete -F _grub_probe -o filenames ${__grub_probe_program}
+ unset __grub_probe_program
+
+
+@@ -482,8 +470,7 @@ _grub_script_check () {
+ fi
+ }
+ __grub_script_check_program="@grub_script_check@"
+-have ${__grub_script_check_program} && \
+- complete -F _grub_script_check -o filenames ${__grub_script_check_program}
++complete -F _grub_script_check -o filenames ${__grub_script_check_program}
+
+
+ # Local variables:
diff --git a/debian/patches/blacklist-1440x900x32.patch b/debian/patches/blacklist-1440x900x32.patch
new file mode 100644
index 0000000..e19fc08
--- /dev/null
+++ b/debian/patches/blacklist-1440x900x32.patch
@@ -0,0 +1,34 @@
+From ee6cee995e403b3fa81798cddb5247be6de3205b Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:11 +0000
+Subject: Blacklist 1440x900x32 from VBE preferred mode handling
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/701111
+Forwarded: no
+Last-Update: 2013-11-14
+
+Patch-Name: blacklist-1440x900x32.patch
+---
+ grub-core/video/i386/pc/vbe.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c
+index b7f911926..4b1bd7d5e 100644
+--- a/grub-core/video/i386/pc/vbe.c
++++ b/grub-core/video/i386/pc/vbe.c
+@@ -1054,6 +1054,15 @@ grub_video_vbe_setup (unsigned int width, unsigned int height,
+ || vbe_mode_info.y_resolution > height)
+ /* Resolution exceeds that of preferred mode. */
+ continue;
++
++ /* Blacklist 1440x900x32 from preferred mode handling until a
++ better solution is available. This mode causes problems on
++ many Thinkpads. See:
++ https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/701111 */
++ if (vbe_mode_info.x_resolution == 1440 &&
++ vbe_mode_info.y_resolution == 900 &&
++ vbe_mode_info.bits_per_pixel == 32)
++ continue;
+ }
+ else
+ {
diff --git a/debian/patches/bootp-new-net_bootp6-command.patch b/debian/patches/bootp-new-net_bootp6-command.patch
new file mode 100644
index 0000000..775213a
--- /dev/null
+++ b/debian/patches/bootp-new-net_bootp6-command.patch
@@ -0,0 +1,1119 @@
+From 2ce72d9b58e2166f47603851fb9b66acb314cca1 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 27 Oct 2016 17:41:04 -0400
+Subject: 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 <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+
+Last-Update: 2021-09-24
+
+Patch-Name: bootp-new-net_bootp6-command.patch
+---
+ grub-core/net/bootp.c | 908 +++++++++++++++++++++++++++++++++++++++++-
+ grub-core/net/ip.c | 39 ++
+ include/grub/net.h | 72 ++++
+ 3 files changed, 1018 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 6fb562702..00c11af39 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -24,6 +24,98 @@
+ #include <grub/net/netbuff.h>
+ #include <grub/net/udp.h>
+ #include <grub/datetime.h>
++#include <grub/time.h>
++#include <grub/list.h>
++
++static int
++dissect_url (const char *url, char **proto, char **host, char **path)
++{
++ const char *p, *ps;
++ grub_size_t l;
++
++ *proto = *host = *path = NULL;
++ ps = p = url;
++
++ while ((p = grub_strchr (p, ':')))
++ {
++ if (grub_strlen (p) < sizeof ("://") - 1)
++ break;
++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
++ {
++ l = p - ps;
++ *proto = grub_malloc (l + 1);
++ if (!*proto)
++ {
++ grub_print_error ();
++ return 0;
++ }
++
++ grub_memcpy (*proto, ps, l);
++ (*proto)[l] = '\0';
++ p += sizeof ("://") - 1;
++ break;
++ }
++ ++p;
++ }
++
++ if (!*proto)
++ {
++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
++ return 0;
++ }
++
++ ps = p;
++ p = grub_strchr (p, '/');
++
++ if (!p)
++ {
++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
++ grub_free (*proto);
++ *proto = NULL;
++ return 0;
++ }
++
++ l = p - ps;
++
++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
++ {
++ *host = grub_malloc (l - 1);
++ if (!*host)
++ {
++ grub_print_error ();
++ grub_free (*proto);
++ *proto = NULL;
++ return 0;
++ }
++ grub_memcpy (*host, ps + 1, l - 2);
++ (*host)[l - 2] = 0;
++ }
++ else
++ {
++ *host = grub_malloc (l + 1);
++ if (!*host)
++ {
++ grub_print_error ();
++ grub_free (*proto);
++ *proto = NULL;
++ return 0;
++ }
++ grub_memcpy (*host, ps, l);
++ (*host)[l] = 0;
++ }
++
++ *path = grub_strdup (p);
++ if (!*path)
++ {
++ grub_print_error ();
++ grub_free (*host);
++ grub_free (*proto);
++ *host = NULL;
++ *proto = NULL;
++ return 0;
++ }
++ return 1;
++}
+
+ struct grub_dhcp_discover_options
+ {
+@@ -607,6 +699,578 @@ out:
+ return err;
+ }
+
++/* The default netbuff size for sending DHCPv6 packets which should be
++ large enough to hold the information */
++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512
++
++struct grub_dhcp6_options
++{
++ grub_uint8_t *client_duid;
++ grub_uint16_t client_duid_len;
++ grub_uint8_t *server_duid;
++ grub_uint16_t server_duid_len;
++ grub_uint32_t iaid;
++ grub_uint32_t t1;
++ grub_uint32_t t2;
++ grub_net_network_level_address_t *ia_addr;
++ grub_uint32_t preferred_lifetime;
++ grub_uint32_t valid_lifetime;
++ grub_net_network_level_address_t *dns_server_addrs;
++ grub_uint16_t num_dns_server;
++ char *boot_file_proto;
++ char *boot_file_server_ip;
++ char *boot_file_path;
++};
++
++typedef struct grub_dhcp6_options *grub_dhcp6_options_t;
++
++struct grub_dhcp6_session
++{
++ struct grub_dhcp6_session *next;
++ struct grub_dhcp6_session **prev;
++ grub_uint32_t iaid;
++ grub_uint32_t transaction_id:24;
++ grub_uint64_t start_time;
++ struct grub_net_dhcp6_option_duid_ll duid;
++ struct grub_net_network_level_interface *iface;
++
++ /* The associated dhcpv6 options */
++ grub_dhcp6_options_t adv;
++ grub_dhcp6_options_t reply;
++};
++
++typedef struct grub_dhcp6_session *grub_dhcp6_session_t;
++
++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data);
++
++static void
++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size,
++ dhcp6_option_hook_fn hook, void *hook_data);
++
++static void
++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data)
++{
++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data;
++
++ grub_uint16_t code = grub_be_to_cpu16 (opt->code);
++ grub_uint16_t len = grub_be_to_cpu16 (opt->len);
++
++ if (code == GRUB_NET_DHCP6_OPTION_IAADDR)
++ {
++ const struct grub_net_dhcp6_option_iaaddr *iaaddr;
++ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data;
++
++ if (len < sizeof (*iaaddr))
++ {
++ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len);
++ return;
++ }
++ if (!dhcp6->ia_addr)
++ {
++ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr));
++ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr);
++ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8);
++ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime);
++ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime);
++ }
++ }
++}
++
++static void
++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data)
++{
++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data;
++ grub_uint16_t code = grub_be_to_cpu16 (opt->code);
++ grub_uint16_t len = grub_be_to_cpu16 (opt->len);
++
++ switch (code)
++ {
++ case GRUB_NET_DHCP6_OPTION_CLIENTID:
++
++ if (dhcp6->client_duid || !len)
++ {
++ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len);
++ break;
++ }
++ dhcp6->client_duid = grub_malloc (len);
++ grub_memcpy (dhcp6->client_duid, opt->data, len);
++ dhcp6->client_duid_len = len;
++ break;
++
++ case GRUB_NET_DHCP6_OPTION_SERVERID:
++
++ if (dhcp6->server_duid || !len)
++ {
++ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len);
++ break;
++ }
++ dhcp6->server_duid = grub_malloc (len);
++ grub_memcpy (dhcp6->server_duid, opt->data, len);
++ dhcp6->server_duid_len = len;
++ break;
++
++ case GRUB_NET_DHCP6_OPTION_IA_NA:
++ {
++ const struct grub_net_dhcp6_option_iana *ia_na;
++ grub_uint16_t data_len;
++
++ if (dhcp6->iaid || len < sizeof (*ia_na))
++ {
++ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len);
++ break;
++ }
++ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data;
++ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid);
++ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1);
++ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2);
++
++ data_len = len - sizeof (*ia_na);
++ if (data_len)
++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6);
++ }
++ break;
++
++ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS:
++ {
++ const grub_uint8_t *po;
++ grub_uint16_t ln;
++ grub_net_network_level_address_t *la;
++
++ if (!len || len & 0xf)
++ {
++ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n");
++ break;
++ }
++ dhcp6->num_dns_server = ln = len >> 4;
++ dhcp6->dns_server_addrs = la = grub_calloc (ln, sizeof (*la));
++
++ for (po = opt->data; ln > 0; po += 0x10, la++, ln--)
++ {
++ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++ la->ipv6[0] = grub_get_unaligned64 (po);
++ la->ipv6[1] = grub_get_unaligned64 (po + 8);
++ la->option = DNS_OPTION_PREFER_IPV6;
++ }
++ }
++ break;
++
++ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL:
++ dissect_url ((const char *)opt->data,
++ &dhcp6->boot_file_proto,
++ &dhcp6->boot_file_server_ip,
++ &dhcp6->boot_file_path);
++ break;
++
++ default:
++ break;
++ }
++}
++
++static void
++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data)
++{
++ while (size)
++ {
++ grub_uint16_t code, len;
++
++ if (size < sizeof (*opt))
++ {
++ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size);
++ break;
++ }
++ size -= sizeof (*opt);
++ len = grub_be_to_cpu16 (opt->len);
++ code = grub_be_to_cpu16 (opt->code);
++ if (size < len)
++ {
++ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code);
++ break;
++ }
++ if (!len)
++ {
++ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code);
++ break;
++ }
++ else
++ {
++ if (hook)
++ hook (opt, hook_data);
++ size -= len;
++ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt));
++ }
++ }
++}
++
++static grub_dhcp6_options_t
++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h,
++ grub_size_t size)
++{
++ grub_dhcp6_options_t options;
++
++ if (size < sizeof (*v6h))
++ {
++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
++ return NULL;
++ }
++
++ options = grub_zalloc (sizeof(*options));
++ if (!options)
++ return NULL;
++
++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options,
++ size - sizeof (*v6h), parse_dhcp6_option, options);
++
++ return options;
++}
++
++static void
++grub_dhcp6_options_free (grub_dhcp6_options_t options)
++{
++ if (options->client_duid)
++ grub_free (options->client_duid);
++ if (options->server_duid)
++ grub_free (options->server_duid);
++ if (options->ia_addr)
++ grub_free (options->ia_addr);
++ if (options->dns_server_addrs)
++ grub_free (options->dns_server_addrs);
++ if (options->boot_file_proto)
++ grub_free (options->boot_file_proto);
++ if (options->boot_file_server_ip)
++ grub_free (options->boot_file_server_ip);
++ if (options->boot_file_path)
++ grub_free (options->boot_file_path);
++
++ grub_free (options);
++}
++
++static grub_dhcp6_session_t grub_dhcp6_sessions;
++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions)
++
++static void
++grub_net_configure_by_dhcp6_info (const char *name,
++ struct grub_net_card *card,
++ grub_dhcp6_options_t dhcp6,
++ int is_def,
++ int flags,
++ struct grub_net_network_level_interface **ret_inf)
++{
++ grub_net_network_level_netaddress_t netaddr;
++ struct grub_net_network_level_interface *inf;
++
++ if (dhcp6->ia_addr)
++ {
++ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags);
++
++ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0];
++ netaddr.ipv6.base[1] = 0;
++ netaddr.ipv6.masksize = 64;
++ grub_net_add_route (name, netaddr, inf);
++
++ if (ret_inf)
++ *ret_inf = inf;
++ }
++
++ if (dhcp6->dns_server_addrs)
++ {
++ grub_uint16_t i;
++
++ for (i = 0; i < dhcp6->num_dns_server; ++i)
++ grub_net_add_dns_server (dhcp6->dns_server_addrs + i);
++ }
++
++ if (dhcp6->boot_file_path)
++ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path,
++ grub_strlen (dhcp6->boot_file_path));
++
++ if (is_def && dhcp6->boot_file_server_ip)
++ {
++ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip);
++ grub_env_set ("net_default_interface", name);
++ grub_env_export ("net_default_interface");
++ }
++}
++
++static void
++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface,
++ grub_uint32_t iaid)
++{
++ grub_dhcp6_session_t se;
++ struct grub_datetime date;
++ grub_err_t err;
++ grub_int64_t t = 0;
++
++ se = grub_malloc (sizeof (*se));
++
++ err = grub_get_datetime (&date);
++ if (err || !grub_datetime2unixtime (&date, &t))
++ {
++ grub_errno = GRUB_ERR_NONE;
++ t = 0;
++ }
++
++ se->iface = iface;
++ se->iaid = iaid;
++ se->transaction_id = t;
++ se->start_time = grub_get_time_ms ();
++ se->duid.type = grub_cpu_to_be16_compile_time (3) ;
++ se->duid.hw_type = grub_cpu_to_be16_compile_time (1);
++ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr));
++ se->adv = NULL;
++ se->reply = NULL;
++ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se));
++}
++
++static void
++grub_dhcp6_session_remove (grub_dhcp6_session_t se)
++{
++ grub_list_remove (GRUB_AS_LIST (se));
++ if (se->adv)
++ grub_dhcp6_options_free (se->adv);
++ if (se->reply)
++ grub_dhcp6_options_free (se->reply);
++ grub_free (se);
++}
++
++static void
++grub_dhcp6_session_remove_all (void)
++{
++ grub_dhcp6_session_t se;
++
++ FOR_DHCP6_SESSIONS (se)
++ {
++ grub_dhcp6_session_remove (se);
++ se = grub_dhcp6_sessions;
++ }
++}
++
++static grub_err_t
++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se)
++{
++ char *name;
++
++ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name);
++ if (!name)
++ return grub_errno;
++
++ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0);
++ grub_free (name);
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_dhcp6_session_send_request (grub_dhcp6_session_t se)
++{
++ struct grub_net_buff *nb;
++ struct grub_net_dhcp6_option *opt;
++ struct grub_net_dhcp6_packet *v6h;
++ struct grub_net_dhcp6_option_iana *ia_na;
++ struct grub_net_dhcp6_option_iaaddr *iaaddr;
++ struct udphdr *udph;
++ grub_net_network_level_address_t multicast;
++ grub_net_link_level_address_t ll_multicast;
++ grub_uint64_t elapsed;
++ struct grub_net_network_level_interface *inf = se->iface;
++ grub_dhcp6_options_t dhcp6 = se->adv;
++ grub_err_t err = GRUB_ERR_NONE;
++
++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
++
++ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
++ if (err)
++ return err;
++
++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++
++ if (!nb)
++ return grub_errno;
++
++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++ opt = (struct grub_net_dhcp6_option *)nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
++ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len);
++ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len);
++
++ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++ opt = (struct grub_net_dhcp6_option *)nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID);
++ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len);
++ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len);
++
++ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ if (dhcp6->ia_addr)
++ {
++ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++ }
++ opt = (struct grub_net_dhcp6_option *)nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
++ if (dhcp6->ia_addr)
++ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt));
++
++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
++ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid);
++
++ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1);
++ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2);
++
++ if (dhcp6->ia_addr)
++ {
++ opt = (struct grub_net_dhcp6_option *)ia_na->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
++ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr));
++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data;
++ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]);
++ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]);
++
++ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime);
++ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime);
++ }
++
++ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ opt = (struct grub_net_dhcp6_option*) nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO);
++ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t));
++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL));
++ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS));
++
++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++ opt = (struct grub_net_dhcp6_option*) nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
++
++ /* the time is expressed in hundredths of a second */
++ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0);
++
++ if (elapsed > 0xffff)
++ elapsed = 0xffff;
++
++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed));
++
++ err = grub_netbuff_push (nb, sizeof (*v6h));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ v6h = (struct grub_net_dhcp6_packet *) nb->data;
++ v6h->message_type = GRUB_NET_DHCP6_REQUEST;
++ v6h->transaction_id = se->transaction_id;
++
++ err = grub_netbuff_push (nb, sizeof (*udph));
++ if (err)
++ {
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ udph = (struct udphdr *) nb->data;
++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
++ udph->chksum = 0;
++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
++
++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
++ &inf->address,
++ &multicast);
++ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
++ GRUB_NET_IP_UDP);
++
++ grub_netbuff_free (nb);
++
++ return err;
++}
++
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_reply (const char *name,
++ struct grub_net_card *card,
++ grub_net_interface_flags_t flags,
++ const struct grub_net_dhcp6_packet *v6h,
++ grub_size_t size,
++ int is_def,
++ char **device, char **path)
++{
++ struct grub_net_network_level_interface *inf;
++ grub_dhcp6_options_t dhcp6;
++
++ dhcp6 = grub_dhcp6_options_get (v6h, size);
++ if (!dhcp6)
++ {
++ grub_print_error ();
++ return NULL;
++ }
++
++ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf);
++
++ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip)
++ {
++ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip);
++ grub_print_error ();
++ }
++ if (path && dhcp6->boot_file_path)
++ {
++ *path = grub_strdup (dhcp6->boot_file_path);
++ grub_print_error ();
++ if (*path)
++ {
++ char *slash;
++ slash = grub_strrchr (*path, '/');
++ if (slash)
++ *slash = 0;
++ else
++ **path = 0;
++ }
++ }
++
++ grub_dhcp6_options_free (dhcp6);
++ return inf;
++}
++
+ /*
+ * This is called directly from net/ip.c:handle_dgram(), because those
+ * BOOTP/DHCP packets are a bit special due to their improper
+@@ -675,6 +1339,77 @@ grub_net_process_dhcp (struct grub_net_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)
+@@ -900,7 +1635,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
+ return err;
+ }
+
+-static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp;
++static grub_err_t
++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
++ int argc, char **args)
++{
++ struct grub_net_card *card;
++ grub_uint32_t iaid = 0;
++ int interval;
++ grub_err_t err;
++ grub_dhcp6_session_t se;
++
++ err = GRUB_ERR_NONE;
++
++ FOR_NET_CARDS (card)
++ {
++ struct grub_net_network_level_interface *iface;
++
++ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
++ continue;
++
++ iface = grub_net_ipv6_get_link_local (card, &card->default_address);
++ if (!iface)
++ {
++ grub_dhcp6_session_remove_all ();
++ return grub_errno;
++ }
++
++ grub_dhcp6_session_add (iface, iaid++);
++ }
++
++ for (interval = 200; interval < 10000; interval *= 2)
++ {
++ int done = 1;
++
++ FOR_DHCP6_SESSIONS (se)
++ {
++ struct grub_net_buff *nb;
++ struct grub_net_dhcp6_option *opt;
++ struct grub_net_dhcp6_packet *v6h;
++ struct grub_net_dhcp6_option_duid_ll *duid;
++ struct grub_net_dhcp6_option_iana *ia_na;
++ grub_net_network_level_address_t multicast;
++ grub_net_link_level_address_t ll_multicast;
++ struct udphdr *udph;
++
++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
++
++ err = grub_net_link_layer_resolve (se->iface,
++ &multicast, &ll_multicast);
++ if (err)
++ {
++ grub_dhcp6_session_remove_all ();
++ return err;
++ }
++
++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++
++ if (!nb)
++ {
++ grub_dhcp6_session_remove_all ();
++ return grub_errno;
++ }
++
++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++ if (err)
++ {
++ grub_dhcp6_session_remove_all ();
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
++ if (err)
++ {
++ grub_dhcp6_session_remove_all ();
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ opt = (struct grub_net_dhcp6_option *)nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
++ grub_set_unaligned16 (opt->data, 0);
++
++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid));
++ if (err)
++ {
++ grub_dhcp6_session_remove_all ();
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ opt = (struct grub_net_dhcp6_option *)nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
++ opt->len = grub_cpu_to_be16 (sizeof (*duid));
++
++ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data;
++ grub_memcpy (duid, &se->duid, sizeof (*duid));
++
++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na));
++ if (err)
++ {
++ grub_dhcp6_session_remove_all ();
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ opt = (struct grub_net_dhcp6_option *)nb->data;
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
++ ia_na->iaid = grub_cpu_to_be32 (se->iaid);
++ ia_na->t1 = 0;
++ ia_na->t2 = 0;
++
++ err = grub_netbuff_push (nb, sizeof (*v6h));
++ if (err)
++ {
++ grub_dhcp6_session_remove_all ();
++ grub_netbuff_free (nb);
++ return err;
++ }
++
++ v6h = (struct grub_net_dhcp6_packet *)nb->data;
++ v6h->message_type = GRUB_NET_DHCP6_SOLICIT;
++ v6h->transaction_id = se->transaction_id;
++
++ grub_netbuff_push (nb, sizeof (*udph));
++
++ udph = (struct udphdr *) nb->data;
++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
++ udph->chksum = 0;
++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
++
++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
++ &se->iface->address, &multicast);
++
++ err = grub_net_send_ip_packet (se->iface, &multicast,
++ &ll_multicast, nb, GRUB_NET_IP_UDP);
++ done = 0;
++ grub_netbuff_free (nb);
++
++ if (err)
++ {
++ grub_dhcp6_session_remove_all ();
++ return err;
++ }
++ }
++ if (!done)
++ grub_net_poll_cards (interval, 0);
++ }
++
++ FOR_DHCP6_SESSIONS (se)
++ {
++ grub_error_push ();
++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
++ N_("couldn't autoconfigure %s"),
++ se->iface->card->name);
++ }
++
++ grub_dhcp6_session_remove_all ();
++
++ return err;
++}
++
++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6;
+
+ void
+ grub_bootp_init (void)
+@@ -914,6 +1816,9 @@ grub_bootp_init (void)
+ cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
+ N_("VAR INTERFACE NUMBER DESCRIPTION"),
+ N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6,
++ N_("[CARD]"),
++ N_("perform a DHCPv6 autoconfiguration"));
+ }
+
+ void
+@@ -922,4 +1827,5 @@ grub_bootp_fini (void)
+ grub_unregister_command (cmd_getdhcp);
+ grub_unregister_command (cmd_bootp);
+ grub_unregister_command (cmd_dhcp);
++ grub_unregister_command (cmd_bootp6);
+ }
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index ea5edf8f1..01410798b 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/net.h b/include/grub/net.h
+index 69bfe0947..1cb05627e 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -448,6 +448,66 @@ struct grub_net_bootp_packet
+ grub_uint8_t vendor[0];
+ } GRUB_PACKED;
+
++struct grub_net_dhcp6_packet
++{
++ grub_uint32_t message_type:8;
++ grub_uint32_t transaction_id:24;
++ grub_uint8_t dhcp_options[0];
++} GRUB_PACKED;
++
++struct grub_net_dhcp6_option {
++ grub_uint16_t code;
++ grub_uint16_t len;
++ grub_uint8_t data[0];
++} GRUB_PACKED;
++
++struct grub_net_dhcp6_option_iana {
++ grub_uint32_t iaid;
++ grub_uint32_t t1;
++ grub_uint32_t t2;
++ grub_uint8_t data[0];
++} GRUB_PACKED;
++
++struct grub_net_dhcp6_option_iaaddr {
++ grub_uint8_t addr[16];
++ grub_uint32_t preferred_lifetime;
++ grub_uint32_t valid_lifetime;
++ grub_uint8_t data[0];
++} GRUB_PACKED;
++
++struct grub_net_dhcp6_option_duid_ll
++{
++ grub_uint16_t type;
++ grub_uint16_t hw_type;
++ grub_uint8_t hwaddr[6];
++} GRUB_PACKED;
++
++enum
++ {
++ GRUB_NET_DHCP6_SOLICIT = 1,
++ GRUB_NET_DHCP6_ADVERTISE = 2,
++ GRUB_NET_DHCP6_REQUEST = 3,
++ GRUB_NET_DHCP6_REPLY = 7
++ };
++
++enum
++ {
++ DHCP6_CLIENT_PORT = 546,
++ DHCP6_SERVER_PORT = 547
++ };
++
++enum
++ {
++ GRUB_NET_DHCP6_OPTION_CLIENTID = 1,
++ GRUB_NET_DHCP6_OPTION_SERVERID = 2,
++ GRUB_NET_DHCP6_OPTION_IA_NA = 3,
++ GRUB_NET_DHCP6_OPTION_IAADDR = 5,
++ GRUB_NET_DHCP6_OPTION_ORO = 6,
++ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8,
++ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23,
++ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59
++ };
++
+ #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63
+ #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82
+ #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53
+@@ -483,6 +543,14 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ grub_size_t size,
+ int is_def, char **device, char **path);
+
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_reply (const char *name,
++ struct grub_net_card *card,
++ grub_net_interface_flags_t flags,
++ const struct grub_net_dhcp6_packet *v6,
++ grub_size_t size,
++ int is_def, char **device, char **path);
++
+ grub_err_t
+ grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
+ int mask);
+@@ -491,6 +559,10 @@ void
+ grub_net_process_dhcp (struct grub_net_buff *nb,
+ struct grub_net_network_level_interface *iface);
+
++grub_err_t
++grub_net_process_dhcp6 (struct grub_net_buff *nb,
++ struct grub_net_card *card);
++
+ int
+ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
+ const grub_net_link_level_address_t *b);
diff --git a/debian/patches/bootp-process-dhcpack-http-boot.patch b/debian/patches/bootp-process-dhcpack-http-boot.patch
new file mode 100644
index 0000000..64b19f6
--- /dev/null
+++ b/debian/patches/bootp-process-dhcpack-http-boot.patch
@@ -0,0 +1,124 @@
+From cd78a54e5fa8d4a6f9223b7ddbb7db86ca0dd993 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 27 Oct 2016 17:42:19 -0400
+Subject: 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 <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+
+Last-Update: 2021-09-24
+
+Patch-Name: bootp-process-dhcpack-http-boot.patch
+---
+ grub-core/net/bootp.c | 60 ++++++++++++++++++++++++++++++++++++++++++-
+ include/grub/net.h | 1 +
+ 2 files changed, 60 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 00c11af39..f35d582b8 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -154,7 +154,7 @@ struct grub_dhcp_request_options
+ {
+ grub_uint8_t type;
+ grub_uint8_t len;
+- grub_uint8_t data[7];
++ grub_uint8_t data[8];
+ } GRUB_PACKED parameter_request;
+ grub_uint8_t end;
+ } GRUB_PACKED;
+@@ -542,6 +542,63 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ grub_free (val);
+ }
+
++ 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_len == sizeof ("HTTPClient") - 1 &&
++ grub_memcmp (opt, "HTTPClient", sizeof ("HTTPClient") - 1) == 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;
++ }
++ }
++
+ inter->dhcp_ack = grub_malloc (size);
+ if (inter->dhcp_ack)
+ {
+@@ -616,6 +673,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
+ GRUB_NET_BOOTP_HOSTNAME,
+ GRUB_NET_BOOTP_ROOT_PATH,
+ GRUB_NET_BOOTP_EXTENSIONS_PATH,
++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER,
+ },
+ },
+ GRUB_NET_BOOTP_END,
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 1cb05627e..cbcae79b1 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -528,6 +528,7 @@ enum
+ GRUB_NET_DHCP_MESSAGE_TYPE = 53,
+ GRUB_NET_DHCP_SERVER_IDENTIFIER = 54,
+ GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55,
++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60,
+ GRUB_NET_BOOTP_CLIENT_ID = 61,
+ GRUB_NET_DHCP_TFTP_SERVER_NAME = 66,
+ GRUB_NET_DHCP_BOOTFILE_NAME = 67,
diff --git a/debian/patches/core-in-fs.patch b/debian/patches/core-in-fs.patch
new file mode 100644
index 0000000..1f18554
--- /dev/null
+++ b/debian/patches/core-in-fs.patch
@@ -0,0 +1,45 @@
+From bd289b232f3e9ddaa378d02f0f0040c2171078a4 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:12:51 +0000
+Subject: Write marker if core.img was written to filesystem
+
+The Debian bug reporting script includes a warning in this case.
+
+Patch-Name: core-in-fs.patch
+---
+ util/setup.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/util/setup.c b/util/setup.c
+index da5f2c07f..d1902656e 100644
+--- a/util/setup.c
++++ b/util/setup.c
+@@ -58,6 +58,8 @@
+
+ #include <errno.h>
+
++#define CORE_IMG_IN_FS "setup_left_core_image_in_filesystem"
++
+ /* On SPARC this program fills in various fields inside of the 'boot' and 'core'
+ * image files.
+ *
+@@ -670,6 +672,8 @@ SETUP (const char *dir,
+ #endif
+ grub_free (sectors);
+
++ unlink (DEFAULT_DIRECTORY "/" CORE_IMG_IN_FS);
++
+ goto finish;
+ }
+
+@@ -711,6 +715,10 @@ unable_to_embed:
+ /* The core image must be put on a filesystem unfortunately. */
+ grub_util_info ("will leave the core image on the filesystem");
+
++ fp = grub_util_fd_open (DEFAULT_DIRECTORY "/" CORE_IMG_IN_FS,
++ GRUB_UTIL_FD_O_WRONLY);
++ grub_util_fd_close (fp);
++
+ grub_util_biosdisk_flush (root_dev->disk);
+
+ /* Clean out the blocklists. */
diff --git a/debian/patches/cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch b/debian/patches/cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch
new file mode 100644
index 0000000..99c2f5a
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch
@@ -0,0 +1,109 @@
+From a85714545fe57a86d14ee231a4cd312158101d43 Mon Sep 17 00:00:00 2001
+From: Alec Brown <alec.r.brown@oracle.com>
+Date: Wed, 26 Oct 2022 20:16:44 -0400
+Subject: [PATCH 01/14] video/readers: Add artificial limit to image dimensions
+
+In grub-core/video/readers/jpeg.c, the height and width of a JPEG image don't
+have an upper limit for how big the JPEG image can be. In Coverity, this is
+getting flagged as an untrusted loop bound. This issue can also seen in PNG and
+TGA format images as well but Coverity isn't flagging it. To prevent this, the
+constant IMAGE_HW_MAX_PX is being added to include/grub/bitmap.h, which has
+a value of 16384, to act as an artificial limit and restrict the height and
+width of images. This value was picked as it is double the current max
+resolution size, which is 8K.
+
+Fixes: CID 292450
+
+Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
+Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ docs/grub.texi | 3 ++-
+ grub-core/video/readers/jpeg.c | 6 +++++-
+ grub-core/video/readers/png.c | 6 +++++-
+ grub-core/video/readers/tga.c | 7 +++++++
+ include/grub/bitmap.h | 2 ++
+ 5 files changed, 21 insertions(+), 3 deletions(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 0dbbdc374..2d6cd8358 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -1515,7 +1515,8 @@ resolution. @xref{gfxmode}.
+ Set a background image for use with the @samp{gfxterm} graphical terminal.
+ The value of this option must be a file readable by GRUB at boot time, and
+ it must end with @file{.png}, @file{.tga}, @file{.jpg}, or @file{.jpeg}.
+-The image will be scaled if necessary to fit the screen.
++The image will be scaled if necessary to fit the screen. Image height and
++width will be restricted by an artificial limit of 16384.
+
+ @item GRUB_THEME
+ Set a theme for use with the @samp{gfxterm} graphical terminal.
+diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
+index 09596fbf5..ae634fd41 100644
+--- a/grub-core/video/readers/jpeg.c
++++ b/grub-core/video/readers/jpeg.c
+@@ -346,7 +346,11 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
+ data->image_height = grub_jpeg_get_word (data);
+ data->image_width = grub_jpeg_get_word (data);
+
+- if ((!data->image_height) || (!data->image_width))
++ grub_dprintf ("jpeg", "image height: %d\n", data->image_height);
++ grub_dprintf ("jpeg", "image width: %d\n", data->image_width);
++
++ if ((!data->image_height) || (!data->image_width) ||
++ (data->image_height > IMAGE_HW_MAX_PX) || (data->image_width > IMAGE_HW_MAX_PX))
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size");
+
+ cc = grub_jpeg_get_byte (data);
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index 7f2ba7849..3163e97bf 100644
+--- a/grub-core/video/readers/png.c
++++ b/grub-core/video/readers/png.c
+@@ -264,7 +264,11 @@ grub_png_decode_image_header (struct grub_png_data *data)
+ data->image_width = grub_png_get_dword (data);
+ data->image_height = grub_png_get_dword (data);
+
+- if ((!data->image_height) || (!data->image_width))
++ grub_dprintf ("png", "image height: %d\n", data->image_height);
++ grub_dprintf ("png", "image width: %d\n", data->image_width);
++
++ if ((!data->image_height) || (!data->image_width) ||
++ (data->image_height > IMAGE_HW_MAX_PX) || (data->image_width > IMAGE_HW_MAX_PX))
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
+
+ color_bits = grub_png_get_byte (data);
+diff --git a/grub-core/video/readers/tga.c b/grub-core/video/readers/tga.c
+index a9ec3a1b6..9c35bf29d 100644
+--- a/grub-core/video/readers/tga.c
++++ b/grub-core/video/readers/tga.c
+@@ -340,6 +340,13 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap,
+ data.image_width = grub_le_to_cpu16 (data.hdr.image_width);
+ data.image_height = grub_le_to_cpu16 (data.hdr.image_height);
+
++ grub_dprintf ("tga", "image height: %d\n", data.image_height);
++ grub_dprintf ("tga", "image width: %d\n", data.image_width);
++
++ /* Check image height and width are within restrictions. */
++ if ((data.image_height > IMAGE_HW_MAX_PX) || (data.image_width > IMAGE_HW_MAX_PX))
++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "tga: invalid image size");
++
+ /* Check that bitmap encoding is supported. */
+ switch (data.hdr.image_type)
+ {
+diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h
+index 5728f8ca3..149d37bfe 100644
+--- a/include/grub/bitmap.h
++++ b/include/grub/bitmap.h
+@@ -24,6 +24,8 @@
+ #include <grub/types.h>
+ #include <grub/video.h>
+
++#define IMAGE_HW_MAX_PX 16384
++
+ struct grub_video_bitmap
+ {
+ /* Bitmap format description. */
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch b/debian/patches/cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
new file mode 100644
index 0000000..7330e5a
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
@@ -0,0 +1,33 @@
+From 5760fcfd466cc757540ea0d591bad6a08caeaa16 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Wed, 3 Aug 2022 19:45:33 +0800
+Subject: [PATCH 02/14] font: Reject glyphs exceeds font->max_glyph_width or
+ font->max_glyph_height
+
+Check glyph's width and height against limits specified in font's
+metadata. Reject the glyph (and font) if such limits are exceeded.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 42189c325..756ca0abf 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -760,7 +760,9 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+ || read_be_uint16 (font->file, &height) != 0
+ || read_be_int16 (font->file, &xoff) != 0
+ || read_be_int16 (font->file, &yoff) != 0
+- || read_be_int16 (font->file, &dwidth) != 0)
++ || read_be_int16 (font->file, &dwidth) != 0
++ || width > font->max_char_width
++ || height > font->max_char_height)
+ {
+ remove_font (font);
+ return 0;
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch b/debian/patches/cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
new file mode 100644
index 0000000..46ccb00
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
@@ -0,0 +1,110 @@
+From 941d10ad6f1dcbd12fb613002249e29ba035f985 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 00:51:20 +0800
+Subject: [PATCH 03/14] font: Fix size overflow in
+ grub_font_get_glyph_internal()
+
+The length of memory allocation and file read may overflow. This patch
+fixes the problem by using safemath macros.
+
+There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe
+if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz().
+It is safe replacement for such code. It has safemath-like prototype.
+
+This patch also introduces grub_cast(value, pointer), it casts value to
+typeof(*pointer) then store the value to *pointer. It returns true when
+overflow occurs or false if there is no overflow. The semantics of arguments
+and return value are designed to be consistent with other safemath macros.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 17 +++++++++++++----
+ include/grub/bitmap.h | 18 ++++++++++++++++++
+ include/grub/safemath.h | 2 ++
+ 3 files changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 2f09a4a55..6a3fbebbd 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+ grub_int16_t xoff;
+ grub_int16_t yoff;
+ grub_int16_t dwidth;
+- int len;
++ grub_ssize_t len;
++ grub_size_t sz;
+
+ if (index_entry->glyph)
+ /* Return cached glyph. */
+@@ -768,9 +769,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+ return 0;
+ }
+
+- len = (width * height + 7) / 8;
+- glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
+- if (!glyph)
++ /* Calculate real struct size of current glyph. */
++ if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) ||
++ grub_add (sizeof (struct grub_font_glyph), len, &sz))
++ {
++ remove_font (font);
++ return 0;
++ }
++
++ /* Allocate and initialize the glyph struct. */
++ glyph = grub_malloc (sz);
++ if (glyph == NULL)
+ {
+ remove_font (font);
+ return 0;
+diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h
+index 149d37bfe..431048936 100644
+--- a/include/grub/bitmap.h
++++ b/include/grub/bitmap.h
+@@ -23,6 +23,7 @@
+ #include <grub/symbol.h>
+ #include <grub/types.h>
+ #include <grub/video.h>
++#include <grub/safemath.h>
+
+ #define IMAGE_HW_MAX_PX 16384
+
+@@ -81,6 +82,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap)
+ return bitmap->mode_info.height;
+ }
+
++/*
++ * Calculate and store the size of data buffer of 1bit bitmap in result.
++ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs.
++ * Return true when overflow occurs or false if there is no overflow.
++ * This function is intentionally implemented as a macro instead of
++ * an inline function. Although a bit awkward, it preserves data types for
++ * safemath macros and reduces macro side effects as much as possible.
++ *
++ * XXX: Will report false overflow if width * height > UINT64_MAX.
++ */
++#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \
++({ \
++ grub_uint64_t _bitmap_pixels; \
++ grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \
++ grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \
++})
++
+ void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap,
+ struct grub_video_mode_info *mode_info);
+
+diff --git a/include/grub/safemath.h b/include/grub/safemath.h
+index c17b89bba..bb0f826de 100644
+--- a/include/grub/safemath.h
++++ b/include/grub/safemath.h
+@@ -30,6 +30,8 @@
+ #define grub_sub(a, b, res) __builtin_sub_overflow(a, b, res)
+ #define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res)
+
++#define grub_cast(a, res) grub_add ((a), 0, (res))
++
+ #else
+ #error gcc 5.1 or newer or clang 3.8 or newer is required
+ #endif
diff --git a/debian/patches/cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch b/debian/patches/cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch
new file mode 100644
index 0000000..9d3c9b2
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch
@@ -0,0 +1,81 @@
+From b1805f251b31a9d3cfae5c3572ddfa630145dbbf Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 01:58:27 +0800
+Subject: [PATCH 04/14] font: Fix several integer overflows in
+ grub_font_construct_glyph()
+
+This patch fixes several integer overflows in grub_font_construct_glyph().
+Glyphs of invalid size, zero or leading to an overflow, are rejected.
+The inconsistency between "glyph" and "max_glyph_size" when grub_malloc()
+returns NULL is fixed too.
+
+Fixes: CVE-2022-2601
+
+Reported-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 29 +++++++++++++++++------------
+ 1 file changed, 17 insertions(+), 12 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index e781521a7..e6548892f 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1517,6 +1517,7 @@ grub_font_construct_glyph (grub_font_t hinted_font,
+ struct grub_video_signed_rect bounds;
+ static struct grub_font_glyph *glyph = 0;
+ static grub_size_t max_glyph_size = 0;
++ grub_size_t cur_glyph_size;
+
+ ensure_comb_space (glyph_id);
+
+@@ -1533,29 +1534,33 @@ grub_font_construct_glyph (grub_font_t hinted_font,
+ if (!glyph_id->ncomb && !glyph_id->attributes)
+ return main_glyph;
+
+- if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT)
++ if (grub_video_bitmap_calc_1bpp_bufsz (bounds.width, bounds.height, &cur_glyph_size) ||
++ grub_add (sizeof (*glyph), cur_glyph_size, &cur_glyph_size))
++ return main_glyph;
++
++ if (max_glyph_size < cur_glyph_size)
+ {
+ grub_free (glyph);
+- max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2;
+- if (max_glyph_size < 8)
+- max_glyph_size = 8;
+- glyph = grub_malloc (max_glyph_size);
++ if (grub_mul (cur_glyph_size, 2, &max_glyph_size))
++ max_glyph_size = 0;
++ glyph = max_glyph_size > 0 ? grub_malloc (max_glyph_size) : NULL;
+ }
+ if (!glyph)
+ {
++ max_glyph_size = 0;
+ grub_errno = GRUB_ERR_NONE;
+ return main_glyph;
+ }
+
+- grub_memset (glyph, 0, sizeof (*glyph)
+- + (bounds.width * bounds.height
+- + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT);
++ grub_memset (glyph, 0, cur_glyph_size);
+
+ glyph->font = main_glyph->font;
+- glyph->width = bounds.width;
+- glyph->height = bounds.height;
+- glyph->offset_x = bounds.x;
+- glyph->offset_y = bounds.y;
++ if (bounds.width == 0 || bounds.height == 0 ||
++ grub_cast (bounds.width, &glyph->width) ||
++ grub_cast (bounds.height, &glyph->height) ||
++ grub_cast (bounds.x, &glyph->offset_x) ||
++ grub_cast (bounds.y, &glyph->offset_y))
++ return main_glyph;
+
+ if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR)
+ grub_font_blit_glyph_mirror (glyph, main_glyph,
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch b/debian/patches/cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch
new file mode 100644
index 0000000..7c957a6
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch
@@ -0,0 +1,42 @@
+From 25ad31c19c331aaa2dbd9bd2b2e2655de5766a9d Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 02:13:29 +0800
+Subject: [PATCH 05/14] font: Remove grub_font_dup_glyph()
+
+Remove grub_font_dup_glyph() since nobody is using it since 2013, and
+I'm too lazy to fix the integer overflow problem in it.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 14 --------------
+ 1 file changed, 14 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index e6548892f..a8576ffec 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1055,20 +1055,6 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code)
+ return best_glyph;
+ }
+
+-#if 0
+-static struct grub_font_glyph *
+-grub_font_dup_glyph (struct grub_font_glyph *glyph)
+-{
+- static struct grub_font_glyph *ret;
+- ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8);
+- if (!ret)
+- return NULL;
+- grub_memcpy (ret, glyph, sizeof (*ret)
+- + (glyph->width * glyph->height + 7) / 8);
+- return ret;
+-}
+-#endif
+-
+ /* FIXME: suboptimal. */
+ static void
+ grub_font_blit_glyph (struct grub_font_glyph *target,
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch b/debian/patches/cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch
new file mode 100644
index 0000000..f35c646
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch
@@ -0,0 +1,48 @@
+From b2740b7e4a03bb8331d48b54b119afea76bb9d5f Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 02:27:05 +0800
+Subject: [PATCH 06/14] font: Fix integer overflow in ensure_comb_space()
+
+In fact it can't overflow at all because glyph_id->ncomb is only 8-bit
+wide. But let's keep safe if somebody changes the width of glyph_id->ncomb
+in the future. This patch also fixes the inconsistency between
+render_max_comb_glyphs and render_combining_glyphs when grub_malloc()
+returns NULL.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index a8576ffec..9e3e0a94e 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1468,14 +1468,18 @@ ensure_comb_space (const struct grub_unicode_glyph *glyph_id)
+ if (glyph_id->ncomb <= render_max_comb_glyphs)
+ return;
+
+- render_max_comb_glyphs = 2 * glyph_id->ncomb;
+- if (render_max_comb_glyphs < 8)
++ if (grub_mul (glyph_id->ncomb, 2, &render_max_comb_glyphs))
++ render_max_comb_glyphs = 0;
++ if (render_max_comb_glyphs > 0 && render_max_comb_glyphs < 8)
+ render_max_comb_glyphs = 8;
+ grub_free (render_combining_glyphs);
+- render_combining_glyphs = grub_malloc (render_max_comb_glyphs
+- * sizeof (render_combining_glyphs[0]));
++ render_combining_glyphs = (render_max_comb_glyphs > 0) ?
++ grub_calloc (render_max_comb_glyphs, sizeof (render_combining_glyphs[0])) : NULL;
+ if (!render_combining_glyphs)
+- grub_errno = 0;
++ {
++ render_max_comb_glyphs = 0;
++ grub_errno = GRUB_ERR_NONE;
++ }
+ }
+
+ int
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch b/debian/patches/cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch
new file mode 100644
index 0000000..7d426f0
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch
@@ -0,0 +1,65 @@
+From afda8b60ba0712abe01ae1e64c5f7a067a0e6492 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Mon, 15 Aug 2022 02:04:58 +0800
+Subject: [PATCH 07/14] font: Fix integer overflow in BMP index
+
+The BMP index (font->bmp_idx) is designed as a reverse lookup table of
+char entries (font->char_index), in order to speed up lookups for BMP
+chars (i.e. code < 0x10000). The values in BMP index are the subscripts
+of the corresponding char entries, stored in grub_uint16_t, while 0xffff
+means not found.
+
+This patch fixes the problem of large subscript truncated to grub_uint16_t,
+leading BMP index to return wrong char entry or report false miss. The
+code now checks for bounds and uses BMP index as a hint, and fallbacks
+to binary-search if necessary.
+
+On the occasion add a comment about BMP index is initialized to 0xffff.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 9e3e0a94e..e4cb0d867 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -300,6 +300,8 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
+ font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t));
+ if (!font->bmp_idx)
+ return 1;
++
++ /* Init the BMP index array to 0xffff. */
+ grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t));
+
+
+@@ -328,7 +330,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
+ return 1;
+ }
+
+- if (entry->code < 0x10000)
++ if (entry->code < 0x10000 && i < 0xffff)
+ font->bmp_idx[entry->code] = i;
+
+ last_code = entry->code;
+@@ -696,9 +698,12 @@ find_glyph (const grub_font_t font, grub_uint32_t code)
+ /* Use BMP index if possible. */
+ if (code < 0x10000 && font->bmp_idx)
+ {
+- if (font->bmp_idx[code] == 0xffff)
+- return 0;
+- return &table[font->bmp_idx[code]];
++ if (font->bmp_idx[code] < 0xffff)
++ return &table[font->bmp_idx[code]];
++ /*
++ * When we are here then lookup in BMP index result in miss,
++ * fallthough to binary-search.
++ */
+ }
+
+ /* Do a binary search in `char_index', which is ordered by code point. */
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch b/debian/patches/cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch
new file mode 100644
index 0000000..0db8d15
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch
@@ -0,0 +1,86 @@
+From c140a086838e7c9af87842036f891b8393a8c4bc Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sun, 14 Aug 2022 18:09:38 +0800
+Subject: [PATCH 08/14] font: Fix integer underflow in binary search of char
+ index
+
+If search target is less than all entries in font->index then "hi"
+variable is set to -1, which translates to SIZE_MAX and leads to errors.
+
+This patch fixes the problem by replacing the entire binary search code
+with the libstdc++'s std::lower_bound() implementation.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 40 ++++++++++++++++++++++------------------
+ 1 file changed, 22 insertions(+), 18 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index e4cb0d867..abd412a5e 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -688,12 +688,12 @@ read_be_int16 (grub_file_t file, grub_int16_t * value)
+ static inline struct char_index_entry *
+ find_glyph (const grub_font_t font, grub_uint32_t code)
+ {
+- struct char_index_entry *table;
+- grub_size_t lo;
+- grub_size_t hi;
+- grub_size_t mid;
++ struct char_index_entry *table, *first, *end;
++ grub_size_t len;
+
+ table = font->char_index;
++ if (table == NULL)
++ return NULL;
+
+ /* Use BMP index if possible. */
+ if (code < 0x10000 && font->bmp_idx)
+@@ -706,25 +706,29 @@ find_glyph (const grub_font_t font, grub_uint32_t code)
+ */
+ }
+
+- /* Do a binary search in `char_index', which is ordered by code point. */
+- lo = 0;
+- hi = font->num_chars - 1;
+-
+- if (!table)
+- return 0;
++ /*
++ * Do a binary search in char_index which is ordered by code point.
++ * The code below is the same as libstdc++'s std::lower_bound().
++ */
++ first = table;
++ len = font->num_chars;
++ end = first + len;
+
+- while (lo <= hi)
++ while (len > 0)
+ {
+- mid = lo + (hi - lo) / 2;
+- if (code < table[mid].code)
+- hi = mid - 1;
+- else if (code > table[mid].code)
+- lo = mid + 1;
++ grub_size_t half = len >> 1;
++ struct char_index_entry *middle = first + half;
++
++ if (middle->code < code)
++ {
++ first = middle + 1;
++ len = len - half - 1;
++ }
+ else
+- return &table[mid];
++ len = half;
+ }
+
+- return 0;
++ return (first < end && first->code == code) ? first : NULL;
+ }
+
+ /* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch b/debian/patches/cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch
new file mode 100644
index 0000000..705835a
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch
@@ -0,0 +1,54 @@
+From 630deb8c0d8b02b670ced4b7030414bcf17aa080 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sun, 14 Aug 2022 15:51:54 +0800
+Subject: [PATCH 09/14] kern/efi/sb: Enforce verification of font files
+
+As a mitigation and hardening measure enforce verification of font
+files. Then only trusted font files can be load. This will reduce the
+attack surface at cost of losing the ability of end-users to customize
+fonts if e.g. UEFI Secure Boot is enabled. Vendors can always customize
+fonts because they have ability to pack fonts into their GRUB bundles.
+
+This goal is achieved by:
+
+ * Removing GRUB_FILE_TYPE_FONT from shim lock verifier's
+ skip-verification list.
+
+ * Adding GRUB_FILE_TYPE_FONT to lockdown verifier's defer-auth list,
+ so font files must be verified by a verifier before they can be loaded.
+
+Suggested-by: Daniel Kiper <daniel.kiper@oracle.com>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/kern/efi/sb.c | 1 -
+ grub-core/kern/lockdown.c | 1 +
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
+index 89c4bb3fd..db42c2539 100644
+--- a/grub-core/kern/efi/sb.c
++++ b/grub-core/kern/efi/sb.c
+@@ -145,7 +145,6 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
+ 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:
+diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c
+index 0bc70fd42..af6d493cd 100644
+--- a/grub-core/kern/lockdown.c
++++ b/grub-core/kern/lockdown.c
+@@ -51,6 +51,7 @@ lockdown_verifier_init (grub_file_t io __attribute__ ((unused)),
+ case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE:
+ case GRUB_FILE_TYPE_ACPI_TABLE:
+ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
++ case GRUB_FILE_TYPE_FONT:
+ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
+
+ /* Fall through. */
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch b/debian/patches/cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch
new file mode 100644
index 0000000..8dcac96
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch
@@ -0,0 +1,85 @@
+From 50a11a81bc842c58962244a2dc86bbd31a426e12 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Tue, 6 Sep 2022 03:03:21 +0800
+Subject: [PATCH 10/14] fbutil: Fix integer overflow
+
+Expressions like u64 = u32 * u32 are unsafe because their products are
+truncated to u32 even if left hand side is u64. This patch fixes all
+problems like that one in fbutil.
+
+To get right result not only left hand side have to be u64 but it's also
+necessary to cast at least one of the operands of all leaf operators of
+right hand side to u64, e.g. u64 = u32 * u32 + u32 * u32 should be
+u64 = (u64)u32 * u32 + (u64)u32 * u32.
+
+For 1-bit bitmaps grub_uint64_t have to be used. It's safe because any
+combination of values in (grub_uint64_t)u32 * u32 + u32 expression will
+not overflow grub_uint64_t.
+
+Other expressions like ptr + u32 * u32 + u32 * u32 are also vulnerable.
+They should be ptr + (grub_addr_t)u32 * u32 + (grub_addr_t)u32 * u32.
+
+This patch also adds a comment to grub_video_fb_get_video_ptr() which
+says it's arguments must be valid and no sanity check is performed
+(like its siblings in grub-core/video/fb/fbutil.c).
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/video/fb/fbutil.c | 4 ++--
+ include/grub/fbutil.h | 13 +++++++++----
+ 2 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c
+index b98bb51fe..25ef39f47 100644
+--- a/grub-core/video/fb/fbutil.c
++++ b/grub-core/video/fb/fbutil.c
+@@ -67,7 +67,7 @@ get_pixel (struct grub_video_fbblit_info *source,
+ case 1:
+ if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+ {
+- int bit_index = y * source->mode_info->width + x;
++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
+ grub_uint8_t *ptr = source->data + bit_index / 8;
+ int bit_pos = 7 - bit_index % 8;
+ color = (*ptr >> bit_pos) & 0x01;
+@@ -138,7 +138,7 @@ set_pixel (struct grub_video_fbblit_info *source,
+ case 1:
+ if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+ {
+- int bit_index = y * source->mode_info->width + x;
++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
+ grub_uint8_t *ptr = source->data + bit_index / 8;
+ int bit_pos = 7 - bit_index % 8;
+ *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos);
+diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h
+index 4205eb917..78a1ab3b4 100644
+--- a/include/grub/fbutil.h
++++ b/include/grub/fbutil.h
+@@ -31,14 +31,19 @@ struct grub_video_fbblit_info
+ grub_uint8_t *data;
+ };
+
+-/* Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
+- and it doesn't make sense, in general, to ask for a pointer
+- to a particular pixel's data. */
++/*
++ * Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
++ * and it doesn't make sense, in general, to ask for a pointer
++ * to a particular pixel's data.
++ *
++ * This function assumes that bounds checking has been done in previous phase
++ * and they are opted out in here.
++ */
+ static inline void *
+ grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source,
+ unsigned int x, unsigned int y)
+ {
+- return source->data + y * source->mode_info->pitch + x * source->mode_info->bytes_per_pixel;
++ return source->data + (grub_addr_t) y * source->mode_info->pitch + (grub_addr_t) x * source->mode_info->bytes_per_pixel;
+ }
+
+ /* Advance pointer by VAL bytes. If there is no unaligned access available,
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch b/debian/patches/cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch
new file mode 100644
index 0000000..3a2b02c
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch
@@ -0,0 +1,91 @@
+From 6d2668dea3774ed74c4cd1eadd146f1b846bc3d4 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Mon, 24 Oct 2022 08:05:35 +0800
+Subject: [PATCH 11/14] font: Fix an integer underflow in blit_comb()
+
+The expression (ctx.bounds.height - combining_glyphs[i]->height) / 2 may
+evaluate to a very big invalid value even if both ctx.bounds.height and
+combining_glyphs[i]->height are small integers. For example, if
+ctx.bounds.height is 10 and combining_glyphs[i]->height is 12, this
+expression evaluates to 2147483647 (expected -1). This is because
+coordinates are allowed to be negative but ctx.bounds.height is an
+unsigned int. So, the subtraction operates on unsigned ints and
+underflows to a very big value. The division makes things even worse.
+The quotient is still an invalid value even if converted back to int.
+
+This patch fixes the problem by casting ctx.bounds.height to int. As
+a result the subtraction will operate on int and grub_uint16_t which
+will be promoted to an int. So, the underflow will no longer happen. Other
+uses of ctx.bounds.height (and ctx.bounds.width) are also casted to int,
+to ensure coordinates are always calculated on signed integers.
+
+Fixes: CVE-2022-3775
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index abd412a5e..3d3d803e8 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1203,12 +1203,12 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+ ctx.bounds.height = main_glyph->height;
+
+ above_rightx = main_glyph->offset_x + main_glyph->width;
+- above_righty = ctx.bounds.y + ctx.bounds.height;
++ above_righty = ctx.bounds.y + (int) ctx.bounds.height;
+
+ above_leftx = main_glyph->offset_x;
+- above_lefty = ctx.bounds.y + ctx.bounds.height;
++ above_lefty = ctx.bounds.y + (int) ctx.bounds.height;
+
+- below_rightx = ctx.bounds.x + ctx.bounds.width;
++ below_rightx = ctx.bounds.x + (int) ctx.bounds.width;
+ below_righty = ctx.bounds.y;
+
+ comb = grub_unicode_get_comb (glyph_id);
+@@ -1221,7 +1221,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+
+ if (!combining_glyphs[i])
+ continue;
+- targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x;
++ targetx = ((int) ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x;
+ /* CGJ is to avoid diacritics reordering. */
+ if (comb[i].code
+ == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER)
+@@ -1231,8 +1231,8 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+ case GRUB_UNICODE_COMB_OVERLAY:
+ do_blit (combining_glyphs[i],
+ targetx,
+- (ctx.bounds.height - combining_glyphs[i]->height) / 2
+- - (ctx.bounds.height + ctx.bounds.y), &ctx);
++ ((int) ctx.bounds.height - combining_glyphs[i]->height) / 2
++ - ((int) ctx.bounds.height + ctx.bounds.y), &ctx);
+ if (min_devwidth < combining_glyphs[i]->width)
+ min_devwidth = combining_glyphs[i]->width;
+ break;
+@@ -1305,7 +1305,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+ /* Fallthrough. */
+ case GRUB_UNICODE_STACK_ATTACHED_ABOVE:
+ do_blit (combining_glyphs[i], targetx,
+- -(ctx.bounds.height + ctx.bounds.y + space
++ -((int) ctx.bounds.height + ctx.bounds.y + space
+ + combining_glyphs[i]->height), &ctx);
+ if (min_devwidth < combining_glyphs[i]->width)
+ min_devwidth = combining_glyphs[i]->width;
+@@ -1313,7 +1313,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+
+ case GRUB_UNICODE_COMB_HEBREW_DAGESH:
+ do_blit (combining_glyphs[i], targetx,
+- -(ctx.bounds.height / 2 + ctx.bounds.y
++ -((int) ctx.bounds.height / 2 + ctx.bounds.y
+ + combining_glyphs[i]->height / 2), &ctx);
+ if (min_devwidth < combining_glyphs[i]->width)
+ min_devwidth = combining_glyphs[i]->width;
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch b/debian/patches/cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
new file mode 100644
index 0000000..6296bf5
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
@@ -0,0 +1,75 @@
+From fcd7aa0c278f7cf3fb9f93f1a3966e1792339eb6 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Mon, 24 Oct 2022 07:15:41 +0800
+Subject: [PATCH 12/14] font: Harden grub_font_blit_glyph() and
+ grub_font_blit_glyph_mirror()
+
+As a mitigation and hardening measure add sanity checks to
+grub_font_blit_glyph() and grub_font_blit_glyph_mirror(). This patch
+makes these two functions do nothing if target blitting area isn't fully
+contained in target bitmap. Therefore, if complex calculations in caller
+overflows and malicious coordinates are given, we are still safe because
+any coordinates which result in out-of-bound-write are rejected. However,
+this patch only checks for invalid coordinates, and doesn't provide any
+protection against invalid source glyph or destination glyph, e.g.
+mismatch between glyph size and buffer size.
+
+This hardening measure is designed to mitigate possible overflows in
+blit_comb(). If overflow occurs, it may return invalid bounding box
+during dry run and call grub_font_blit_glyph() with malicious
+coordinates during actual blitting. However, we are still safe because
+the scratch glyph itself is valid, although its size makes no sense, and
+any invalid coordinates are rejected.
+
+It would be better to call grub_fatal() if illegal parameter is detected.
+However, doing this may end up in a dangerous recursion because grub_fatal()
+would print messages to the screen and we are in the progress of drawing
+characters on the screen.
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 3d3d803e8..cf15dc2f9 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1069,8 +1069,15 @@ static void
+ grub_font_blit_glyph (struct grub_font_glyph *target,
+ struct grub_font_glyph *src, unsigned dx, unsigned dy)
+ {
++ grub_uint16_t max_x, max_y;
+ unsigned src_bit, tgt_bit, src_byte, tgt_byte;
+ unsigned i, j;
++
++ /* Harden against out-of-bound writes. */
++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) ||
++ (grub_add (dy, src->height, &max_y) || max_y > target->height))
++ return;
++
+ for (i = 0; i < src->height; i++)
+ {
+ src_bit = (src->width * i) % 8;
+@@ -1102,9 +1109,16 @@ grub_font_blit_glyph_mirror (struct grub_font_glyph *target,
+ struct grub_font_glyph *src,
+ unsigned dx, unsigned dy)
+ {
++ grub_uint16_t max_x, max_y;
+ unsigned tgt_bit, src_byte, tgt_byte;
+ signed src_bit;
+ unsigned i, j;
++
++ /* Harden against out-of-bound writes. */
++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) ||
++ (grub_add (dy, src->height, &max_y) || max_y > target->height))
++ return;
++
+ for (i = 0; i < src->height; i++)
+ {
+ src_bit = (src->width * i + src->width - 1) % 8;
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch b/debian/patches/cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
new file mode 100644
index 0000000..2db665f
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
@@ -0,0 +1,36 @@
+From dd539d695482069d28b40f2d3821f710cdcf6ee6 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 28 Oct 2022 17:29:16 +0800
+Subject: [PATCH 13/14] font: Assign null_font to glyphs in ascii_font_glyph[]
+
+The calculations in blit_comb() need information from glyph's font, e.g.
+grub_font_get_xheight(main_glyph->font). However, main_glyph->font is
+NULL if main_glyph comes from ascii_font_glyph[]. Therefore
+grub_font_get_*() crashes because of NULL pointer.
+
+There is already a solution, the null_font. So, assign it to those glyphs
+in ascii_font_glyph[].
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/font/font.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index cf15dc2f9..3821937e6 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -137,7 +137,7 @@ ascii_glyph_lookup (grub_uint32_t code)
+ ascii_font_glyph[current]->offset_x = 0;
+ ascii_font_glyph[current]->offset_y = -2;
+ ascii_font_glyph[current]->device_width = 8;
+- ascii_font_glyph[current]->font = NULL;
++ ascii_font_glyph[current]->font = &null_font;
+
+ grub_memcpy (ascii_font_glyph[current]->bitmap,
+ &ascii_bitmaps[current * ASCII_BITMAP_SIZE],
+--
+2.30.2
+
diff --git a/debian/patches/cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch b/debian/patches/cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
new file mode 100644
index 0000000..a94450a
--- /dev/null
+++ b/debian/patches/cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
@@ -0,0 +1,55 @@
+From da90d62316a3b105d2fbd7334d6521936bd6dcf6 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 28 Oct 2022 21:31:39 +0800
+Subject: [PATCH 14/14] normal/charset: Fix an integer overflow in
+ grub_unicode_aglomerate_comb()
+
+The out->ncomb is a bit-field of 8 bits. So, the max possible value is 255.
+However, code in grub_unicode_aglomerate_comb() doesn't check for an
+overflow when incrementing out->ncomb. If out->ncomb is already 255,
+after incrementing it will get 0 instead of 256, and cause illegal
+memory access in subsequent processing.
+
+This patch introduces GRUB_UNICODE_NCOMB_MAX to represent the max
+acceptable value of ncomb. The code now checks for this limit and
+ignores additional combining characters when limit is reached.
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/normal/charset.c | 3 +++
+ include/grub/unicode.h | 2 ++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
+index 000e687bd..4f6647116 100644
+--- a/grub-core/normal/charset.c
++++ b/grub-core/normal/charset.c
+@@ -472,6 +472,9 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
+ if (!haveout)
+ continue;
+
++ if (out->ncomb == GRUB_UNICODE_NCOMB_MAX)
++ continue;
++
+ if (comb_type == GRUB_UNICODE_COMB_MC
+ || comb_type == GRUB_UNICODE_COMB_ME
+ || comb_type == GRUB_UNICODE_COMB_MN)
+diff --git a/include/grub/unicode.h b/include/grub/unicode.h
+index 71a4d1a54..9360b0b97 100644
+--- a/include/grub/unicode.h
++++ b/include/grub/unicode.h
+@@ -147,7 +147,9 @@ struct grub_unicode_glyph
+ grub_uint8_t bidi_level:6; /* minimum: 6 */
+ enum grub_bidi_type bidi_type:5; /* minimum: :5 */
+
++#define GRUB_UNICODE_NCOMB_MAX ((1 << 8) - 1)
+ unsigned ncomb:8;
++
+ /* Hint by unicode subsystem how wide this character usually is.
+ Real width is determined by font. Set only in UTF-8 stream. */
+ int estimated_width:8;
+--
+2.30.2
+
diff --git a/debian/patches/debug_verifiers.patch b/debian/patches/debug_verifiers.patch
new file mode 100644
index 0000000..2d2daca
--- /dev/null
+++ b/debian/patches/debug_verifiers.patch
@@ -0,0 +1,28 @@
+From 55796e3e90a55d54aff94f2dfeb6e02055e08e30 Mon Sep 17 00:00:00 2001
+From: Steve McIntyre <93sam@debian.org>
+Date: Sat, 17 Apr 2021 22:05:47 +0100
+Subject: Add debug to display what's going on with verifiers
+
+Patch-Name: debug_verifiers.patch
+---
+ grub-core/kern/verifiers.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grub-core/kern/verifiers.c b/grub-core/kern/verifiers.c
+index 1245d0d9e..5242a723f 100644
+--- a/grub-core/kern/verifiers.c
++++ b/grub-core/kern/verifiers.c
+@@ -100,11 +100,13 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type)
+ FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
+ {
+ enum grub_verify_flags flags = 0;
++ grub_dprintf ("verify", "trying verifier %s\n", ver->name);
+ err = ver->init (io, type, &context, &flags);
+ if (err)
+ goto fail_noclose;
+ if (flags & GRUB_VERIFY_FLAGS_DEFER_AUTH)
+ {
++ grub_dprintf ("verify", "verifier %s said GRUB_VERIFY_FLAGS_DEFER_AUTH\n", ver->name);
+ defer = 1;
+ continue;
+ }
diff --git a/debian/patches/default-grub-d.patch b/debian/patches/default-grub-d.patch
new file mode 100644
index 0000000..f7ca596
--- /dev/null
+++ b/debian/patches/default-grub-d.patch
@@ -0,0 +1,209 @@
+From 4dff7f7df2853c519c4b0f59ff224c0b31f8223e Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:10 +0000
+Subject: Read /etc/default/grub.d/*.cfg after /etc/default/grub
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/901600
+Forwarded: no
+Last-Update: 2021-09-24
+
+Patch-Name: default-grub-d.patch
+---
+ grub-core/osdep/unix/config.c | 128 ++++++++++++++++++++++++++++------
+ util/grub-mkconfig.in | 5 ++
+ 2 files changed, 112 insertions(+), 21 deletions(-)
+
+diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
+index 7d6325138..545d64b4c 100644
+--- a/grub-core/osdep/unix/config.c
++++ b/grub-core/osdep/unix/config.c
+@@ -24,6 +24,9 @@
+ #include <grub/emu/config.h>
+ #include <grub/util/install.h>
+ #include <grub/util/misc.h>
++#include <grub/list.h>
++#include <grub/safemath.h>
++#include <assert.h>
+ #include <string.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+@@ -61,13 +64,27 @@ grub_util_get_localedir (void)
+ return LOCALEDIR;
+ }
+
++struct cfglist
++{
++ struct cfglist *next;
++ struct cfglist *prev;
++ char *path;
++};
++
+ void
+ grub_util_load_config (struct grub_util_config *cfg)
+ {
+ pid_t pid;
+ const char *argv[4];
+- char *script, *ptr;
++ char *script = NULL, *ptr;
+ const char *cfgfile, *iptr;
++ char *cfgdir;
++ grub_util_fd_dir_t d;
++ struct cfglist *cfgpaths = NULL, *cfgpath, *next_cfgpath;
++ int num_cfgpaths = 0;
++ size_t len_cfgpaths = 0;
++ char **sorted_cfgpaths = NULL;
++ int i;
+ FILE *f = NULL;
+ int fd;
+ const char *v;
+@@ -83,29 +100,88 @@ grub_util_load_config (struct grub_util_config *cfg)
+ cfg->grub_distributor = xstrdup (v);
+
+ cfgfile = grub_util_get_config_filename ();
+- if (!grub_util_is_regular (cfgfile))
+- return;
++ if (grub_util_is_regular (cfgfile))
++ {
++ size_t sz;
++
++ ++num_cfgpaths;
++ sz = strlen (cfgfile);
++ if (grub_mul (sz, 4, &sz) ||
++ grub_add (sz, sizeof (". ''; ") - 1, &sz) ||
++ grub_add (len_cfgpaths, sz, &len_cfgpaths))
++ grub_util_error ("%s", _("overflow is detected"));
++ }
++
++ cfgdir = xasprintf ("%s.d", cfgfile);
++ d = grub_util_fd_opendir (cfgdir);
++ if (d)
++ {
++ grub_util_fd_dirent_t de;
++
++ while ((de = grub_util_fd_readdir (d)))
++ {
++ const char *ext = strrchr (de->d_name, '.');
++ size_t sz;
++
++ if (!ext || strcmp (ext, ".cfg") != 0)
++ continue;
++
++ cfgpath = xmalloc (sizeof (*cfgpath));
++ cfgpath->path = grub_util_path_concat (2, cfgdir, de->d_name);
++ grub_list_push (GRUB_AS_LIST_P (&cfgpaths), GRUB_AS_LIST (cfgpath));
++ ++num_cfgpaths;
++ sz = strlen (cfgpath->path);
++ if (grub_mul (sz, 4, &sz) ||
++ grub_add (sz, sizeof (". ''; ") - 1, &sz) ||
++ grub_add (len_cfgpaths, sz, &len_cfgpaths))
++ grub_util_error ("%s", _("overflow is detected"));
++ }
++ grub_util_fd_closedir (d);
++ }
++
++ if (num_cfgpaths == 0)
++ goto out;
++
++ sorted_cfgpaths = xcalloc (num_cfgpaths, sizeof (*sorted_cfgpaths));
++ i = 0;
++ if (grub_util_is_regular (cfgfile))
++ sorted_cfgpaths[i++] = xstrdup (cfgfile);
++ FOR_LIST_ELEMENTS_SAFE (cfgpath, next_cfgpath, cfgpaths)
++ {
++ sorted_cfgpaths[i++] = cfgpath->path;
++ free (cfgpath);
++ }
++ assert (i == num_cfgpaths);
++ qsort (sorted_cfgpaths + 1, num_cfgpaths - 1, sizeof (*sorted_cfgpaths),
++ (int (*) (const void *, const void *)) strcmp);
+
+ argv[0] = "sh";
+ argv[1] = "-c";
+
+- script = xcalloc (4, strlen (cfgfile) + 300);
++ if (grub_add (len_cfgpaths, 300, &len_cfgpaths))
++ grub_util_error ("%s", _("overflow is detected"));
++ script = xmalloc (len_cfgpaths);
+
+ ptr = script;
+- memcpy (ptr, ". '", 3);
+- ptr += 3;
+- for (iptr = cfgfile; *iptr; iptr++)
++ for (i = 0; i < num_cfgpaths; i++)
+ {
+- if (*iptr == '\\')
++ memcpy (ptr, ". '", 3);
++ ptr += 3;
++ for (iptr = sorted_cfgpaths[i]; *iptr; iptr++)
+ {
+- memcpy (ptr, "'\\''", 4);
+- ptr += 4;
+- continue;
++ if (*iptr == '\\')
++ {
++ memcpy (ptr, "'\\''", 4);
++ ptr += 4;
++ continue;
++ }
++ *ptr++ = *iptr;
+ }
+- *ptr++ = *iptr;
++ memcpy (ptr, "'; ", 3);
++ ptr += 3;
+ }
+
+- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
++ strcpy (ptr, "printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
+ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\"");
+
+ argv[2] = script;
+@@ -125,15 +201,25 @@ grub_util_load_config (struct grub_util_config *cfg)
+ waitpid (pid, NULL, 0);
+ }
+ if (f)
+- return;
++ goto out;
+
+- f = grub_util_fopen (cfgfile, "r");
+- if (f)
++ for (i = 0; i < num_cfgpaths; i++)
+ {
+- grub_util_parse_config (f, cfg, 0);
+- fclose (f);
++ f = grub_util_fopen (sorted_cfgpaths[i], "r");
++ if (f)
++ {
++ grub_util_parse_config (f, cfg, 0);
++ fclose (f);
++ }
++ else
++ grub_util_warn (_("cannot open configuration file `%s': %s"),
++ cfgfile, strerror (errno));
+ }
+- else
+- grub_util_warn (_("cannot open configuration file `%s': %s"),
+- cfgfile, strerror (errno));
++
++out:
++ free (script);
++ for (i = 0; i < num_cfgpaths; i++)
++ free (sorted_cfgpaths[i]);
++ free (sorted_cfgpaths);
++ free (cfgdir);
+ }
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 0fd618e35..0265a5a66 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -160,6 +160,11 @@ fi
+ if test -f ${sysconfdir}/default/grub ; then
+ . ${sysconfdir}/default/grub
+ fi
++for x in ${sysconfdir}/default/grub.d/*.cfg ; do
++ if [ -e "${x}" ]; then
++ . "${x}"
++ fi
++done
+
+ if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then
+ if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then
diff --git a/debian/patches/dejavu-font-path.patch b/debian/patches/dejavu-font-path.patch
new file mode 100644
index 0000000..cda9800
--- /dev/null
+++ b/debian/patches/dejavu-font-path.patch
@@ -0,0 +1,23 @@
+From 973e040bdeddcf366a7a45bb5d9f77e06f4784c7 Mon Sep 17 00:00:00 2001
+From: Fabian Greffrath <fabian@greffrath.com>
+Date: Tue, 19 May 2020 12:19:26 +0200
+Subject: add /u/s/fonts/truetype/dejavu to the DejaVu fonts search paths
+
+Patch-Name: dejavu-font-path.patch
+---
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index b3fb7437e..22c6cf7ac 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1719,7 +1719,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/dejavu /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do
+ if test -f "$dir/DejaVuSans.$ext"; then
+ DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext"
+ break 2
diff --git a/debian/patches/disable-floppies.patch b/debian/patches/disable-floppies.patch
new file mode 100644
index 0000000..ee4ae5a
--- /dev/null
+++ b/debian/patches/disable-floppies.patch
@@ -0,0 +1,37 @@
+From 6a1ff6845e571d2a9885763a3e52a16a9eec54bb Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:12:54 +0000
+Subject: Disable use of floppy devices
+
+An ugly kludge. Should this be merged upstream?
+
+Author: Robert Millan
+
+Patch-Name: disable-floppies.patch
+---
+ grub-core/kern/emu/hostdisk.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/grub-core/kern/emu/hostdisk.c b/grub-core/kern/emu/hostdisk.c
+index d975265b2..f90b6c9ce 100644
+--- a/grub-core/kern/emu/hostdisk.c
++++ b/grub-core/kern/emu/hostdisk.c
+@@ -532,6 +532,18 @@ read_device_map (const char *dev_map)
+ continue;
+ }
+
++ if (! strncmp (p, "/dev/fd", sizeof ("/dev/fd") - 1))
++ {
++ char *q = p + sizeof ("/dev/fd") - 1;
++ if (*q >= '0' && *q <= '9')
++ {
++ free (map[drive].drive);
++ map[drive].drive = NULL;
++ grub_util_info ("`%s' looks like a floppy drive, skipping", p);
++ continue;
++ }
++ }
++
+ /* On Linux, the devfs uses symbolic links horribly, and that
+ confuses the interface very much, so use realpath to expand
+ symbolic links. */
diff --git a/debian/patches/disk-cryptodisk-when-cheatmounting-use-the-sector-info-of-the-cheat-device.patch b/debian/patches/disk-cryptodisk-when-cheatmounting-use-the-sector-info-of-the-cheat-device.patch
new file mode 100644
index 0000000..1c7d781
--- /dev/null
+++ b/debian/patches/disk-cryptodisk-when-cheatmounting-use-the-sector-info-of-the-cheat-device.patch
@@ -0,0 +1,72 @@
+From: Fabian Vogt <fvogt@suse.de>
+Date: Thu, 12 Jan 2023 17:05:07 -0600
+Subject: disk/cryptodisk: When cheatmounting, use the sector info of the cheat
+ device
+Origin: https://git.savannah.gnu.org/cgit/grub.git/commit/?id=efc9c363b2aab222586b420508eb46fc13242739
+Bug-Debian: https://bugs.debian.org/1028301
+
+When using grub-probe with cryptodisk, the mapped block device from the host
+is used directly instead of decrypting the source device in GRUB code.
+In that case, the sector size and count of the host device needs to be used.
+This is especially important when using LUKS2, which does not assign
+total_sectors and log_sector_size when scanning, but only later when the
+segments in the JSON area are evaluated. With an unset log_sector_size,
+grub_device_open() complains.
+
+This fixes grub-probe failing with
+"error: sector sizes of 1 bytes aren't supported yet.".
+
+Signed-off-by: Fabian Vogt <fvogt@suse.de>
+Reviewed-by: Patrick Steinhardt <ps@pks.im>
+Tested-by: Glenn Washburn <development@efficientek.com>
+Reviewed-by: Glenn Washburn <development@efficientek.com>
+Reviewed-by: Patrick Steinhardt <ps@pks.im>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/disk/cryptodisk.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+--- a/grub-core/disk/cryptodisk.c
++++ b/grub-core/disk/cryptodisk.c
+@@ -694,16 +694,31 @@ grub_cryptodisk_open (const char *name,
+ if (!dev)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
+
+- disk->log_sector_size = dev->log_sector_size;
+-
+ #ifdef GRUB_UTIL
+ if (dev->cheat)
+ {
++ grub_uint64_t cheat_dev_size;
++ unsigned int cheat_log_sector_size;
++
+ if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
+ dev->cheat_fd = grub_util_fd_open (dev->cheat, GRUB_UTIL_FD_O_RDONLY);
+ if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
+ return grub_error (GRUB_ERR_IO, N_("cannot open `%s': %s"),
+ dev->cheat, grub_util_fd_strerror ());
++
++ /* Use the sector size and count of the cheat device. */
++ cheat_dev_size = grub_util_get_fd_size (dev->cheat_fd, dev->cheat, &cheat_log_sector_size);
++ if (cheat_dev_size == -1)
++ {
++ const char *errmsg = grub_util_fd_strerror ();
++ grub_util_fd_close (dev->cheat_fd);
++ dev->cheat_fd = GRUB_UTIL_FD_INVALID;
++ return grub_error (GRUB_ERR_IO, N_("failed to query size of device `%s': %s"),
++ dev->cheat, errmsg);
++ }
++
++ dev->log_sector_size = cheat_log_sector_size;
++ dev->total_sectors = cheat_dev_size >> cheat_log_sector_size;
+ }
+ #endif
+
+@@ -717,6 +732,7 @@ grub_cryptodisk_open (const char *name,
+ }
+
+ disk->data = dev;
++ disk->log_sector_size = dev->log_sector_size;
+ disk->total_sectors = dev->total_sectors;
+ disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
+ disk->id = dev->id;
diff --git a/debian/patches/dpkg-version-comparison.patch b/debian/patches/dpkg-version-comparison.patch
new file mode 100644
index 0000000..d20e986
--- /dev/null
+++ b/debian/patches/dpkg-version-comparison.patch
@@ -0,0 +1,38 @@
+From 562d50025e18052cabc40c8eb63ed4d0bb5de236 Mon Sep 17 00:00:00 2001
+From: Robert Millan <rmh@aybabtu.com>
+Date: Mon, 13 Jan 2014 12:12:52 +0000
+Subject: Improve handling of Debian kernel version numbers
+
+Forwarded: not-needed
+Last-Update: 2013-12-20
+
+Patch-Name: dpkg-version-comparison.patch
+---
+ util/grub-mkconfig_lib.in | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 301d1ac22..17f9b3e58 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -243,8 +243,9 @@ version_test_numeric ()
+
+ version_test_gt ()
+ {
+- version_test_gt_a="`echo "$1" | sed -e "s/[^-]*-//"`"
+- version_test_gt_b="`echo "$2" | sed -e "s/[^-]*-//"`"
++ version_test_gt_sedexp="s/[^-]*-//;s/[._-]\(pre\|rc\|test\|git\|old\|trunk\)/~\1/g"
++ version_test_gt_a="`echo "$1" | sed -e "$version_test_gt_sedexp"`"
++ version_test_gt_b="`echo "$2" | sed -e "$version_test_gt_sedexp"`"
+ version_test_gt_cmp=gt
+ if [ "x$version_test_gt_b" = "x" ] ; then
+ return 0
+@@ -254,7 +255,7 @@ version_test_gt ()
+ *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;;
+ *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;;
+ esac
+- version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b"
++ dpkg --compare-versions "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b"
+ return "$?"
+ }
+
diff --git a/debian/patches/efi-variable-storage-minimise-writes.patch b/debian/patches/efi-variable-storage-minimise-writes.patch
new file mode 100644
index 0000000..c06dbe8
--- /dev/null
+++ b/debian/patches/efi-variable-storage-minimise-writes.patch
@@ -0,0 +1,895 @@
+From 6e3841fc4abf50d16d819c39ac5de74ccc4de225 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 11 Mar 2019 11:17:43 +0000
+Subject: Minimise writes to EFI variable storage
+
+Some UEFI firmware is easily provoked into running out of space in its
+variable storage. This is usually due to certain kernel drivers (e.g.
+pstore), but regardless of the cause it can cause grub-install to fail
+because it currently asks efibootmgr to delete and re-add entries, and
+the deletion often doesn't result in an immediate garbage collection.
+Writing variables frequently also increases wear on the NVRAM which may
+have limited write cycles. For these reasons, it's desirable to find a
+way to minimise writes while still allowing grub-install to ensure that
+a suitable boot entry exists.
+
+Unfortunately, efibootmgr doesn't offer an interface that would let
+grub-install do this. It doesn't in general make very much effort to
+minimise writes; it doesn't allow modifying an existing Boot* variable
+entry, except in certain limited ways; and current versions don't have a
+way to export the expected variable data so that grub-install can
+compare it to the current data. While it would be possible (and perhaps
+desirable?) to add at least some of this to efibootmgr, that would still
+leave the problem that there isn't a good upstreamable way for
+grub-install to guarantee that it has a new enough version of
+efibootmgr. In any case, it's cumbersome and slow for grub-install to
+have to fork efibootmgr to get things done.
+
+Fortunately, a few years ago Peter Jones helpfully factored out a
+substantial part of efibootmgr to the efivar and efiboot libraries, and
+so it's now possible to have grub-install use those directly. We still
+have to use some code from efibootmgr, but much less than would
+previously have been necessary.
+
+grub-install now reuses existing boot entries where possible, and avoids
+writing to variables when the new contents are the same as the old
+contents. In the common upgrade case where nothing needs to change, it
+no longer writes to NVRAM at all. It's also now slightly faster, since
+using libefivar is faster than forking efibootmgr.
+
+Fixes Debian bug #891434.
+
+Signed-off-by: Colin Watson <cjwatson@ubuntu.com>
+
+Bug-Debian: https://bugs.debian.org/891434
+Forwarded: https://lists.gnu.org/archive/html/grub-devel/2019-03/msg00119.html
+Last-Update: 2019-03-23
+
+Patch-Name: efi-variable-storage-minimise-writes.patch
+---
+ INSTALL | 5 +
+ Makefile.util.def | 20 ++
+ configure.ac | 12 +
+ grub-core/osdep/efivar.c | 3 +
+ grub-core/osdep/unix/efivar.c | 508 ++++++++++++++++++++++++++++++++
+ grub-core/osdep/unix/platform.c | 100 +------
+ include/grub/util/install.h | 5 +
+ util/grub-install.c | 4 +-
+ 8 files changed, 562 insertions(+), 95 deletions(-)
+ create mode 100644 grub-core/osdep/efivar.c
+ create mode 100644 grub-core/osdep/unix/efivar.c
+
+diff --git a/INSTALL b/INSTALL
+index 79a0af7d9..590b52482 100644
+--- a/INSTALL
++++ b/INSTALL
+@@ -23,6 +23,11 @@ configuring the GRUB.
+ * Other standard GNU/Unix tools
+ * a libc with large file support (e.g. glibc 2.1 or later)
+
++On Unix-based systems, you also need:
++
++* libefivar (recommended)
++* libefiboot (recommended; your OS may ship this together with libefivar)
++
+ On GNU/Linux, you also need:
+
+ * libdevmapper 1.02.34 or later (recommended)
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 27f948291..a3d134b03 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -570,6 +570,8 @@ program = {
+ common = grub-core/osdep/compress.c;
+ extra_dist = grub-core/osdep/unix/compress.c;
+ extra_dist = grub-core/osdep/basic/compress.c;
++ common = grub-core/osdep/efivar.c;
++ extra_dist = grub-core/osdep/unix/efivar.c;
+ common = util/editenv.c;
+ common = grub-core/osdep/blocklist.c;
+ common = grub-core/osdep/config.c;
+@@ -583,12 +585,15 @@ program = {
+ common = grub-core/kern/emu/argp_common.c;
+ common = grub-core/osdep/init.c;
+
++ cflags = '$(EFIVAR_CFLAGS)';
++
+ ldadd = '$(LIBLZMA)';
+ ldadd = libgrubmods.a;
+ ldadd = libgrubgcry.a;
+ ldadd = libgrubkern.a;
+ ldadd = grub-core/lib/gnulib/libgnu.a;
+ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
++ ldadd = '$(EFIVAR_LIBS)';
+
+ condition = COND_HAVE_EXEC;
+ };
+@@ -617,6 +622,8 @@ program = {
+ extra_dist = grub-core/osdep/basic/no_platform.c;
+ extra_dist = grub-core/osdep/unix/platform.c;
+ common = grub-core/osdep/compress.c;
++ common = grub-core/osdep/efivar.c;
++ extra_dist = grub-core/osdep/unix/efivar.c;
+ common = util/editenv.c;
+ common = grub-core/osdep/blocklist.c;
+ common = grub-core/osdep/config.c;
+@@ -630,12 +637,15 @@ program = {
+ common = grub-core/kern/emu/argp_common.c;
+ common = grub-core/osdep/init.c;
+
++ cflags = '$(EFIVAR_CFLAGS)';
++
+ ldadd = '$(LIBLZMA)';
+ ldadd = libgrubmods.a;
+ ldadd = libgrubgcry.a;
+ ldadd = libgrubkern.a;
+ ldadd = grub-core/lib/gnulib/libgnu.a;
+ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
++ ldadd = '$(EFIVAR_LIBS)';
+ };
+
+ program = {
+@@ -657,6 +667,8 @@ program = {
+ common = grub-core/osdep/platform.c;
+ common = grub-core/osdep/platform_unix.c;
+ common = grub-core/osdep/compress.c;
++ common = grub-core/osdep/efivar.c;
++ extra_dist = grub-core/osdep/unix/efivar.c;
+ common = util/editenv.c;
+ common = grub-core/osdep/blocklist.c;
+ common = grub-core/osdep/config.c;
+@@ -669,12 +681,15 @@ program = {
+ common = grub-core/kern/emu/argp_common.c;
+ common = grub-core/osdep/init.c;
+
++ cflags = '$(EFIVAR_CFLAGS)';
++
+ ldadd = '$(LIBLZMA)';
+ ldadd = libgrubmods.a;
+ ldadd = libgrubgcry.a;
+ ldadd = libgrubkern.a;
+ ldadd = grub-core/lib/gnulib/libgnu.a;
+ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
++ ldadd = '$(EFIVAR_LIBS)';
+ };
+
+ program = {
+@@ -696,6 +711,8 @@ program = {
+ common = grub-core/osdep/platform.c;
+ common = grub-core/osdep/platform_unix.c;
+ common = grub-core/osdep/compress.c;
++ common = grub-core/osdep/efivar.c;
++ extra_dist = grub-core/osdep/unix/efivar.c;
+ common = util/editenv.c;
+ common = grub-core/osdep/blocklist.c;
+ common = grub-core/osdep/config.c;
+@@ -705,12 +722,15 @@ program = {
+ common = grub-core/kern/emu/argp_common.c;
+ common = grub-core/osdep/init.c;
+
++ cflags = '$(EFIVAR_CFLAGS)';
++
+ ldadd = '$(LIBLZMA)';
+ ldadd = libgrubmods.a;
+ ldadd = libgrubgcry.a;
+ ldadd = libgrubkern.a;
+ ldadd = grub-core/lib/gnulib/libgnu.a;
+ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
++ ldadd = '$(EFIVAR_LIBS)';
+ };
+
+ script = {
+diff --git a/configure.ac b/configure.ac
+index e11df6bc5..b3fb7437e 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -452,6 +452,18 @@ AC_CHECK_HEADER([util.h], [
+ ])
+ AC_SUBST([LIBUTIL])
+
++case "$host_os" in
++ cygwin | windows* | mingw32* | aros*)
++ ;;
++ *)
++ # For setting EFI variables in grub-install.
++ PKG_CHECK_MODULES([EFIVAR], [efivar efiboot], [
++ AC_DEFINE([HAVE_EFIVAR], [1],
++ [Define to 1 if you have the efivar and efiboot libraries.])
++ ], [:])
++ ;;
++esac
++
+ AC_CACHE_CHECK([whether -Wtrampolines work], [grub_cv_host_cc_wtrampolines], [
+ SAVED_CFLAGS="$CFLAGS"
+ CFLAGS="$HOST_CFLAGS -Wtrampolines -Werror"
+diff --git a/grub-core/osdep/efivar.c b/grub-core/osdep/efivar.c
+new file mode 100644
+index 000000000..d2750e252
+--- /dev/null
++++ b/grub-core/osdep/efivar.c
+@@ -0,0 +1,3 @@
++#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__AROS__)
++#include "unix/efivar.c"
++#endif
+diff --git a/grub-core/osdep/unix/efivar.c b/grub-core/osdep/unix/efivar.c
+new file mode 100644
+index 000000000..4a58328b4
+--- /dev/null
++++ b/grub-core/osdep/unix/efivar.c
+@@ -0,0 +1,508 @@
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2013,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 <http://www.gnu.org/licenses/>.
++ */
++
++/* Contains portions derived from efibootmgr, licensed as follows:
++ *
++ * Copyright (C) 2001-2004 Dell, Inc. <Matt_Domsch@dell.com>
++ * Copyright 2015-2016 Red Hat, Inc. <pjones@redhat.com>
++ *
++ * 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 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <config.h>
++
++#ifdef HAVE_EFIVAR
++
++#include <grub/util/install.h>
++#include <grub/emu/hostdisk.h>
++#include <grub/util/misc.h>
++#include <grub/list.h>
++#include <grub/misc.h>
++#include <grub/emu/exec.h>
++#include <sys/types.h>
++#include <ctype.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <efiboot.h>
++#include <efivar.h>
++
++struct efi_variable {
++ struct efi_variable *next;
++ struct efi_variable **prev;
++ char *name;
++ efi_guid_t guid;
++ uint8_t *data;
++ size_t data_size;
++ uint32_t attributes;
++ int num;
++};
++
++/* Boot option attributes. */
++#define LOAD_OPTION_ACTIVE 0x00000001
++
++/* GUIDs. */
++#define BLKX_UNKNOWN_GUID \
++ EFI_GUID (0x47c7b225, 0xc42a, 0x11d2, 0x8e57, 0x00, 0xa0, 0xc9, 0x69, \
++ 0x72, 0x3b)
++
++/* Log all errors recorded by libefivar/libefiboot. */
++static void
++show_efi_errors (void)
++{
++ int i;
++ int saved_errno = errno;
++
++ for (i = 0; ; ++i)
++ {
++ char *filename, *function, *message = NULL;
++ int line, error = 0, rc;
++
++ rc = efi_error_get (i, &filename, &function, &line, &message, &error);
++ if (rc < 0)
++ /* Give up. The caller is going to log an error anyway. */
++ break;
++ if (rc == 0)
++ /* No more errors. */
++ break;
++ grub_util_warn ("%s: %s: %s", function, message, strerror (error));
++ }
++
++ efi_error_clear ();
++ errno = saved_errno;
++}
++
++static struct efi_variable *
++new_efi_variable (void)
++{
++ struct efi_variable *new = xmalloc (sizeof (*new));
++ memset (new, 0, sizeof (*new));
++ return new;
++}
++
++static struct efi_variable *
++new_boot_variable (void)
++{
++ struct efi_variable *new = new_efi_variable ();
++ new->guid = EFI_GLOBAL_GUID;
++ new->attributes = EFI_VARIABLE_NON_VOLATILE |
++ EFI_VARIABLE_BOOTSERVICE_ACCESS |
++ EFI_VARIABLE_RUNTIME_ACCESS;
++ return new;
++}
++
++static void
++free_efi_variable (struct efi_variable *entry)
++{
++ if (entry)
++ {
++ free (entry->name);
++ free (entry->data);
++ free (entry);
++ }
++}
++
++static int
++read_efi_variable (const char *name, struct efi_variable **entry)
++{
++ struct efi_variable *new = new_efi_variable ();
++ int rc;
++
++ rc = efi_get_variable (EFI_GLOBAL_GUID, name,
++ &new->data, &new->data_size, &new->attributes);
++ if (rc < 0)
++ {
++ free_efi_variable (new);
++ new = NULL;
++ }
++
++ if (new)
++ {
++ /* Latest Apple firmware sets the high bit which appears invalid
++ to the Linux kernel if we write it back, so let's zero it out if it
++ is set since it would be invalid to set it anyway. */
++ new->attributes = new->attributes & ~(1 << 31);
++
++ new->name = xstrdup (name);
++ new->guid = EFI_GLOBAL_GUID;
++ }
++
++ *entry = new;
++ return rc;
++}
++
++/* Set an EFI variable, but only if it differs from the current value.
++ Some firmware implementations are liable to fill up flash space if we set
++ variables unnecessarily, so try to keep write activity to a minimum. */
++static int
++set_efi_variable (const char *name, struct efi_variable *entry)
++{
++ struct efi_variable *old = NULL;
++ int rc = 0;
++
++ read_efi_variable (name, &old);
++ efi_error_clear ();
++ if (old && old->attributes == entry->attributes &&
++ old->data_size == entry->data_size &&
++ memcmp (old->data, entry->data, entry->data_size) == 0)
++ grub_util_info ("skipping unnecessary update of EFI variable %s", name);
++ else
++ {
++ rc = efi_set_variable (EFI_GLOBAL_GUID, name,
++ entry->data, entry->data_size, entry->attributes,
++ 0644);
++ if (rc < 0)
++ grub_util_warn (_("Cannot set EFI variable %s"), name);
++ }
++ free_efi_variable (old);
++ return rc;
++}
++
++static int
++cmpvarbyname (const void *p1, const void *p2)
++{
++ const struct efi_variable *var1 = *(const struct efi_variable **)p1;
++ const struct efi_variable *var2 = *(const struct efi_variable **)p2;
++ return strcmp (var1->name, var2->name);
++}
++
++static int
++read_boot_variables (struct efi_variable **varlist)
++{
++ int rc;
++ efi_guid_t *guid = NULL;
++ char *name = NULL;
++ struct efi_variable **newlist = NULL;
++ int nentries = 0;
++ int i;
++
++ while ((rc = efi_get_next_variable_name (&guid, &name)) > 0)
++ {
++ const char *snum = name + sizeof ("Boot") - 1;
++ struct efi_variable *var = NULL;
++ unsigned int num;
++
++ if (memcmp (guid, &efi_guid_global, sizeof (efi_guid_global)) != 0 ||
++ strncmp (name, "Boot", sizeof ("Boot") - 1) != 0 ||
++ !grub_isxdigit (snum[0]) || !grub_isxdigit (snum[1]) ||
++ !grub_isxdigit (snum[2]) || !grub_isxdigit (snum[3]))
++ continue;
++
++ rc = read_efi_variable (name, &var);
++ if (rc < 0)
++ break;
++
++ if (sscanf (var->name, "Boot%04X-%*s", &num) == 1 && num < 65536)
++ var->num = num;
++
++ newlist = xrealloc (newlist, (++nentries) * sizeof (*newlist));
++ newlist[nentries - 1] = var;
++ }
++ if (rc == 0 && newlist)
++ {
++ qsort (newlist, nentries, sizeof (*newlist), cmpvarbyname);
++ for (i = nentries - 1; i >= 0; --i)
++ grub_list_push (GRUB_AS_LIST_P (varlist), GRUB_AS_LIST (newlist[i]));
++ }
++ else if (newlist)
++ {
++ for (i = 0; i < nentries; ++i)
++ free_efi_variable (newlist[i]);
++ free (newlist);
++ }
++ return rc;
++}
++
++#define GET_ORDER(data, i) \
++ ((uint16_t) ((data)[(i) * 2]) + ((data)[(i) * 2 + 1] << 8))
++#define SET_ORDER(data, i, num) \
++ do { \
++ (data)[(i) * 2] = (num) & 0xFF; \
++ (data)[(i) * 2 + 1] = ((num) >> 8) & 0xFF; \
++ } while (0)
++
++static void
++remove_from_boot_order (struct efi_variable *order, uint16_t num)
++{
++ unsigned int old_i, new_i;
++
++ /* We've got an array (in order->data) of the order. Squeeze out any
++ instance of the entry we're deleting by shifting the remainder down. */
++ for (old_i = 0, new_i = 0;
++ old_i < order->data_size / sizeof (uint16_t);
++ ++old_i)
++ {
++ uint16_t old_num = GET_ORDER (order->data, old_i);
++ if (old_num != num)
++ {
++ if (new_i != old_i)
++ SET_ORDER (order->data, new_i, old_num);
++ ++new_i;
++ }
++ }
++
++ order->data_size = new_i * sizeof (uint16_t);
++}
++
++static void
++add_to_boot_order (struct efi_variable *order, uint16_t num)
++{
++ int i;
++ size_t new_data_size;
++ uint8_t *new_data;
++
++ /* Check whether this entry is already in the boot order. If it is, leave
++ it alone. */
++ for (i = 0; i < order->data_size / sizeof (uint16_t); ++i)
++ if (GET_ORDER (order->data, i) == num)
++ return;
++
++ new_data_size = order->data_size + sizeof (uint16_t);
++ new_data = xmalloc (new_data_size);
++ SET_ORDER (new_data, 0, num);
++ memcpy (new_data + sizeof (uint16_t), order->data, order->data_size);
++ free (order->data);
++ order->data = new_data;
++ order->data_size = new_data_size;
++}
++
++static int
++find_free_boot_num (struct efi_variable *entries)
++{
++ int num_vars = 0, i;
++ struct efi_variable *entry;
++
++ FOR_LIST_ELEMENTS (entry, entries)
++ ++num_vars;
++
++ if (num_vars == 0)
++ return 0;
++
++ /* O(n^2), but n is small and this is easy. */
++ for (i = 0; i < num_vars; ++i)
++ {
++ int found = 0;
++ FOR_LIST_ELEMENTS (entry, entries)
++ {
++ if (entry->num == i)
++ {
++ found = 1;
++ break;
++ }
++ }
++ if (!found)
++ return i;
++ }
++
++ return i;
++}
++
++static int
++get_edd_version (void)
++{
++ efi_guid_t blkx_guid = BLKX_UNKNOWN_GUID;
++ uint8_t *data = NULL;
++ size_t data_size = 0;
++ uint32_t attributes;
++ efidp_header *path;
++ int rc;
++
++ rc = efi_get_variable (blkx_guid, "blk0", &data, &data_size, &attributes);
++ if (rc < 0)
++ return rc;
++
++ path = (efidp_header *) data;
++ if (path->type == 2 && path->subtype == 1)
++ return 3;
++ return 1;
++}
++
++static struct efi_variable *
++make_boot_variable (int num, const char *disk, int part, const char *loader,
++ const char *label)
++{
++ struct efi_variable *entry = new_boot_variable ();
++ uint32_t options;
++ uint32_t edd10_devicenum;
++ ssize_t dp_needed, loadopt_needed;
++ efidp dp = NULL;
++
++ options = EFIBOOT_ABBREV_HD;
++ switch (get_edd_version ()) {
++ case 1:
++ options = EFIBOOT_ABBREV_EDD10;
++ break;
++ case 3:
++ options = EFIBOOT_ABBREV_NONE;
++ break;
++ }
++
++ /* This may not be the right disk; but it's probably only an issue on very
++ old hardware anyway. */
++ edd10_devicenum = 0x80;
++
++ dp_needed = efi_generate_file_device_path_from_esp (NULL, 0, disk, part,
++ loader, options,
++ edd10_devicenum);
++ if (dp_needed < 0)
++ goto err;
++
++ dp = xmalloc (dp_needed);
++ dp_needed = efi_generate_file_device_path_from_esp ((uint8_t *) dp,
++ dp_needed, disk, part,
++ loader, options,
++ edd10_devicenum);
++ if (dp_needed < 0)
++ goto err;
++
++ loadopt_needed = efi_loadopt_create (NULL, 0, LOAD_OPTION_ACTIVE,
++ dp, dp_needed, (unsigned char *) label,
++ NULL, 0);
++ if (loadopt_needed < 0)
++ goto err;
++ entry->data_size = loadopt_needed;
++ entry->data = xmalloc (entry->data_size);
++ loadopt_needed = efi_loadopt_create (entry->data, entry->data_size,
++ LOAD_OPTION_ACTIVE, dp, dp_needed,
++ (unsigned char *) label, NULL, 0);
++ if (loadopt_needed < 0)
++ goto err;
++
++ entry->name = xasprintf ("Boot%04X", num);
++ entry->num = num;
++
++ return entry;
++
++err:
++ free_efi_variable (entry);
++ free (dp);
++ return NULL;
++}
++
++int
++grub_install_efivar_register_efi (grub_device_t efidir_grub_dev,
++ const char *efifile_path,
++ const char *efi_distributor)
++{
++ const char *efidir_disk;
++ int efidir_part;
++ struct efi_variable *entries = NULL, *entry;
++ struct efi_variable *order;
++ int entry_num = -1;
++ int rc;
++
++ efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk);
++ efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
++
++#ifdef __linux__
++ /*
++ * Linux uses efivarfs (mounted on /sys/firmware/efi/efivars) to access the
++ * EFI variable store. Some legacy systems may still use the deprecated
++ * efivars interface (accessed through /sys/firmware/efi/vars). Where both
++ * are present, libefivar will use the former in preference, so attempting
++ * to load efivars will not interfere with later operations.
++ */
++ grub_util_exec_redirect_all ((const char * []){ "modprobe", "efivars", NULL },
++ NULL, NULL, "/dev/null");
++#endif
++
++ if (!efi_variables_supported ())
++ {
++ grub_util_warn ("%s",
++ _("EFI variables are not supported on this system."));
++ /* Let the user continue. Perhaps they can still arrange to boot GRUB
++ manually. */
++ return 0;
++ }
++
++ rc = read_boot_variables (&entries);
++ if (rc < 0)
++ {
++ grub_util_warn ("%s", _("Cannot read EFI Boot* variables"));
++ goto err;
++ }
++ rc = read_efi_variable ("BootOrder", &order);
++ if (rc < 0)
++ {
++ order = new_boot_variable ();
++ order->name = xstrdup ("BootOrder");
++ efi_error_clear ();
++ }
++
++ /* Delete old entries from the same distributor. */
++ FOR_LIST_ELEMENTS (entry, entries)
++ {
++ efi_load_option *load_option = (efi_load_option *) entry->data;
++ const char *label;
++
++ if (entry->num < 0)
++ continue;
++ label = (const char *) efi_loadopt_desc (load_option, entry->data_size);
++ if (strcasecmp (label, efi_distributor) != 0)
++ continue;
++
++ /* To avoid problems with some firmware implementations, reuse the first
++ matching variable we find rather than deleting and recreating it. */
++ if (entry_num == -1)
++ entry_num = entry->num;
++ else
++ {
++ grub_util_info ("deleting superfluous EFI variable %s (%s)",
++ entry->name, label);
++ rc = efi_del_variable (EFI_GLOBAL_GUID, entry->name);
++ if (rc < 0)
++ {
++ grub_util_warn (_("Cannot delete EFI variable %s"), entry->name);
++ goto err;
++ }
++ }
++
++ remove_from_boot_order (order, (uint16_t) entry->num);
++ }
++
++ if (entry_num == -1)
++ entry_num = find_free_boot_num (entries);
++ entry = make_boot_variable (entry_num, efidir_disk, efidir_part,
++ efifile_path, efi_distributor);
++ if (!entry)
++ goto err;
++
++ grub_util_info ("setting EFI variable %s", entry->name);
++ rc = set_efi_variable (entry->name, entry);
++ if (rc < 0)
++ goto err;
++
++ add_to_boot_order (order, (uint16_t) entry_num);
++
++ grub_util_info ("setting EFI variable BootOrder");
++ rc = set_efi_variable ("BootOrder", order);
++ if (rc < 0)
++ goto err;
++
++ return 0;
++
++err:
++ show_efi_errors ();
++ return errno;
++}
++
++#endif /* HAVE_EFIVAR */
+diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c
+index 9c439326a..b561174ea 100644
+--- a/grub-core/osdep/unix/platform.c
++++ b/grub-core/osdep/unix/platform.c
+@@ -19,15 +19,12 @@
+ #include <config.h>
+
+ #include <grub/util/install.h>
+-#include <grub/emu/hostdisk.h>
+ #include <grub/util/misc.h>
+ #include <grub/misc.h>
+ #include <grub/i18n.h>
+ #include <grub/emu/exec.h>
+ #include <sys/types.h>
+-#include <dirent.h>
+ #include <string.h>
+-#include <errno.h>
+
+ static char *
+ get_ofpathname (const char *dev)
+@@ -78,102 +75,19 @@ get_ofpathname (const char *dev)
+ dev);
+ }
+
+-static int
+-grub_install_remove_efi_entries_by_distributor (const char *efi_distributor)
+-{
+- int fd;
+- pid_t pid = grub_util_exec_pipe ((const char * []){ "efibootmgr", NULL }, &fd);
+- char *line = NULL;
+- size_t len = 0;
+- int rc = 0;
+-
+- if (!pid)
+- {
+- grub_util_warn (_("Unable to open stream from %s: %s"),
+- "efibootmgr", strerror (errno));
+- return errno;
+- }
+-
+- FILE *fp = fdopen (fd, "r");
+- if (!fp)
+- {
+- grub_util_warn (_("Unable to open stream from %s: %s"),
+- "efibootmgr", strerror (errno));
+- return errno;
+- }
+-
+- line = xmalloc (80);
+- len = 80;
+- while (1)
+- {
+- int ret;
+- char *bootnum;
+- ret = getline (&line, &len, fp);
+- if (ret == -1)
+- break;
+- if (grub_memcmp (line, "Boot", sizeof ("Boot") - 1) != 0
+- || line[sizeof ("Boot") - 1] < '0'
+- || line[sizeof ("Boot") - 1] > '9')
+- continue;
+- if (!strcasestr (line, efi_distributor))
+- continue;
+- bootnum = line + sizeof ("Boot") - 1;
+- bootnum[4] = '\0';
+- if (!verbosity)
+- rc = grub_util_exec ((const char * []){ "efibootmgr", "-q",
+- "-b", bootnum, "-B", NULL });
+- else
+- rc = grub_util_exec ((const char * []){ "efibootmgr",
+- "-b", bootnum, "-B", NULL });
+- }
+-
+- free (line);
+- return rc;
+-}
+-
+ int
+ grub_install_register_efi (grub_device_t efidir_grub_dev,
+ const char *efifile_path,
+ const char *efi_distributor)
+ {
+- const char * efidir_disk;
+- int efidir_part;
+- int ret;
+- efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk);
+- efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
+-
+- if (grub_util_exec_redirect_null ((const char * []){ "efibootmgr", "--version", NULL }))
+- {
+- /* TRANSLATORS: This message is shown when required executable `%s'
+- isn't found. */
+- grub_util_error (_("%s: not found"), "efibootmgr");
+- }
+-
+- /* On Linux, we need the efivars kernel modules. */
+-#ifdef __linux__
+- grub_util_exec ((const char * []){ "modprobe", "-q", "efivars", NULL });
++#ifdef HAVE_EFIVAR
++ return grub_install_efivar_register_efi (efidir_grub_dev, efifile_path,
++ efi_distributor);
++#else
++ grub_util_error ("%s",
++ _("GRUB was not built with efivar support; "
++ "cannot register EFI boot entry"));
+ #endif
+- /* Delete old entries from the same distributor. */
+- ret = grub_install_remove_efi_entries_by_distributor (efi_distributor);
+- if (ret)
+- return ret;
+-
+- char *efidir_part_str = xasprintf ("%d", efidir_part);
+-
+- if (!verbosity)
+- ret = grub_util_exec ((const char * []){ "efibootmgr", "-q",
+- "-c", "-d", efidir_disk,
+- "-p", efidir_part_str, "-w",
+- "-L", efi_distributor, "-l",
+- efifile_path, NULL });
+- else
+- ret = grub_util_exec ((const char * []){ "efibootmgr",
+- "-c", "-d", efidir_disk,
+- "-p", efidir_part_str, "-w",
+- "-L", efi_distributor, "-l",
+- efifile_path, NULL });
+- free (efidir_part_str);
+- return ret;
+ }
+
+ void
+diff --git a/include/grub/util/install.h b/include/grub/util/install.h
+index 135ba48d2..134b862ec 100644
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -226,6 +226,11 @@ grub_install_get_default_x86_platform (void);
+ const char *
+ grub_install_get_default_powerpc_machtype (void);
+
++int
++grub_install_efivar_register_efi (grub_device_t efidir_grub_dev,
++ const char *efifile_path,
++ const char *efi_distributor);
++
+ int
+ grub_install_register_efi (grub_device_t efidir_grub_dev,
+ const char *efifile_path,
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 58f1453ba..05b695226 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -2086,7 +2086,7 @@ main (int argc, char *argv[])
+ "\\System\\Library\\CoreServices",
+ efi_distributor);
+ if (ret)
+- grub_util_error (_("efibootmgr failed to register the boot entry: %s"),
++ grub_util_error (_("failed to register the EFI boot entry: %s"),
+ strerror (ret));
+ }
+
+@@ -2203,7 +2203,7 @@ main (int argc, char *argv[])
+ ret = grub_install_register_efi (efidir_grub_dev,
+ efifile_path, efi_distributor);
+ if (ret)
+- grub_util_error (_("efibootmgr failed to register the boot entry: %s"),
++ grub_util_error (_("failed to register the EFI boot entry: %s"),
+ strerror (ret));
+ }
+ break;
diff --git a/debian/patches/efinet-set-dns-from-uefi-proto.patch b/debian/patches/efinet-set-dns-from-uefi-proto.patch
new file mode 100644
index 0000000..9b5861b
--- /dev/null
+++ b/debian/patches/efinet-set-dns-from-uefi-proto.patch
@@ -0,0 +1,341 @@
+From 5a2c53dd059351cf385575fa99d5763bc07e0de2 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 27 Oct 2016 17:43:21 -0400
+Subject: 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 <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+
+Last-Update: 2021-09-24
+
+Patch-Name: efinet-set-dns-from-uefi-proto.patch
+---
+ grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++
+ include/grub/efi/api.h | 76 ++++++++++++++
+ 2 files changed, 239 insertions(+)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 2d3b00f0e..82a28fb6e 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -30,6 +30,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ /* GUID. */
+ static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
+ static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
+
+ static grub_err_t
+ send_card_buffer (struct grub_net_card *dev,
+@@ -325,6 +327,125 @@ grub_efinet_findcards (void)
+ grub_free (handles);
+ }
+
++static grub_efi_handle_t
++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
++ grub_efi_device_path_t **r_device_path)
++{
++ grub_efi_handle_t handle;
++ grub_efi_status_t status;
++
++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
++ protocol, &device_path, &handle);
++
++ if (status != GRUB_EFI_SUCCESS)
++ return 0;
++
++ if (r_device_path)
++ *r_device_path = device_path;
++
++ return handle;
++}
++
++static grub_efi_ipv4_address_t *
++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
++{
++ grub_efi_handle_t hnd;
++ grub_efi_status_t status;
++ grub_efi_ip4_config2_protocol_t *conf;
++ grub_efi_ipv4_address_t *addrs;
++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t);
++
++ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL);
++
++ if (!hnd)
++ return 0;
++
++ conf = grub_efi_open_protocol (hnd, &ip4_config_guid,
++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++ if (!conf)
++ return 0;
++
++ addrs = grub_malloc (data_size);
++ if (!addrs)
++ return 0;
++
++ status = efi_call_4 (conf->get_data, conf,
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++ &data_size, addrs);
++
++ if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++ {
++ grub_free (addrs);
++ addrs = grub_malloc (data_size);
++ if (!addrs)
++ return 0;
++
++ status = efi_call_4 (conf->get_data, conf,
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++ &data_size, addrs);
++ }
++
++ if (status != GRUB_EFI_SUCCESS)
++ {
++ grub_free (addrs);
++ return 0;
++ }
++
++ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t);
++ return addrs;
++}
++
++static grub_efi_ipv6_address_t *
++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
++{
++ grub_efi_handle_t hnd;
++ grub_efi_status_t status;
++ grub_efi_ip6_config_protocol_t *conf;
++ grub_efi_ipv6_address_t *addrs;
++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t);
++
++ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL);
++
++ if (!hnd)
++ return 0;
++
++ conf = grub_efi_open_protocol (hnd, &ip6_config_guid,
++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++ if (!conf)
++ return 0;
++
++ addrs = grub_malloc (data_size);
++ if (!addrs)
++ return 0;
++
++ status = efi_call_4 (conf->get_data, conf,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++ &data_size, addrs);
++
++ if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++ {
++ grub_free (addrs);
++ addrs = grub_malloc (data_size);
++ if (!addrs)
++ return 0;
++
++ status = efi_call_4 (conf->get_data, conf,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++ &data_size, addrs);
++ }
++
++ if (status != GRUB_EFI_SUCCESS)
++ {
++ grub_free (addrs);
++ return 0;
++ }
++
++ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t);
++ return addrs;
++}
++
+ static struct grub_net_buff *
+ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
+ {
+@@ -377,6 +498,8 @@ grub_efinet_create_dhcp_ack_from_device_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);
+@@ -438,6 +561,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)
+@@ -470,6 +612,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));
+@@ -533,6 +677,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 4b4652ca5..9cab1a51d 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -354,6 +354,16 @@
+ { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \
+ }
+
++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \
++ { 0x5b446ed1, 0xe30b, 0x4faa, \
++ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \
++ }
++
++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \
++ { 0x937fe521, 0x95ae, 0x4d1a, \
++ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
++ }
++
+ struct grub_efi_sal_system_table
+ {
+ grub_uint32_t signature;
+@@ -1793,6 +1803,72 @@ struct grub_efi_rng_protocol
+ };
+ typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t;
+
++enum grub_efi_ip4_config2_data_type {
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM
++};
++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t;
++
++struct grub_efi_ip4_config2_protocol
++{
++ grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this,
++ grub_efi_ip4_config2_data_type_t data_type,
++ grub_efi_uintn_t data_size,
++ void *data);
++
++ grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this,
++ grub_efi_ip4_config2_data_type_t data_type,
++ grub_efi_uintn_t *data_size,
++ void *data);
++
++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this,
++ grub_efi_ip4_config2_data_type_t data_type,
++ grub_efi_event_t event);
++
++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this,
++ grub_efi_ip4_config2_data_type_t data_type,
++ grub_efi_event_t event);
++};
++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
++
++enum grub_efi_ip6_config_data_type {
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM
++};
++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t;
++
++struct grub_efi_ip6_config_protocol
++{
++ grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this,
++ grub_efi_ip6_config_data_type_t data_type,
++ grub_efi_uintn_t data_size,
++ void *data);
++
++ grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this,
++ grub_efi_ip6_config_data_type_t data_type,
++ grub_efi_uintn_t *data_size,
++ void *data);
++
++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this,
++ grub_efi_ip6_config_data_type_t data_type,
++ grub_efi_event_t event);
++
++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this,
++ grub_efi_ip6_config_data_type_t data_type,
++ grub_efi_event_t event);
++};
++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
++
+ #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
+ || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
+ || defined(__riscv)
diff --git a/debian/patches/efinet-set-network-from-uefi-devpath.patch b/debian/patches/efinet-set-network-from-uefi-devpath.patch
new file mode 100644
index 0000000..bf97ddf
--- /dev/null
+++ b/debian/patches/efinet-set-network-from-uefi-devpath.patch
@@ -0,0 +1,388 @@
+From 3f85b646c8f6188f6e2122fc90351fb900e1b337 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 27 Oct 2016 17:43:05 -0400
+Subject: 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 <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+
+Patch-Name: efinet-set-network-from-uefi-devpath.patch
+---
+ grub-core/net/drivers/efi/efinet.c | 268 ++++++++++++++++++++++++++++-
+ include/grub/efi/api.h | 11 ++
+ 2 files changed, 270 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index fc90415f2..2d3b00f0e 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -23,6 +23,7 @@
+ #include <grub/efi/api.h>
+ #include <grub/efi/efi.h>
+ #include <grub/i18n.h>
++#include <grub/net/netbuff.h>
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+@@ -324,6 +325,221 @@ grub_efinet_findcards (void)
+ grub_free (handles);
+ }
+
++static struct grub_net_buff *
++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
++{
++ grub_efi_uint16_t uri_len;
++ grub_efi_device_path_t *ldp, *ddp;
++ grub_efi_uri_device_path_t *uri_dp;
++ struct grub_net_buff *nb;
++ grub_err_t err;
++
++ ddp = grub_efi_duplicate_device_path (dp);
++ ldp = grub_efi_find_last_device_path (ddp);
++
++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++ {
++ grub_free (ddp);
++ return NULL;
++ }
++
++ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0;
++
++ if (!uri_len)
++ {
++ grub_free (ddp);
++ return NULL;
++ }
++
++ uri_dp = (grub_efi_uri_device_path_t *) ldp;
++
++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++ ldp->length = sizeof (*ldp);
++
++ ldp = grub_efi_find_last_device_path (ddp);
++
++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++ {
++ grub_free (ddp);
++ return NULL;
++ }
++
++ nb = grub_netbuff_alloc (512);
++ if (!nb)
++ return NULL;
++
++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++ {
++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
++ struct grub_net_bootp_packet *bp;
++ grub_uint8_t *ptr;
++
++ bp = (struct grub_net_bootp_packet *) nb->tail;
++ err = grub_netbuff_put (nb, sizeof (*bp) + 4);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++
++ if (sizeof(bp->boot_file) < uri_len)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len);
++ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip));
++ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip));
++
++ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0;
++ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1;
++ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2;
++ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3;
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr++ = GRUB_NET_BOOTP_NETMASK;
++ *ptr++ = sizeof (ipv4->subnet_mask);
++ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask));
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr++ = GRUB_NET_BOOTP_ROUTER;
++ *ptr++ = sizeof (ipv4->gateway_ip_address);
++ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address));
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER;
++ *ptr++ = sizeof ("HTTPClient") - 1;
++ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, 1);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr = GRUB_NET_BOOTP_END;
++ *use_ipv6 = 0;
++
++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++ ldp->length = sizeof (*ldp);
++ ldp = grub_efi_find_last_device_path (ddp);
++
++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
++ {
++ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp;
++ bp->hw_type = mac->if_type;
++ bp->hw_len = sizeof (bp->mac_addr);
++ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len);
++ }
++ }
++ else
++ {
++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp;
++
++ struct grub_net_dhcp6_packet *d6p;
++ struct grub_net_dhcp6_option *opt;
++ struct grub_net_dhcp6_option_iana *iana;
++ struct grub_net_dhcp6_option_iaaddr *iaaddr;
++
++ d6p = (struct grub_net_dhcp6_packet *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*d6p));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ d6p->message_type = GRUB_NET_DHCP6_REPLY;
++
++ opt = (struct grub_net_dhcp6_option *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*opt));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr));
++
++ err = grub_netbuff_put (nb, sizeof(*iana));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++
++ opt = (struct grub_net_dhcp6_option *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*opt));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
++ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr));
++
++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*iaaddr));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address));
++
++ opt = (struct grub_net_dhcp6_option *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL);
++ opt->len = grub_cpu_to_be16 (uri_len);
++ grub_memcpy (opt->data, uri_dp->uri, uri_len);
++
++ *use_ipv6 = 1;
++ }
++
++ grub_free (ddp);
++ return nb;
++}
++
+ static void
+ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ char **path)
+@@ -340,6 +556,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ grub_efi_device_path_t *cdp;
+ struct grub_efi_pxe *pxe;
+ struct grub_efi_pxe_mode *pxe_mode;
++ grub_uint8_t *packet_buf;
++ grub_size_t packet_bufsz ;
++ int ipv6;
++ struct grub_net_buff *nb = NULL;
++
+ if (card->driver != &efidriver)
+ continue;
+ cdp = grub_efi_get_device_path (card->efi_handle);
+@@ -359,11 +580,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ ldp = grub_efi_find_last_device_path (dp);
+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ continue;
+ dup_dp = grub_efi_duplicate_device_path (dp);
+ if (!dup_dp)
+ continue;
++
++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++ {
++ dup_ldp = grub_efi_find_last_device_path (dup_dp);
++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++ dup_ldp->length = sizeof (*dup_ldp);
++ }
++
+ dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+@@ -375,16 +606,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ }
+ pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+- if (! pxe)
+- continue;
+- pxe_mode = pxe->mode;
++ if (!pxe)
++ {
++ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6);
++ if (!nb)
++ {
++ grub_print_error ();
++ continue;
++ }
++ packet_buf = nb->head;
++ packet_bufsz = nb->tail - nb->head;
++ }
++ else
++ {
++ pxe_mode = pxe->mode;
++ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack;
++ packet_bufsz = sizeof (pxe_mode->dhcp_ack);
++ ipv6 = pxe_mode->using_ipv6;
++ }
+
+- if (pxe_mode->using_ipv6)
++ if (ipv6)
+ {
+ grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
+ (struct grub_net_dhcp6_packet *)
+- &pxe_mode->dhcp_ack,
+- sizeof (pxe_mode->dhcp_ack),
++ packet_buf,
++ packet_bufsz,
+ 1, device, path);
+ if (grub_errno)
+ grub_print_error ();
+@@ -393,10 +639,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ {
+ grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ (struct grub_net_bootp_packet *)
+- &pxe_mode->dhcp_ack,
+- sizeof (pxe_mode->dhcp_ack),
++ packet_buf,
++ packet_bufsz,
+ 1, device, path);
+ }
++
++ if (nb)
++ grub_netbuff_free (nb);
++
+ return;
+ }
+ }
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 50ab8e844..4b4652ca5 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -849,6 +849,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;
+
+@@ -903,6 +905,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/debian/patches/efinet-uefi-ipv6-pxe-support.patch b/debian/patches/efinet-uefi-ipv6-pxe-support.patch
new file mode 100644
index 0000000..3a75beb
--- /dev/null
+++ b/debian/patches/efinet-uefi-ipv6-pxe-support.patch
@@ -0,0 +1,126 @@
+From a124f295433d6d3f371730b93d6468e6d5ad58e1 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 27 Oct 2016 17:41:21 -0400
+Subject: 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 <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+
+Patch-Name: efinet-uefi-ipv6-pxe-support.patch
+---
+ grub-core/net/drivers/efi/efinet.c | 24 ++++++++++---
+ include/grub/efi/api.h | 55 +++++++++++++++++++++++++++++-
+ 2 files changed, 73 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 5388f952b..fc90415f2 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -378,11 +378,25 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ if (! pxe)
+ continue;
+ pxe_mode = pxe->mode;
+- grub_net_configure_by_dhcp_ack (card->name, card, 0,
+- (struct grub_net_bootp_packet *)
+- &pxe_mode->dhcp_ack,
+- sizeof (pxe_mode->dhcp_ack),
+- 1, device, path);
++
++ if (pxe_mode->using_ipv6)
++ {
++ grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
++ (struct grub_net_dhcp6_packet *)
++ &pxe_mode->dhcp_ack,
++ sizeof (pxe_mode->dhcp_ack),
++ 1, device, path);
++ if (grub_errno)
++ grub_print_error ();
++ }
++ else
++ {
++ grub_net_configure_by_dhcp_ack (card->name, card, 0,
++ (struct grub_net_bootp_packet *)
++ &pxe_mode->dhcp_ack,
++ sizeof (pxe_mode->dhcp_ack),
++ 1, device, path);
++ }
+ return;
+ }
+ }
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index f1a52210c..50ab8e844 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -1476,14 +1476,67 @@ typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output
+
+ typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
+
++typedef struct {
++ grub_uint8_t addr[4];
++} grub_efi_pxe_ipv4_address_t;
++
++typedef struct {
++ grub_uint8_t addr[16];
++} grub_efi_pxe_ipv6_address_t;
++
++typedef struct {
++ grub_uint8_t addr[32];
++} grub_efi_pxe_mac_address_t;
++
++typedef union {
++ grub_uint32_t addr[4];
++ grub_efi_pxe_ipv4_address_t v4;
++ grub_efi_pxe_ipv6_address_t v6;
++} grub_efi_pxe_ip_address_t;
++
++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
++typedef struct {
++ grub_uint8_t filters;
++ grub_uint8_t ip_cnt;
++ grub_uint16_t reserved;
++ grub_efi_pxe_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT];
++} grub_efi_pxe_ip_filter_t;
++
++typedef struct {
++ grub_efi_pxe_ip_address_t ip_addr;
++ grub_efi_pxe_mac_address_t mac_addr;
++} grub_efi_pxe_arp_entry_t;
++
++typedef struct {
++ grub_efi_pxe_ip_address_t ip_addr;
++ grub_efi_pxe_ip_address_t subnet_mask;
++ grub_efi_pxe_ip_address_t gw_addr;
++} grub_efi_pxe_route_entry_t;
++
++
++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8
++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8
++
+ typedef struct grub_efi_pxe_mode
+ {
+- grub_uint8_t unused[52];
++ grub_uint8_t started;
++ grub_uint8_t ipv6_available;
++ grub_uint8_t ipv6_supported;
++ grub_uint8_t using_ipv6;
++ grub_uint8_t unused[16];
++ grub_efi_pxe_ip_address_t station_ip;
++ grub_efi_pxe_ip_address_t subnet_mask;
+ grub_efi_pxe_packet_t dhcp_discover;
+ grub_efi_pxe_packet_t dhcp_ack;
+ grub_efi_pxe_packet_t proxy_offer;
+ grub_efi_pxe_packet_t pxe_discover;
+ grub_efi_pxe_packet_t pxe_reply;
++ grub_efi_pxe_packet_t pxe_bis_reply;
++ grub_efi_pxe_ip_filter_t ip_filter;
++ grub_uint32_t arp_cache_entries;
++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES];
++ grub_uint32_t route_table_entries;
++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES];
+ } grub_efi_pxe_mode_t;
+
+ typedef struct grub_efi_pxe
diff --git a/debian/patches/fix-lockdown.patch b/debian/patches/fix-lockdown.patch
new file mode 100644
index 0000000..54a7928
--- /dev/null
+++ b/debian/patches/fix-lockdown.patch
@@ -0,0 +1,45 @@
+From b2c4515a832f82a4fe4ee8d32faa16b48de63d12 Mon Sep 17 00:00:00 2001
+From: Luca Boccassi <bluca@debian.org>
+Date: Tue, 15 May 2018 11:36:46 +0100
+Subject: Do not overwrite sentinel byte in boot_params, breaks lockdown
+
+grub currently copies the entire boot_params, which includes setting
+sentinel byte to 0xff, which triggers sanitize_boot_params in the kernel
+which in turn clears various boot_params variables, including the
+indication that the bootloader chain is verified and thus the kernel
+disables lockdown mode. According to the information on the Fedora bug
+tracker, only the information from byte 0x1f1 is necessary, so start
+copying from there instead.
+
+Author: Luca Boccassi <bluca@debian.org>
+Bug-Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=1418360
+Forwarded: no
+
+Patch-Name: fix-lockdown.patch
+---
+ grub-core/loader/i386/efi/linux.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 45b68c05a..532e4e512 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -29,6 +29,7 @@
+ #include <grub/linux.h>
+ #include <grub/efi/efi.h>
+ #include <grub/efi/sb.h>
++#include <stddef.h>
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+@@ -336,7 +337,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
+ }
+
+- grub_memcpy (params, &lh, 2 * 512);
++ /* do not overwrite below boot_params->hdr to avoid setting the sentinel byte */
++ start = offsetof (struct linux_kernel_params, setup_sects);
++ grub_memcpy ((grub_uint8_t *)params + start, (grub_uint8_t *)&lh + start, 2 * 512 - start);
+
+ params->type_of_loader = 0x21;
+
diff --git a/debian/patches/font-Try-opening-fonts-from-the-bundled-memdisk.patch b/debian/patches/font-Try-opening-fonts-from-the-bundled-memdisk.patch
new file mode 100644
index 0000000..7c9209a
--- /dev/null
+++ b/debian/patches/font-Try-opening-fonts-from-the-bundled-memdisk.patch
@@ -0,0 +1,76 @@
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Wed, 16 Nov 2022 14:40:04 +0000
+Subject: font: Try opening fonts from the bundled memdisk
+
+---
+ grub-core/font/font.c | 48 +++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 31 insertions(+), 17 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index e6616e6..e421d1a 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -409,6 +409,27 @@ read_section_as_short (struct font_file_section *section,
+ return 0;
+ }
+
++static grub_file_t
++try_open_from_prefix (const char *prefix, const char *filename)
++{
++ grub_file_t file;
++ char *fullname, *ptr;
++
++ fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1
++ + sizeof ("/fonts/") + sizeof (".pf2"));
++ if (!fullname)
++ return 0;
++ ptr = grub_stpcpy (fullname, prefix);
++ ptr = grub_stpcpy (ptr, "/fonts/");
++ ptr = grub_stpcpy (ptr, filename);
++ ptr = grub_stpcpy (ptr, ".pf2");
++ *ptr = 0;
++
++ file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024);
++ grub_free (fullname);
++ return file;
++}
++
+ /* Load a font and add it to the beginning of the global font list.
+ Returns 0 upon success, nonzero upon failure. */
+ grub_font_t
+@@ -427,25 +448,18 @@ grub_font_load (const char *filename)
+ file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024);
+ else
+ {
+- const char *prefix = grub_env_get ("prefix");
+- char *fullname, *ptr;
+- if (!prefix)
++ file = try_open_from_prefix ("(memdisk)", filename);
++ if (!file)
+ {
+- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"),
+- "prefix");
+- goto fail;
++ const char *prefix = grub_env_get ("prefix");
++ if (!prefix)
++ {
++ grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"),
++ "prefix");
++ goto fail;
++ }
++ file = try_open_from_prefix (prefix, filename);
+ }
+- fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1
+- + sizeof ("/fonts/") + sizeof (".pf2"));
+- if (!fullname)
+- goto fail;
+- ptr = grub_stpcpy (fullname, prefix);
+- ptr = grub_stpcpy (ptr, "/fonts/");
+- ptr = grub_stpcpy (ptr, filename);
+- ptr = grub_stpcpy (ptr, ".pf2");
+- *ptr = 0;
+- file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024);
+- grub_free (fullname);
+ }
+ if (!file)
+ goto fail;
diff --git a/debian/patches/fs-tester-time-fail.patch b/debian/patches/fs-tester-time-fail.patch
new file mode 100644
index 0000000..43675db
--- /dev/null
+++ b/debian/patches/fs-tester-time-fail.patch
@@ -0,0 +1,27 @@
+Explicitly unset SOURCE_DATE_EPOCH before running fs tests. In some
+filesystem utils like mksquashfs, it will silently change behaviour
+and cause timestamps to unexpectedly change. Reproducible builds are
+good and useful for shipped artifacts, but this causes build-time
+tests to fail.
+
+Author: Steve McIntyre
+
+Patch-Name: fs-tester-time-fail.patch
+---
+ tests/util/grub-fs-tester.in | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tests/util/grub-fs-tester.in b/tests/util/grub-fs-tester.in
+index bfc425e1f..660691302 100644
+--- a/tests/util/grub-fs-tester.in
++++ b/tests/util/grub-fs-tester.in
+@@ -4,6 +4,9 @@ set -e
+
+ fs="$1"
+
++# We can't have this set, or filesystem tests will fail
++unset SOURCE_DATE_EPOCH
++
+ GRUBFSTEST="@builddir@/grub-fstest"
+
+ tempdir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1
diff --git a/debian/patches/gcc12_build_array_bounds.patch b/debian/patches/gcc12_build_array_bounds.patch
new file mode 100644
index 0000000..c28bcb6
--- /dev/null
+++ b/debian/patches/gcc12_build_array_bounds.patch
@@ -0,0 +1,493 @@
+Borrowed and tweaked fix from:
+
+commit acffb81485e35e1f28152949a1c6e1d4dbf5172e
+Author: Michael Chang <mchang@suse.com>
+Date: Mon Mar 28 15:00:53 2022 +0800
+
+build: Fix -Werror=array-bounds array subscript 0 is outside array bounds
+
+diff --git a/grub-core/bus/cs5536.c b/grub-core/bus/cs5536.c
+index 8c90ed598..cd0a45e58 100644
+--- a/grub-core/bus/cs5536.c
++++ b/grub-core/bus/cs5536.c
+@@ -331,8 +331,9 @@ grub_cs5536_init_geode (grub_pci_device_t dev)
+
+ {
+ volatile grub_uint32_t *oc;
+- oc = grub_pci_device_map_range (dev, 0x05022000,
+- GRUB_CS5536_USB_OPTION_REGS_SIZE);
++
++ oc = grub_absolute_pointer (grub_pci_device_map_range (dev, 0x05022000,
++ GRUB_CS5536_USB_OPTION_REGS_SIZE));
+
+ oc[GRUB_CS5536_USB_OPTION_REG_UOCMUX] =
+ (oc[GRUB_CS5536_USB_OPTION_REG_UOCMUX]
+diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c
+index 1215f2a62..fda62f4ea 100644
+--- a/grub-core/commands/acpi.c
++++ b/grub-core/commands/acpi.c
+@@ -168,7 +168,7 @@ grub_acpi_create_ebda (void)
+ struct grub_acpi_rsdp_v10 *v1;
+ struct grub_acpi_rsdp_v20 *v2;
+
+- ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *)0x40e)) << 4);
++ ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *) grub_absolute_pointer (0x40e))) << 4);
+ grub_dprintf ("acpi", "EBDA @%p\n", ebda);
+ if (ebda)
+ ebda_kb_len = *(grub_uint16_t *) ebda;
+@@ -298,7 +298,7 @@ grub_acpi_create_ebda (void)
+ *target = 0;
+
+ grub_dprintf ("acpi", "Switching EBDA\n");
+- (*((grub_uint16_t *) 0x40e)) = ((grub_addr_t) targetebda) >> 4;
++ (*((grub_uint16_t *) grub_absolute_pointer (0x40e))) = ((grub_addr_t) targetebda) >> 4;
+ grub_dprintf ("acpi", "EBDA switched\n");
+
+ return GRUB_ERR_NONE;
+diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c
+index 5c7725f8b..574e41046 100644
+--- a/grub-core/commands/efi/loadbios.c
++++ b/grub-core/commands/efi/loadbios.c
+@@ -46,7 +46,7 @@ enable_rom_area (void)
+ grub_uint32_t *rom_ptr;
+ grub_pci_device_t dev = { .bus = 0, .device = 0, .function = 0};
+
+- rom_ptr = (grub_uint32_t *) VBIOS_ADDR;
++ rom_ptr = grub_absolute_pointer (VBIOS_ADDR);
+ if (*rom_ptr != BLANK_MEM)
+ {
+ grub_puts_ (N_("ROM image is present."));
+@@ -96,8 +96,8 @@ fake_bios_data (int use_rom)
+ void *acpi, *smbios;
+ grub_uint16_t *ebda_seg_ptr, *low_mem_ptr;
+
+- ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR;
+- low_mem_ptr = (grub_uint16_t *) LOW_MEM_ADDR;
++ ebda_seg_ptr = grub_absolute_pointer (EBDA_SEG_ADDR);
++ low_mem_ptr = grub_absolute_pointer (LOW_MEM_ADDR);
+ if ((*ebda_seg_ptr) || (*low_mem_ptr))
+ return;
+
+@@ -132,7 +132,8 @@ fake_bios_data (int use_rom)
+ *ebda_seg_ptr = FAKE_EBDA_SEG;
+ *low_mem_ptr = (FAKE_EBDA_SEG >> 6);
+
+- *((grub_uint16_t *) (FAKE_EBDA_SEG << 4)) = 640 - *low_mem_ptr;
++ /* *((grub_uint16_t *) (FAKE_EBDA_SEG << 4)) = 640 - *low_mem_ptr; */
++ *((grub_uint16_t *) (grub_absolute_pointer (FAKE_EBDA_SEG << 4))) = 640 - *low_mem_ptr;
+
+ if (acpi)
+ grub_memcpy ((char *) ((FAKE_EBDA_SEG << 4) + 16), acpi, 1024 - 16);
+diff --git a/grub-core/commands/i386/pc/drivemap.c b/grub-core/commands/i386/pc/drivemap.c
+index 3fb22dc46..a7ee4c9bd 100644
+--- a/grub-core/commands/i386/pc/drivemap.c
++++ b/grub-core/commands/i386/pc/drivemap.c
+@@ -31,9 +31,6 @@
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+-/* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */
+-static grub_uint32_t *const int13slot = (grub_uint32_t *) (4 * 0x13);
+-
+ /* Remember to update enum opt_idxs accordingly. */
+ static const struct grub_arg_option options[] = {
+ /* TRANSLATORS: In this file "mapping" refers to a change GRUB makes so if
+@@ -280,6 +277,8 @@ install_int13_handler (int noret __attribute__ ((unused)))
+ grub_uint8_t *handler_base = 0;
+ /* Address of the map within the deployed bundle. */
+ int13map_node_t *handler_map;
++ /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */
++ grub_uint32_t *int13slot = (grub_uint32_t *) grub_absolute_pointer (4 * 0x13);
+
+ int i;
+ int entries = 0;
+@@ -354,6 +353,9 @@ install_int13_handler (int noret __attribute__ ((unused)))
+ static grub_err_t
+ uninstall_int13_handler (void)
+ {
++ /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */
++ grub_uint32_t *int13slot = (grub_uint32_t *) grub_absolute_pointer (4 * 0x13);
++
+ if (! grub_drivemap_oldhandler)
+ return GRUB_ERR_NONE;
+
+diff --git a/grub-core/disk/i386/pc/biosdisk.c b/grub-core/disk/i386/pc/biosdisk.c
+index 81fd4e832..49e4e8a14 100644
+--- a/grub-core/disk/i386/pc/biosdisk.c
++++ b/grub-core/disk/i386/pc/biosdisk.c
+@@ -367,7 +367,7 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
+ if (version)
+ {
+ struct grub_biosdisk_drp *drp
+- = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ = (struct grub_biosdisk_drp *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+
+ /* Clear out the DRP. */
+ grub_memset (drp, 0, sizeof (*drp));
+@@ -654,7 +654,7 @@ grub_disk_biosdisk_fini (void)
+ GRUB_MOD_INIT(biosdisk)
+ {
+ struct grub_biosdisk_cdrp *cdrp
+- = (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ = (struct grub_biosdisk_cdrp *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ grub_uint8_t boot_drive;
+
+ if (grub_disk_firmware_is_tainted)
+diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c
+index 581215ef1..8ab7106af 100644
+--- a/grub-core/fs/cbfs.c
++++ b/grub-core/fs/cbfs.c
+@@ -342,7 +342,7 @@ init_cbfsdisk (void)
+ grub_uint32_t ptr;
+ struct cbfs_header *head;
+
+- ptr = *(grub_uint32_t *) 0xfffffffc;
++ ptr = *((grub_uint32_t *) grub_absolute_pointer (0xfffffffc));
+ head = (struct cbfs_header *) (grub_addr_t) ptr;
+ grub_dprintf ("cbfs", "head=%p\n", head);
+
+diff --git a/grub-core/kern/i386/pc/acpi.c b/grub-core/kern/i386/pc/acpi.c
+index 297f5d05f..0a69eba7b 100644
+--- a/grub-core/kern/i386/pc/acpi.c
++++ b/grub-core/kern/i386/pc/acpi.c
+@@ -27,7 +27,7 @@ grub_machine_acpi_get_rsdpv1 (void)
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+- ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
++ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) grub_absolute_pointer (0x40e))) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len) /* FIXME do we really need this check? */
+ goto scan_bios;
+@@ -55,7 +55,7 @@ grub_machine_acpi_get_rsdpv2 (void)
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+- ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
++ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) grub_absolute_pointer (0x40e))) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len) /* FIXME do we really need this check? */
+ goto scan_bios;
+diff --git a/grub-core/kern/i386/pc/mmap.c b/grub-core/kern/i386/pc/mmap.c
+index ef2faa2ab..53fcf45af 100644
+--- a/grub-core/kern/i386/pc/mmap.c
++++ b/grub-core/kern/i386/pc/mmap.c
+@@ -143,7 +143,7 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
+ {
+ grub_uint32_t cont = 0;
+ struct grub_machine_mmap_entry *entry
+- = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ = (struct grub_machine_mmap_entry *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ int e820_works = 0;
+
+ while (1)
+diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
+index 6d680d671..00a48413c 100644
+--- a/grub-core/loader/multiboot_mbi2.c
++++ b/grub-core/loader/multiboot_mbi2.c
+@@ -504,7 +504,7 @@ static void
+ fill_vbe_tag (struct multiboot_tag_vbe *tag)
+ {
+ grub_vbe_status_t status;
+- void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ void *scratch = grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+
+ tag->type = MULTIBOOT_TAG_TYPE_VBE;
+ tag->size = 0;
+@@ -577,7 +577,7 @@ retrieve_video_parameters (grub_properly_aligned_t **ptrorig)
+ #if defined (GRUB_MACHINE_PCBIOS)
+ {
+ grub_vbe_status_t status;
+- void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ void *scratch = grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ status = grub_vbe_bios_get_mode (scratch);
+ vbe_mode = *(grub_uint32_t *) scratch;
+ if (status != GRUB_VBE_STATUS_OK)
+diff --git a/grub-core/mmap/i386/pc/mmap.c b/grub-core/mmap/i386/pc/mmap.c
+index 6ab4f6730..b9c5b0a00 100644
+--- a/grub-core/mmap/i386/pc/mmap.c
++++ b/grub-core/mmap/i386/pc/mmap.c
+@@ -80,13 +80,13 @@ preboot (int noreturn __attribute__ ((unused)))
+ = min (grub_mmap_get_post64 (), 0xfc000000ULL) >> 16;
+
+ /* Correct BDA. */
+- *((grub_uint16_t *) 0x413) = grub_mmap_get_lower () >> 10;
++ *((grub_uint16_t *) grub_absolute_pointer (0x413)) = grub_mmap_get_lower () >> 10;
+
+ /* Save old interrupt handlers. */
+- grub_machine_mmaphook_int12offset = *((grub_uint16_t *) 0x48);
+- grub_machine_mmaphook_int12segment = *((grub_uint16_t *) 0x4a);
+- grub_machine_mmaphook_int15offset = *((grub_uint16_t *) 0x54);
+- grub_machine_mmaphook_int15segment = *((grub_uint16_t *) 0x56);
++ grub_machine_mmaphook_int12offset = *((grub_uint16_t *) grub_absolute_pointer (0x48));
++ grub_machine_mmaphook_int12segment = *((grub_uint16_t *) grub_absolute_pointer (0x4a));
++ grub_machine_mmaphook_int15offset = *((grub_uint16_t *) grub_absolute_pointer (0x54));
++ grub_machine_mmaphook_int15segment = *((grub_uint16_t *) grub_absolute_pointer (0x56));
+
+ grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
+
+@@ -94,11 +94,11 @@ preboot (int noreturn __attribute__ ((unused)))
+ grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
+ &grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
+
+- *((grub_uint16_t *) 0x4a) = ((grub_addr_t) hooktarget) >> 4;
+- *((grub_uint16_t *) 0x56) = ((grub_addr_t) hooktarget) >> 4;
+- *((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12
++ *((grub_uint16_t *) grub_absolute_pointer (0x4a)) = ((grub_addr_t) hooktarget) >> 4;
++ *((grub_uint16_t *) grub_absolute_pointer (0x56)) = ((grub_addr_t) hooktarget) >> 4;
++ *((grub_uint16_t *) grub_absolute_pointer (0x48)) = &grub_machine_mmaphook_int12
+ - &grub_machine_mmaphook_start;
+- *((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15
++ *((grub_uint16_t *) grub_absolute_pointer (0x54)) = &grub_machine_mmaphook_int15
+ - &grub_machine_mmaphook_start;
+
+ return GRUB_ERR_NONE;
+@@ -108,10 +108,10 @@ static grub_err_t
+ preboot_rest (void)
+ {
+ /* Restore old interrupt handlers. */
+- *((grub_uint16_t *) 0x48) = grub_machine_mmaphook_int12offset;
+- *((grub_uint16_t *) 0x4a) = grub_machine_mmaphook_int12segment;
+- *((grub_uint16_t *) 0x54) = grub_machine_mmaphook_int15offset;
+- *((grub_uint16_t *) 0x56) = grub_machine_mmaphook_int15segment;
++ *((grub_uint16_t *) grub_absolute_pointer (0x48)) = grub_machine_mmaphook_int12offset;
++ *((grub_uint16_t *) grub_absolute_pointer (0x4a)) = grub_machine_mmaphook_int12segment;
++ *((grub_uint16_t *) grub_absolute_pointer (0x54)) = grub_machine_mmaphook_int15offset;
++ *((grub_uint16_t *) grub_absolute_pointer (0x56)) = grub_machine_mmaphook_int15segment;
+
+ return GRUB_ERR_NONE;
+ }
+diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c
+index 997010cf1..db17186ee 100644
+--- a/grub-core/net/drivers/i386/pc/pxe.c
++++ b/grub-core/net/drivers/i386/pc/pxe.c
+@@ -174,7 +174,7 @@ grub_pxe_recv (struct grub_net_card *dev __attribute__ ((unused)))
+ grub_uint8_t *ptr, *end;
+ struct grub_net_buff *buf;
+
+- isr = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ isr = (void *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+
+ if (!in_progress)
+ {
+@@ -256,11 +256,11 @@ grub_pxe_send (struct grub_net_card *dev __attribute__ ((unused)),
+ struct grub_pxe_undi_tbd *tbd;
+ char *buf;
+
+- trans = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ trans = (void *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ grub_memset (trans, 0, sizeof (*trans));
+- tbd = (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 128);
++ tbd = (void *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 128);
+ grub_memset (tbd, 0, sizeof (*tbd));
+- buf = (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 256);
++ buf = (void *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 256);
+ grub_memcpy (buf, pack->data, pack->tail - pack->data);
+
+ trans->tbd = SEGOFS ((grub_addr_t) tbd);
+@@ -287,7 +287,7 @@ static grub_err_t
+ grub_pxe_open (struct grub_net_card *dev __attribute__ ((unused)))
+ {
+ struct grub_pxe_undi_open *ou;
+- ou = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ ou = (void *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ grub_memset (ou, 0, sizeof (*ou));
+ ou->pkt_filter = 4;
+ grub_pxe_call (GRUB_PXENV_UNDI_OPEN, ou, pxe_rm_entry);
+@@ -382,7 +382,7 @@ GRUB_MOD_INIT(pxe)
+ if (! pxenv)
+ return;
+
+- ui = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ ui = (void *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ grub_memset (ui, 0, sizeof (*ui));
+ grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry);
+
+diff --git a/grub-core/term/i386/pc/console.c b/grub-core/term/i386/pc/console.c
+index d44937c30..9403390f1 100644
+--- a/grub-core/term/i386/pc/console.c
++++ b/grub-core/term/i386/pc/console.c
+@@ -238,12 +238,11 @@ grub_console_getkey (struct grub_term_input *term __attribute__ ((unused)))
+ return (regs.eax & 0xff) + (('a' - 1) | GRUB_TERM_CTRL);
+ }
+
+-static const struct grub_machine_bios_data_area *bios_data_area =
+- (struct grub_machine_bios_data_area *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
+-
+ static int
+ grub_console_getkeystatus (struct grub_term_input *term __attribute__ ((unused)))
+ {
++ const struct grub_machine_bios_data_area *bios_data_area =
++ (struct grub_machine_bios_data_area *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR);
+ /* conveniently GRUB keystatus is modelled after BIOS one. */
+ return bios_data_area->keyboard_flag_lower & ~0x80;
+ }
+diff --git a/grub-core/term/i386/pc/vga_text.c b/grub-core/term/i386/pc/vga_text.c
+index 88fecc5ea..669d06fad 100644
+--- a/grub-core/term/i386/pc/vga_text.c
++++ b/grub-core/term/i386/pc/vga_text.c
+@@ -45,15 +45,15 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ static struct grub_term_coordinate grub_curr_pos;
+
+ #ifdef __mips__
+-#define VGA_TEXT_SCREEN ((grub_uint16_t *) 0xb00b8000)
++#define VGA_TEXT_SCREEN ((grub_uint16_t *) grub_absolute_pointer (0xb00b8000))
+ #define cr_read grub_vga_cr_read
+ #define cr_write grub_vga_cr_write
+ #elif defined (MODE_MDA)
+-#define VGA_TEXT_SCREEN ((grub_uint16_t *) 0xb0000)
++#define VGA_TEXT_SCREEN ((grub_uint16_t *) grub_absolute_pointer (0xb0000))
+ #define cr_read grub_vga_cr_bw_read
+ #define cr_write grub_vga_cr_bw_write
+ #else
+-#define VGA_TEXT_SCREEN ((grub_uint16_t *) 0xb8000)
++#define VGA_TEXT_SCREEN ((grub_uint16_t *) grub_absolute_pointer (0xb8000))
+ #define cr_read grub_vga_cr_read
+ #define cr_write grub_vga_cr_write
+ #endif
+diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c
+index 59801839b..83b25990c 100644
+--- a/grub-core/term/ns8250.c
++++ b/grub-core/term/ns8250.c
+@@ -28,7 +28,6 @@
+
+ #ifdef GRUB_MACHINE_PCBIOS
+ #include <grub/machine/memory.h>
+-static const unsigned short *serial_hw_io_addr = (const unsigned short *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
+ #define GRUB_SERIAL_PORT_NUM 4
+ #else
+ #include <grub/machine/serial.h>
+@@ -237,6 +236,9 @@ static struct grub_serial_port com_ports[GRUB_SERIAL_PORT_NUM];
+ void
+ grub_ns8250_init (void)
+ {
++#ifdef GRUB_MACHINE_PCBIOS
++ const unsigned short *serial_hw_io_addr = (const unsigned short *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR);
++#endif
+ unsigned i;
+ for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++)
+ if (serial_hw_io_addr[i])
+@@ -272,6 +274,9 @@ grub_ns8250_init (void)
+ grub_port_t
+ grub_ns8250_hw_get_port (const unsigned int unit)
+ {
++#ifdef GRUB_MACHINE_PCBIOS
++ const unsigned short *serial_hw_io_addr = (const unsigned short *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR);
++#endif
+ if (unit < GRUB_SERIAL_PORT_NUM
+ && !(dead_ports & (1 << unit)))
+ return serial_hw_io_addr[unit];
+diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c
+index 0e65b5206..a0bb9af09 100644
+--- a/grub-core/video/i386/pc/vbe.c
++++ b/grub-core/video/i386/pc/vbe.c
+@@ -514,7 +514,7 @@ grub_vbe_probe (struct grub_vbe_info_block *info_block)
+
+ /* Use low memory scratch area as temporary storage
+ for VESA BIOS call. */
+- vbe_ib = (struct grub_vbe_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ vbe_ib = (struct grub_vbe_info_block *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+
+ /* Prepare info block. */
+ grub_memset (vbe_ib, 0, sizeof (*vbe_ib));
+@@ -574,7 +574,7 @@ grub_vbe_get_preferred_mode (unsigned int *width, unsigned int *height)
+
+ /* Use low memory scratch area as temporary storage for VESA BIOS calls. */
+ flat_panel_info = (struct grub_vbe_flat_panel_info *)
+- (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + sizeof (struct grub_video_edid_info));
++ grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + sizeof (struct grub_video_edid_info));
+
+ if (controller_info.version >= 0x200
+ && (grub_vbe_bios_get_ddc_capabilities (&ddc_level) & 0xff)
+@@ -676,7 +676,7 @@ grub_vbe_set_video_mode (grub_uint32_t vbe_mode,
+ == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)
+ {
+ struct grub_vbe_palette_data *palette
+- = (struct grub_vbe_palette_data *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ = (struct grub_vbe_palette_data *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ unsigned i;
+
+ /* Make sure that the BIOS can reach the palette. */
+diff --git a/include/grub/types.h b/include/grub/types.h
+index 0a3ff1591..5ae0ced38 100644
+--- a/include/grub/types.h
++++ b/include/grub/types.h
+@@ -340,4 +340,28 @@ static inline void grub_set_unaligned64 (void *ptr, grub_uint64_t val)
+ dd->d = val;
+ }
+
++/*
++ * The grub_absolute_pointer() macro borrows the idea from Linux kernel of using
++ * RELOC_HIDE() macro to stop GCC from checking the result of pointer arithmetic
++ * and also it's conversion to be inside the symbol's boundary [1]. The check
++ * is sometimes false positive, especially it is controversial to emit the array
++ * bounds [-Warray-bounds] warning on all hardwired literal pointers since GCC
++ * 11/12 [2]. Unless a good solution can be settled, for the time being we
++ * would be in favor of the macro instead of GCC pragmas which cannot match the
++ * places the warning needs to be ignored in an exact way.
++ *
++ * [1] https://lists.linuxcoding.com/kernel/2006-q3/msg17979.html
++ * [2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578
++ */
++#if defined(__GNUC__)
++# define grub_absolute_pointer(val) \
++({ \
++ grub_addr_t __ptr; \
++ asm ("" : "=r" (__ptr) : "0" ((void *) (val))); \
++ (void *) (__ptr); \
++})
++#else
++# define grub_absolute_pointer(val) ((void *) (val))
++#endif
++
+ #endif /* ! GRUB_TYPES_HEADER */
+diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
+index a67d9d0a8..434e694ff 100644
+--- a/grub-core/loader/i386/multiboot_mbi.c
++++ b/grub-core/loader/i386/multiboot_mbi.c
+@@ -293,7 +293,7 @@ fill_vbe_info (struct multiboot_info *mbi, grub_uint8_t *ptrorig,
+ struct grub_vbe_mode_info_block *mode_info;
+ #if GRUB_MACHINE_HAS_VBE
+ grub_vbe_status_t status;
+- void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
++ void *scratch = grub_absolute_pointer (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+
+ status = grub_vbe_bios_get_controller_info (scratch);
+ if (status != GRUB_VBE_STATUS_OK)
+diff --git a/grub-core/commands/i386/pc/sendkey.c b/grub-core/commands/i386/pc/sendkey.c
+index 26d9acd3d..9fbd8cb2c 100644
+--- a/grub-core/commands/i386/pc/sendkey.c
++++ b/grub-core/commands/i386/pc/sendkey.c
+@@ -216,12 +216,12 @@ static grub_err_t
+ grub_sendkey_postboot (void)
+ {
+ /* For convention: pointer to flags. */
+- grub_uint32_t *flags = (grub_uint32_t *) 0x417;
++ grub_uint32_t *flags = grub_absolute_pointer (0x417);
+
+ *flags = oldflags;
+
+- *((char *) 0x41a) = 0x1e;
+- *((char *) 0x41c) = 0x1e;
++ *((volatile char *) grub_absolute_pointer (0x41a)) = 0x1e;
++ *((volatile char *) grub_absolute_pointer (0x41c)) = 0x1e;
+
+ return GRUB_ERR_NONE;
+ }
+@@ -231,13 +231,13 @@ static grub_err_t
+ grub_sendkey_preboot (int noret __attribute__ ((unused)))
+ {
+ /* For convention: pointer to flags. */
+- grub_uint32_t *flags = (grub_uint32_t *) 0x417;
++ grub_uint32_t *flags = grub_absolute_pointer (0x417);
+
+ oldflags = *flags;
+
+ /* Set the sendkey. */
+- *((char *) 0x41a) = 0x1e;
+- *((char *) 0x41c) = keylen + 0x1e;
++ *((volatile char *) grub_absolute_pointer (0x41a)) = 0x1e;
++ *((volatile char *) grub_absolute_pointer (0x41c)) = keylen + 0x1e;
+ grub_memcpy ((char *) 0x41e, sendkey, 0x20);
+
+ /* Transform "any ctrl" to "right ctrl" flag. */
diff --git a/debian/patches/gcc12_build_array_bounds2.patch b/debian/patches/gcc12_build_array_bounds2.patch
new file mode 100644
index 0000000..6036eba
--- /dev/null
+++ b/debian/patches/gcc12_build_array_bounds2.patch
@@ -0,0 +1,46 @@
+commit 3ce13d974b887338ae972c79b41ff6fc0eee6388
+Author: Michael Chang <mchang@suse.com>
+Date: Mon Mar 28 15:00:54 2022 +0800
+
+ lib/reed_solomon: Fix array subscript 0 is outside array bounds
+
+ The grub_absolute_pointer() is a compound expression that can only work
+ within a function. We are out of luck here when the pointer variables
+ require global definition due to ATTRIBUTE_TEXT that have to use fully
+ initialized global definition because of the way linkers work.
+
+ static gf_single_t * const gf_powx ATTRIBUTE_TEXT = (void *) 0x100000;
+
+ For the reason given above, use GCC diagnostic pragmas to suppress the
+ array-bounds warning.
+
+ Signed-off-by: Michael Chang <mchang@suse.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c
+index 82779a296..562bd2e3e 100644
+--- a/grub-core/lib/reed_solomon.c
++++ b/grub-core/lib/reed_solomon.c
+@@ -102,6 +102,11 @@ static gf_single_t errvals[256];
+ static gf_single_t eqstat[65536 + 256];
+ #endif
+
++#if __GNUC__ == 12
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Warray-bounds"
++#endif
++
+ static gf_single_t
+ gf_mul (gf_single_t a, gf_single_t b)
+ {
+@@ -319,6 +324,10 @@ decode_block (gf_single_t *ptr, grub_size_t s,
+ }
+ }
+
++#if __GNUC__ == 12
++#pragma GCC diagnostic pop
++#endif
++
+ #if !defined (STANDALONE)
+ static void
+ encode_block (gf_single_t *ptr, grub_size_t s,
diff --git a/debian/patches/gcc12_build_dangling_pointer.patch b/debian/patches/gcc12_build_dangling_pointer.patch
new file mode 100644
index 0000000..78bbacb
--- /dev/null
+++ b/debian/patches/gcc12_build_dangling_pointer.patch
@@ -0,0 +1,67 @@
+Borrowed and tweaked fix from:
+
+commit be8eb0eed69f8bc9ac20837eae58e55218011880
+Author: Michael Chang <mchang@suse.com>
+Date: Mon Mar 28 15:00:52 2022 +0800
+
+ util/mkimage: Fix dangling pointer may be used error
+
+diff --git a/util/mkimage.c b/util/mkimage.c
+index a26cf76f7..58c199f7c 100644
+--- a/util/mkimage 2022-12-11 15:41:56.717934782 +0000
++++ b/util/mkimage.c 2022-12-11 15:43:05.318432532 +0000
+@@ -1383,6 +1383,10 @@
+ section = (struct grub_pe32_section_table *)(o64 + 1);
+ }
+
++#if __GNUC__ >= 12
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wdangling-pointer"
++#endif
+ 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;
+@@ -1402,6 +1406,9 @@
+ /* The sections. */
+ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (vma);
+ PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size);
++#if __GNUC__ >= 12
++#pragma GCC diagnostic pop
++#endif
+ section = init_pe_section (image_target, section, ".text",
+ &vma, layout.exec_size,
+ image_target->section_align,
+@@ -1413,10 +1420,17 @@
+ raw_size = layout.kernel_size - layout.exec_size;
+ scn_size = ALIGN_UP (raw_size, GRUB_PE32_FILE_ALIGNMENT);
+ /* ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT) is done earlier. */
++#if __GNUC__ >= 12
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wdangling-pointer"
++#endif
+ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + sbat_size +
+ ALIGN_UP (total_module_size,
+ GRUB_PE32_FILE_ALIGNMENT));
+
++#if __GNUC__ >= 12
++#pragma GCC diagnostic pop
++#endif
+ section = init_pe_section (image_target, section, ".data",
+ &vma, scn_size, image_target->section_align,
+ &raw_data, raw_size,
+@@ -1448,8 +1462,15 @@
+ }
+
+ scn_size = ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT);
++#if __GNUC__ >= 12
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wdangling-pointer"
++#endif
+ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma);
+ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size);
++#if __GNUC__ >= 12
++#pragma GCC diagnostic pop
++#endif
+ memcpy (pe_img + raw_data, layout.reloc_section, scn_size);
+ init_pe_section (image_target, section, ".reloc",
+ &vma, scn_size, image_target->section_align,
diff --git a/debian/patches/gettext-quiet.patch b/debian/patches/gettext-quiet.patch
new file mode 100644
index 0000000..eddcce7
--- /dev/null
+++ b/debian/patches/gettext-quiet.patch
@@ -0,0 +1,30 @@
+From ddc3423d5c2bf1fb83a6f378726ff87b12794d19 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:02 +0000
+Subject: Silence error messages when translations are unavailable
+
+Bug: https://savannah.gnu.org/bugs/?35880
+Forwarded: https://savannah.gnu.org/bugs/?35880
+Last-Update: 2013-11-14
+
+Patch-Name: gettext-quiet.patch
+---
+ grub-core/gettext/gettext.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
+index 4d02e62c1..2a19389f2 100644
+--- a/grub-core/gettext/gettext.c
++++ b/grub-core/gettext/gettext.c
+@@ -427,6 +427,11 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx,
+ if (locale[0] == 'e' && locale[1] == 'n'
+ && (locale[2] == '\0' || locale[2] == '_'))
+ grub_errno = err = GRUB_ERR_NONE;
++
++ /* If no translations are available, fall back to untranslated text. */
++ if (err == GRUB_ERR_FILE_NOT_FOUND)
++ grub_errno = err = GRUB_ERR_NONE;
++
+ return err;
+ }
+
diff --git a/debian/patches/gfxpayload-dynamic.patch b/debian/patches/gfxpayload-dynamic.patch
new file mode 100644
index 0000000..b0a19b3
--- /dev/null
+++ b/debian/patches/gfxpayload-dynamic.patch
@@ -0,0 +1,290 @@
+From bc7f762a1d253537eb524946884b0f3e50a419f0 Mon Sep 17 00:00:00 2001
+From: Evan Broder <evan@ebroder.net>
+Date: Mon, 13 Jan 2014 12:13:29 +0000
+Subject: Add configure option to enable gfxpayload=keep dynamically
+
+Set GRUB_GFXPAYLOAD_LINUX=keep unless it's known to be unsupported on
+the current hardware. See
+https://blueprints.launchpad.net/ubuntu/+spec/packageselection-foundations-n-grub2-boot-framebuffer.
+
+Author: Colin Watson <cjwatson@ubuntu.com>
+Forwarded: no
+Last-Update: 2019-05-25
+
+Patch-Name: gfxpayload-dynamic.patch
+---
+ configure.ac | 11 ++
+ grub-core/Makefile.core.def | 8 ++
+ grub-core/commands/i386/pc/hwmatch.c | 146 +++++++++++++++++++++++++++
+ include/grub/file.h | 1 +
+ util/grub.d/10_linux.in | 37 ++++++-
+ 5 files changed, 200 insertions(+), 3 deletions(-)
+ create mode 100644 grub-core/commands/i386/pc/hwmatch.c
+
+diff --git a/configure.ac b/configure.ac
+index c42e4c784..947fd529f 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1937,6 +1937,17 @@ else
+ fi
+ AC_SUBST([QUICK_BOOT])
+
++AC_ARG_ENABLE([gfxpayload-dynamic],
++ [AS_HELP_STRING([--enable-gfxpayload-dynamic],
++ [use GRUB_GFXPAYLOAD_LINUX=keep unless explicitly unsupported on current hardware (default=no)])],
++ [], [enable_gfxpayload_dynamic=no])
++if test x"$enable_gfxpayload_dynamic" = xyes ; then
++ GFXPAYLOAD_DYNAMIC=1
++else
++ GFXPAYLOAD_DYNAMIC=0
++fi
++AC_SUBST([GFXPAYLOAD_DYNAMIC])
++
+ LIBS=""
+
+ AC_SUBST([FONT_SOURCE])
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index e5b3d27f5..2ff266806 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -964,6 +964,14 @@ module = {
+ common = lib/hexdump.c;
+ };
+
++module = {
++ name = hwmatch;
++ i386_pc = commands/i386/pc/hwmatch.c;
++ enable = i386_pc;
++ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
++};
++
+ module = {
+ name = keystatus;
+ common = commands/keystatus.c;
+diff --git a/grub-core/commands/i386/pc/hwmatch.c b/grub-core/commands/i386/pc/hwmatch.c
+new file mode 100644
+index 000000000..6de07cecc
+--- /dev/null
++++ b/grub-core/commands/i386/pc/hwmatch.c
+@@ -0,0 +1,146 @@
++/* hwmatch.c - Match hardware against a whitelist/blacklist. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2011 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/dl.h>
++#include <grub/misc.h>
++#include <grub/command.h>
++#include <grub/pci.h>
++#include <grub/normal.h>
++#include <grub/file.h>
++#include <grub/env.h>
++#include <grub/i18n.h>
++#include <regex.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++/* Context for grub_cmd_hwmatch. */
++struct hwmatch_ctx
++{
++ grub_file_t matches_file;
++ int class_match;
++ int match;
++};
++
++/* Helper for grub_cmd_hwmatch. */
++static int
++hwmatch_iter (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
++{
++ struct hwmatch_ctx *ctx = data;
++ grub_pci_address_t addr;
++ grub_uint32_t class, baseclass, vendor, device;
++ grub_pci_id_t subpciid;
++ grub_uint32_t subvendor, subdevice, subclass;
++ char *id, *line;
++
++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
++ class = grub_pci_read (addr);
++ baseclass = class >> 24;
++
++ if (ctx->class_match != baseclass)
++ return 0;
++
++ vendor = pciid & 0xffff;
++ device = pciid >> 16;
++
++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_SUBVENDOR);
++ subpciid = grub_pci_read (addr);
++
++ subclass = (class >> 16) & 0xff;
++ subvendor = subpciid & 0xffff;
++ subdevice = subpciid >> 16;
++
++ id = grub_xasprintf ("v%04xd%04xsv%04xsd%04xbc%02xsc%02x",
++ vendor, device, subvendor, subdevice,
++ baseclass, subclass);
++
++ grub_file_seek (ctx->matches_file, 0);
++ while ((line = grub_file_getline (ctx->matches_file)) != NULL)
++ {
++ char *anchored_line;
++ regex_t regex;
++ int ret;
++
++ if (! *line || *line == '#')
++ {
++ grub_free (line);
++ continue;
++ }
++
++ anchored_line = grub_xasprintf ("^%s$", line);
++ ret = regcomp (&regex, anchored_line, REG_EXTENDED | REG_NOSUB);
++ grub_free (anchored_line);
++ if (ret)
++ {
++ grub_free (line);
++ continue;
++ }
++
++ ret = regexec (&regex, id, 0, NULL, 0);
++ regfree (&regex);
++ grub_free (line);
++ if (! ret)
++ {
++ ctx->match = 1;
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++static grub_err_t
++grub_cmd_hwmatch (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char **args)
++{
++ struct hwmatch_ctx ctx = { .match = 0 };
++ char *match_str;
++
++ if (argc < 2)
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "list file and class required");
++
++ ctx.matches_file = grub_file_open (args[0], GRUB_FILE_TYPE_HWMATCH);
++ if (! ctx.matches_file)
++ return grub_errno;
++
++ ctx.class_match = grub_strtol (args[1], 0, 10);
++
++ grub_pci_iterate (hwmatch_iter, &ctx);
++
++ match_str = grub_xasprintf ("%d", ctx.match);
++ grub_env_set ("match", match_str);
++ grub_free (match_str);
++
++ grub_file_close (ctx.matches_file);
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_command_t cmd;
++
++GRUB_MOD_INIT(hwmatch)
++{
++ cmd = grub_register_command ("hwmatch", grub_cmd_hwmatch,
++ N_("MATCHES-FILE CLASS"),
++ N_("Match PCI devices."));
++}
++
++GRUB_MOD_FINI(hwmatch)
++{
++ grub_unregister_command (cmd);
++}
+diff --git a/include/grub/file.h b/include/grub/file.h
+index 31567483c..e3c4cae2b 100644
+--- a/include/grub/file.h
++++ b/include/grub/file.h
+@@ -122,6 +122,7 @@ enum grub_file_type
+ GRUB_FILE_TYPE_FS_SEARCH,
+ GRUB_FILE_TYPE_AUDIO,
+ GRUB_FILE_TYPE_VBE_DUMP,
++ GRUB_FILE_TYPE_HWMATCH,
+
+ GRUB_FILE_TYPE_LOADENV,
+ GRUB_FILE_TYPE_SAVEENV,
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 80315a31b..d46d7852b 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -23,6 +23,7 @@ datarootdir="@datarootdir@"
+ ubuntu_recovery="@UBUNTU_RECOVERY@"
+ quiet_boot="@QUIET_BOOT@"
+ quick_boot="@QUICK_BOOT@"
++gfxpayload_dynamic="@GFXPAYLOAD_DYNAMIC@"
+
+ . "$pkgdatadir/grub-mkconfig_lib"
+
+@@ -145,9 +146,10 @@ linux_entry ()
+ if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
+ echo " load_video" | sed "s/^/$submenu_indentation/"
+ fi
+- if [ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]; then
+- echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
+- fi
++ fi
++ if ([ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]) && \
++ ([ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 1 ]); then
++ echo " set gfxpayload=\$linux_gfx_mode" | sed "s/^/$submenu_indentation/"
+ fi
+
+ echo " insmod gzio" | sed "s/^/$submenu_indentation/"
+@@ -226,6 +228,35 @@ prepare_root_cache=
+ boot_device_id=
+ title_correction_code=
+
++# Use ELILO's generic "efifb" when it's known to be available.
++# FIXME: We need an interface to select vesafb in case efifb can't be used.
++if [ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 0 ]; then
++ echo "set linux_gfx_mode=$GRUB_GFXPAYLOAD_LINUX"
++else
++ cat << EOF
++if [ "\${recordfail}" != 1 ]; then
++ if [ -e \${prefix}/gfxblacklist.txt ]; then
++ if hwmatch \${prefix}/gfxblacklist.txt 3; then
++ if [ \${match} = 0 ]; then
++ set linux_gfx_mode=keep
++ else
++ set linux_gfx_mode=text
++ fi
++ else
++ set linux_gfx_mode=text
++ fi
++ else
++ set linux_gfx_mode=keep
++ fi
++else
++ set linux_gfx_mode=text
++fi
++EOF
++fi
++cat << EOF
++export linux_gfx_mode
++EOF
++
+ # Extra indentation to add to menu entries in a submenu. We're not in a submenu
+ # yet, so it's empty. In a submenu it will be equal to '\t' (one tab).
+ submenu_indentation=""
diff --git a/debian/patches/gfxpayload-keep-default.patch b/debian/patches/gfxpayload-keep-default.patch
new file mode 100644
index 0000000..1308966
--- /dev/null
+++ b/debian/patches/gfxpayload-keep-default.patch
@@ -0,0 +1,39 @@
+From 70a2b23aadd93955a3869aa1c29a7f09c0696b95 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:12:57 +0000
+Subject: Disable gfxpayload=keep by default
+
+Setting gfxpayload=keep has been known to cause efifb to be
+inappropriately enabled. In any case, with the current Linux kernel the
+result of this option is that early kernelspace will be unable to print
+anything to the console, so (for example) if boot fails and you end up
+dumped to an initramfs prompt, you won't be able to see anything on the
+screen. As such it shouldn't be enabled by default in Debian, no matter
+what kernel options are enabled.
+
+gfxpayload=keep is a good idea but rather ahead of its time ...
+
+Bug-Debian: http://bugs.debian.org/567245
+Forwarded: no
+Last-Update: 2013-12-25
+
+Patch-Name: gfxpayload-keep-default.patch
+---
+ 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 e8b01c0d0..9446d6833 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -114,10 +114,6 @@ linux_entry ()
+ # FIXME: We need an interface to select vesafb in case efifb can't be used.
+ if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
+ echo " load_video" | sed "s/^/$submenu_indentation/"
+- if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \
+- && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then
+- echo " set gfxpayload=keep" | sed "s/^/$submenu_indentation/"
+- fi
+ else
+ if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
+ echo " load_video" | sed "s/^/$submenu_indentation/"
diff --git a/debian/patches/grub-install-extra-removable.patch b/debian/patches/grub-install-extra-removable.patch
new file mode 100644
index 0000000..1e7d2b4
--- /dev/null
+++ b/debian/patches/grub-install-extra-removable.patch
@@ -0,0 +1,202 @@
+From a0bfbdf9139bc127d28c4102b941ee504f7f0041 Mon Sep 17 00:00:00 2001
+From: Steve McIntyre <93sam@debian.org>
+Date: Wed, 3 Dec 2014 01:25:12 +0000
+Subject: Add support for forcing EFI installation to the removable media path
+
+Add an extra option to grub-install "--force-extra-removable". On EFI
+platforms, this will cause an extra copy of the grub-efi image to be
+written to the appropriate removable media patch
+/boot/efi/EFI/BOOT/BOOT$ARCH.EFI as well. This will help with broken
+UEFI implementations where the firmware does not work when configured
+with new boot paths.
+
+Signed-off-by: Steve McIntyre <93sam@debian.org>
+
+Bug-Debian: https://bugs.debian.org/767037 https://bugs.debian.org/773092
+Forwarded: Not yet
+Last-Update: 2021-09-24
+
+Patch-Name: grub-install-extra-removable.patch
+---
+ util/grub-install.c | 110 +++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 108 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 2304cc5c4..b51fe4710 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -56,6 +56,7 @@
+
+ static char *target;
+ static int removable = 0;
++static int force_extra_removable = 0;
+ static int recheck = 0;
+ static int update_nvram = 1;
+ static char *install_device = NULL;
+@@ -113,7 +114,8 @@ enum
+ OPTION_LABEL_BGCOLOR,
+ OPTION_PRODUCT_VERSION,
+ OPTION_UEFI_SECURE_BOOT,
+- OPTION_NO_UEFI_SECURE_BOOT
++ OPTION_NO_UEFI_SECURE_BOOT,
++ OPTION_FORCE_EXTRA_REMOVABLE
+ };
+
+ static int fs_probe = 1;
+@@ -216,6 +218,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
+ removable = 1;
+ return 0;
+
++ case OPTION_FORCE_EXTRA_REMOVABLE:
++ force_extra_removable = 1;
++ return 0;
++
+ case OPTION_ALLOW_FLOPPY:
+ allow_floppy = 1;
+ return 0;
+@@ -322,6 +328,9 @@ static struct argp_option options[] = {
+ N_("do not install an image usable with UEFI Secure Boot, even if the "
+ "system was currently started using it. "
+ "This option is only available on EFI."), 2},
++ {"force-extra-removable", OPTION_FORCE_EXTRA_REMOVABLE, 0, 0,
++ N_("force installation to the removable media path also. "
++ "This option is only available on EFI."), 2},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+@@ -847,6 +856,91 @@ fill_core_services (const char *core_services)
+ free (sysv_plist);
+ }
+
++/* Helper routine for also_install_removable() below. Walk through the
++ specified dir, looking to see if there is a file/dir that matches
++ the search string exactly, but in a case-insensitive manner. If so,
++ return a copy of the exact file/dir that *does* exist. If not,
++ return NULL */
++static char *
++check_component_exists(const char *dir,
++ const char *search)
++{
++ grub_util_fd_dir_t d;
++ grub_util_fd_dirent_t de;
++ char *found = NULL;
++
++ d = grub_util_fd_opendir (dir);
++ if (!d)
++ grub_util_error (_("cannot open directory `%s': %s"),
++ dir, grub_util_fd_strerror ());
++
++ while ((de = grub_util_fd_readdir (d)))
++ {
++ if (strcasecmp (de->d_name, search) == 0)
++ {
++ found = xstrdup (de->d_name);
++ break;
++ }
++ }
++ grub_util_fd_closedir (d);
++ return found;
++}
++
++/* Some complex directory-handling stuff in here, to cope with
++ * case-insensitive FAT/VFAT filesystem semantics. Ugh. */
++static void
++also_install_removable(const char *src,
++ const char *base_efidir,
++ const char *efi_suffix_upper)
++{
++ char *efi_file = NULL;
++ char *dst = NULL;
++ char *cur = NULL;
++ char *found = NULL;
++
++ if (!efi_suffix_upper)
++ grub_util_error ("%s", _("efi_suffix_upper not set"));
++ efi_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper);
++
++ /* We need to install in $base_efidir/EFI/BOOT/$efi_file, but we
++ * need to cope with case-insensitive stuff here. Build the path one
++ * component at a time, checking for existing matches each time. */
++
++ /* Look for "EFI" in base_efidir. Make it if it does not exist in
++ * some form. */
++ found = check_component_exists(base_efidir, "EFI");
++ if (found == NULL)
++ found = xstrdup("EFI");
++ dst = grub_util_path_concat (2, base_efidir, found);
++ cur = xstrdup (dst);
++ free (dst);
++ free (found);
++ grub_install_mkdir_p (cur);
++
++ /* Now BOOT */
++ found = check_component_exists(cur, "BOOT");
++ if (found == NULL)
++ found = xstrdup("BOOT");
++ dst = grub_util_path_concat (2, cur, found);
++ cur = xstrdup (dst);
++ free (dst);
++ free (found);
++ grub_install_mkdir_p (cur);
++
++ /* Now $efi_file */
++ found = check_component_exists(cur, efi_file);
++ if (found == NULL)
++ found = xstrdup(efi_file);
++ dst = grub_util_path_concat (2, cur, found);
++ cur = xstrdup (dst);
++ free (dst);
++ free (found);
++ grub_install_copy_file (src, cur, 1);
++
++ free (cur);
++ free (efi_file);
++}
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -864,6 +958,7 @@ main (int argc, char *argv[])
+ char *relative_grubdir;
+ char **efidir_device_names = NULL;
+ grub_device_t efidir_grub_dev = NULL;
++ char *base_efidir = NULL;
+ char *efidir_grub_devname;
+ int efidir_is_mac = 0;
+ int is_prep = 0;
+@@ -896,6 +991,9 @@ main (int argc, char *argv[])
+ bootloader_id = xstrdup ("grub");
+ }
+
++ if (removable && force_extra_removable)
++ grub_util_error (_("Invalid to use both --removable and --force_extra_removable"));
++
+ if (!grub_install_source_directory)
+ {
+ if (!target)
+@@ -1115,6 +1213,8 @@ main (int argc, char *argv[])
+ if (!efidir_is_mac && grub_strcmp (fs->name, "fat") != 0)
+ grub_util_error (_("%s doesn't look like an EFI partition"), efidir);
+
++ base_efidir = xstrdup(efidir);
++
+ /* The EFI specification requires that an EFI System Partition must
+ contain an "EFI" subdirectory, and that OS loaders are stored in
+ subdirectories below EFI. Vendors are expected to pick names that do
+@@ -2048,9 +2148,15 @@ main (int argc, char *argv[])
+ fprintf (config_dst_f, "configfile $prefix/grub.cfg\n");
+ fclose (config_dst_f);
+ free (config_dst);
++ if (force_extra_removable)
++ also_install_removable(efi_signed, base_efidir, efi_suffix_upper);
+ }
+ else
+- grub_install_copy_file (imgfile, dst, 1);
++ {
++ grub_install_copy_file (imgfile, dst, 1);
++ if (force_extra_removable)
++ also_install_removable(imgfile, base_efidir, efi_suffix_upper);
++ }
+
+ grub_set_install_backup_ponr ();
+
diff --git a/debian/patches/grub-install-pvxen-paths.patch b/debian/patches/grub-install-pvxen-paths.patch
new file mode 100644
index 0000000..88987a2
--- /dev/null
+++ b/debian/patches/grub-install-pvxen-paths.patch
@@ -0,0 +1,71 @@
+From 4e93755cd1c371ba856b375f453664fd07a67205 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ijc@hellion.org.uk>
+Date: Sat, 6 Sep 2014 12:20:12 +0100
+Subject: grub-install: Install PV Xen binaries into the upstream specified
+ path
+
+Upstream have defined a specification for where guests ought to place their
+xenpv grub binaries in order to facilitate chainloading from a stage 1 grub
+loaded from dom0.
+
+http://xenbits.xen.org/docs/unstable-staging/misc/x86-xenpv-bootloader.html
+
+The spec calls for installation into /boot/xen/pvboot-i386.elf or
+/boot/xen/pvboot-x86_64.elf.
+
+Signed-off-by: Ian Campbell <ijc@hellion.org.uk>
+
+Bug-Debian: https://bugs.debian.org/762307
+Forwarded: http://lists.gnu.org/archive/html/grub-devel/2014-10/msg00041.html
+Last-Update: 2014-10-24
+
+Patch-Name: grub-install-pvxen-paths.patch
+
+---
+v2: Respect bootdir, create /boot/xen as needed.
+---
+ util/grub-install.c | 24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index d02bd488a..2304cc5c4 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -2085,6 +2085,28 @@ main (int argc, char *argv[])
+ }
+ break;
+
++ case GRUB_INSTALL_PLATFORM_I386_XEN:
++ {
++ char *path = grub_util_path_concat (2, bootdir, "xen");
++ char *dst = grub_util_path_concat (2, path, "pvboot-i386.elf");
++ grub_install_mkdir_p (path);
++ grub_install_copy_file (imgfile, dst, 1);
++ free (dst);
++ free (path);
++ }
++ break;
++
++ case GRUB_INSTALL_PLATFORM_X86_64_XEN:
++ {
++ char *path = grub_util_path_concat (2, bootdir, "xen");
++ char *dst = grub_util_path_concat (2, path, "pvboot-x86_64.elf");
++ grub_install_mkdir_p (path);
++ grub_install_copy_file (imgfile, dst, 1);
++ free (dst);
++ free (path);
++ }
++ break;
++
+ case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+ case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+ case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+@@ -2094,8 +2116,6 @@ main (int argc, char *argv[])
+ case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+ case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+ case GRUB_INSTALL_PLATFORM_I386_QEMU:
+- case GRUB_INSTALL_PLATFORM_I386_XEN:
+- case GRUB_INSTALL_PLATFORM_X86_64_XEN:
+ case GRUB_INSTALL_PLATFORM_I386_XEN_PVH:
+ grub_util_warn ("%s",
+ _("WARNING: no platform-specific install was performed"));
diff --git a/debian/patches/grub-install-removable-shim.patch b/debian/patches/grub-install-removable-shim.patch
new file mode 100644
index 0000000..21b87c4
--- /dev/null
+++ b/debian/patches/grub-install-removable-shim.patch
@@ -0,0 +1,196 @@
+From c8351a8a7a7664dfac4de63fb6df185b2a52a346 Mon Sep 17 00:00:00 2001
+From: Steve McIntyre <93sam@debian.org>
+Date: Fri, 14 Jun 2019 16:37:11 +0100
+Subject: Deal with --force-extra-removable with signed shim too
+
+In this case, we need both the signed shim as /EFI/BOOT/BOOTXXX.EFI
+and signed Grub as /EFI/BOOT/grubXXX.efi.
+
+Also install the BOOTXXX.CSV into /EFI/debian, and FBXXX.EFI into
+/EFI/BOOT/ so that it can work when needed (*iff* we're updating the
+NVRAM).
+
+[cjwatson: Refactored also_install_removable somewhat for brevity and so
+that we're using consistent case-insensitive logic.]
+
+Bug-Debian: https://bugs.debian.org/930531
+Last-Update: 2021-09-24
+
+Patch-Name: grub-install-removable-shim.patch
+---
+ util/grub-install.c | 83 +++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 66 insertions(+), 17 deletions(-)
+
+Index: grub.git/util/grub-install.c
+===================================================================
+--- grub.git.orig/util/grub-install.c
++++ grub.git/util/grub-install.c
+@@ -891,17 +891,13 @@ check_component_exists(const char *dir,
+ static void
+ also_install_removable(const char *src,
+ const char *base_efidir,
+- const char *efi_suffix_upper)
++ const char *efi_file,
++ int is_needed)
+ {
+- char *efi_file = NULL;
+ char *dst = NULL;
+ char *cur = NULL;
+ char *found = NULL;
+
+- if (!efi_suffix_upper)
+- grub_util_error ("%s", _("efi_suffix_upper not set"));
+- efi_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper);
+-
+ /* We need to install in $base_efidir/EFI/BOOT/$efi_file, but we
+ * need to cope with case-insensitive stuff here. Build the path one
+ * component at a time, checking for existing matches each time. */
+@@ -935,10 +931,9 @@ also_install_removable(const char *src,
+ cur = xstrdup (dst);
+ free (dst);
+ free (found);
+- grub_install_copy_file (src, cur, 1);
++ grub_install_copy_file (src, cur, is_needed);
+
+ free (cur);
+- free (efi_file);
+ }
+
+ int
+@@ -2103,11 +2098,14 @@ main (int argc, char *argv[])
+ case GRUB_INSTALL_PLATFORM_IA64_EFI:
+ {
+ char *dst = grub_util_path_concat (2, efidir, efi_file);
++ char *removable_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper);
++
+ if (uefi_secure_boot)
+ {
+ char *shim_signed = NULL;
+ char *mok_signed = NULL, *mok_file = NULL;
+ char *fb_signed = NULL, *fb_file = NULL;
++ char *csv_file = NULL;
+ char *config_dst;
+ FILE *config_dst_f;
+
+@@ -2116,11 +2114,15 @@ main (int argc, char *argv[])
+ mok_file = xasprintf ("mm%s.efi", efi_suffix);
+ fb_signed = xasprintf ("fb%s.efi.signed", efi_suffix);
+ fb_file = xasprintf ("fb%s.efi", efi_suffix);
++ csv_file = xasprintf ("BOOT%s.CSV", efi_suffix_upper);
++
++ /* If we have a signed shim binary, install that and all
++ its helpers in the normal vendor path */
+
+ if (grub_util_is_regular (shim_signed))
+ {
+ char *chained_base, *chained_dst;
+- char *mok_src, *mok_dst, *fb_src, *fb_dst;
++ char *mok_src, *mok_dst, *fb_src, *fb_dst, *csv_src, *csv_dst;
+ if (!removable)
+ {
+ free (efi_file);
+@@ -2132,8 +2134,6 @@ main (int argc, char *argv[])
+ chained_base = xasprintf ("grub%s.efi", efi_suffix);
+ chained_dst = grub_util_path_concat (2, efidir, chained_base);
+ grub_install_copy_file (efi_signed, chained_dst, 1);
+- free (chained_dst);
+- free (chained_base);
+
+ /* Not critical, so not an error if they are not present (as it
+ won't be for older releases); but if we have them, make
+@@ -2144,8 +2144,6 @@ main (int argc, char *argv[])
+ mok_file);
+ grub_install_copy_file (mok_src,
+ mok_dst, 0);
+- free (mok_src);
+- free (mok_dst);
+
+ fb_src = grub_util_path_concat (2, "/usr/lib/shim/",
+ fb_signed);
+@@ -2154,30 +2152,82 @@ main (int argc, char *argv[])
+ if (!removable)
+ grub_install_copy_file (fb_src,
+ fb_dst, 0);
++
++ csv_src = grub_util_path_concat (2, "/usr/lib/shim/",
++ csv_file);
++ csv_dst = grub_util_path_concat (2, efidir,
++ csv_file);
++ grub_install_copy_file (csv_src,
++ csv_dst, 0);
++
++ /* Install binaries into .../EFI/BOOT too:
++ the shim binary
++ the grub binary
++ the shim fallback binary (not fatal on failure) */
++ if (force_extra_removable)
++ {
++ grub_util_info ("Secure boot: installing shim and image into rm path");
++ also_install_removable (shim_signed, base_efidir, removable_file, 1);
++
++ also_install_removable (efi_signed, base_efidir, chained_base, 1);
++ also_install_removable (mok_src, base_efidir, mok_file, 0);
++
++ /* If we're updating the NVRAM, add fallback too - it
++ will re-update the NVRAM later if things break */
++ if (update_nvram)
++ also_install_removable (fb_src, base_efidir, fb_file, 0);
++ }
++
++ free (chained_dst);
++ free (chained_base);
++ free (mok_src);
++ free (mok_dst);
+ free (fb_src);
+ free (fb_dst);
++ free (csv_src);
++ free (csv_dst);
+ }
+ else
+- grub_install_copy_file (efi_signed, dst, 1);
++ {
++ /* Tried to install for secure boot, but no signed
++ shim found. Fall back to just installing the signed
++ grub binary */
++ grub_util_info ("Secure boot (no shim): installing signed grub binary");
++ grub_install_copy_file (efi_signed, dst, 1);
++ if (force_extra_removable)
++ {
++ grub_util_info ("Secure boot (no shim): installing signed grub binary into rm path");
++ also_install_removable (efi_signed, base_efidir, removable_file, 1);
++ }
++ }
+
++ /* In either case, install our grub.cfg */
+ config_dst = grub_util_path_concat (2, efidir, "grub.cfg");
+ grub_install_copy_file (load_cfg, config_dst, 1);
+ config_dst_f = grub_util_fopen (config_dst, "ab");
+ fprintf (config_dst_f, "configfile $prefix/grub.cfg\n");
+ fclose (config_dst_f);
+ free (config_dst);
+- if (force_extra_removable)
+- also_install_removable(efi_signed, base_efidir, efi_suffix_upper);
++
++ free (csv_file);
++ free (fb_file);
++ free (fb_signed);
++ free (mok_file);
++ free (mok_signed);
++ free (shim_signed);
+ }
+ else
+ {
++ /* No secure boot - just install our newly-generated image */
++ grub_util_info ("No Secure Boot: installing core image");
+ grub_install_copy_file (imgfile, dst, 1);
+ if (force_extra_removable)
+- also_install_removable(imgfile, base_efidir, efi_suffix_upper);
++ also_install_removable (imgfile, base_efidir, removable_file, 1);
+ }
+
+ grub_set_install_backup_ponr ();
+
++ free (removable_file);
+ free (dst);
+ }
+ if (!removable && update_nvram)
diff --git a/debian/patches/grub-legacy-0-based-partitions.patch b/debian/patches/grub-legacy-0-based-partitions.patch
new file mode 100644
index 0000000..31dc3c1
--- /dev/null
+++ b/debian/patches/grub-legacy-0-based-partitions.patch
@@ -0,0 +1,39 @@
+From ae648ba6160a334707f8a8fc0768ec1bc60c4442 Mon Sep 17 00:00:00 2001
+From: Robert Millan <rmh@aybabtu.com>
+Date: Mon, 13 Jan 2014 12:12:53 +0000
+Subject: Support running grub-probe in grub-legacy's update-grub
+
+Author: Colin Watson <cjwatson@debian.org>
+Forwarded: not-needed
+Last-Update: 2013-12-25
+
+Patch-Name: grub-legacy-0-based-partitions.patch
+---
+ util/getroot.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/util/getroot.c b/util/getroot.c
+index a5eaa64fd..6ae35ecaa 100644
+--- a/util/getroot.c
++++ b/util/getroot.c
+@@ -245,6 +245,20 @@ find_partition (grub_disk_t dsk __attribute__ ((unused)),
+
+ if (ctx->start == part_start)
+ {
++ /* This is dreadfully hardcoded, but there's a limit to what GRUB
++ Legacy was able to deal with anyway. */
++ if (getenv ("GRUB_LEGACY_0_BASED_PARTITIONS"))
++ {
++ if (partition->parent)
++ /* Probably a BSD slice. */
++ ctx->partname = xasprintf ("%d,%d", partition->parent->number,
++ partition->number + 1);
++ else
++ ctx->partname = xasprintf ("%d", partition->number);
++
++ return 1;
++ }
++
+ ctx->partname = grub_partition_get_name (partition);
+ return 1;
+ }
diff --git a/debian/patches/grub.cfg-400.patch b/debian/patches/grub.cfg-400.patch
new file mode 100644
index 0000000..2f1c304
--- /dev/null
+++ b/debian/patches/grub.cfg-400.patch
@@ -0,0 +1,25 @@
+From 2f1be2e80ba5dd1278401f21cfe07526312838e9 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:12:55 +0000
+Subject: Make grub.cfg world-readable if it contains no passwords
+
+Patch-Name: grub.cfg-400.patch
+---
+ util/grub-mkconfig.in | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index f8cbb8d7a..0fd618e35 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -289,6 +289,10 @@ for i in "${grub_mkconfig_dir}"/* ; do
+ esac
+ done
+
++if [ "x${grub_cfg}" != "x" ] && ! grep "^password" ${grub_cfg}.new >/dev/null; then
++ chmod 444 ${grub_cfg}.new || true
++fi
++
+ if test "x${grub_cfg}" != "x" ; then
+ if ! ${grub_script_check} ${grub_cfg}.new; then
+ # TRANSLATORS: %s is replaced by filename
diff --git a/debian/patches/grub_mkconfig_restore_umask.patch b/debian/patches/grub_mkconfig_restore_umask.patch
new file mode 100644
index 0000000..bd85cfc
--- /dev/null
+++ b/debian/patches/grub_mkconfig_restore_umask.patch
@@ -0,0 +1,36 @@
+commit 0adec29674561034771c13e446069b41ef41e4d4
+Author: Michael Chang <mchang@suse.com>
+Date: Fri Dec 3 16:13:28 2021 +0800
+
+ grub-mkconfig: Restore umask for the grub.cfg
+
+ The 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 running grub-mkconfig. The resulting
+ wrong permission (0644) would allow unprivileged users to read GRUB
+ 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 sets the creation file mode
+ to 0600 preventing unprivileged access.
+
+ Fixes: CVE-2021-3981
+
+ Signed-off-by: Michael Chang <mchang@suse.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index c3ea7612e..62335d027 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -301,7 +301,10 @@ 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/debian/patches/grub_os-prober.patch b/debian/patches/grub_os-prober.patch
new file mode 100644
index 0000000..e226eab
--- /dev/null
+++ b/debian/patches/grub_os-prober.patch
@@ -0,0 +1,22 @@
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 225a3baf7..ea3f3f804 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -40,13 +40,13 @@ EOF
+ fi
+ }
+
+-if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then
+- grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")"
++if ! command -v os-prober > /dev/null || ! command -v linux-boot-prober > /dev/null ; then
++ # missing os-prober and/or linux-boot-prober
+ exit 0
+ fi
+
+-if ! command -v os-prober > /dev/null || ! command -v linux-boot-prober > /dev/null ; then
+- # missing os-prober and/or linux-boot-prober
++if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then
++ grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")"
+ exit 0
+ fi
+
diff --git a/debian/patches/ieee1275-clear-reset.patch b/debian/patches/ieee1275-clear-reset.patch
new file mode 100644
index 0000000..c528944
--- /dev/null
+++ b/debian/patches/ieee1275-clear-reset.patch
@@ -0,0 +1,32 @@
+From 791c1034910b5e87ec7ff4166300f0f26b647625 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com>
+Date: Thu, 25 Sep 2014 18:41:29 -0300
+Subject: Include a text attribute reset in the clear command for ppc
+
+Always clear text attribute for clear command in order to avoid problems
+after it boots.
+
+* grub-core/term/terminfo.c: Add escape for text attribute reset
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1295255
+Origin: other, https://lists.gnu.org/archive/html/grub-devel/2014-09/msg00076.html
+Last-Update: 2014-09-26
+
+Patch-Name: ieee1275-clear-reset.patch
+---
+ grub-core/term/terminfo.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c
+index 85ecf06b4..e5ec77107 100644
+--- a/grub-core/term/terminfo.c
++++ b/grub-core/term/terminfo.c
+@@ -151,7 +151,7 @@ grub_terminfo_set_current (struct grub_term_output *term,
+ /* Clear the screen. Using serial console, screen(1) only recognizes the
+ * ANSI escape sequence. Using video console, Apple Open Firmware
+ * (version 3.1.1) only recognizes the literal ^L. So use both. */
+- data->cls = grub_strdup (" \e[2J");
++ data->cls = grub_strdup (" \e[2J\e[m");
+ data->reverse_video_on = grub_strdup ("\e[7m");
+ data->reverse_video_off = grub_strdup ("\e[m");
+ if (grub_strcmp ("ieee1275", str) == 0)
diff --git a/debian/patches/ignore-grub_func_test-failures.patch b/debian/patches/ignore-grub_func_test-failures.patch
new file mode 100644
index 0000000..6275b26
--- /dev/null
+++ b/debian/patches/ignore-grub_func_test-failures.patch
@@ -0,0 +1,29 @@
+From f8d8c2e9dfd49bd0e59e27c09fc535a547d13c01 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:13:32 +0000
+Subject: Ignore functional test failures for now as they are broken
+
+See: https://lists.gnu.org/archive/html/grub-devel/2013-11/msg00242.html
+
+Forwarded: not-needed
+Last-Update: 2013-11-19
+
+Patch-Name: ignore-grub_func_test-failures.patch
+---
+ tests/grub_func_test.in | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/tests/grub_func_test.in b/tests/grub_func_test.in
+index c67f9e422..728cd6e06 100644
+--- a/tests/grub_func_test.in
++++ b/tests/grub_func_test.in
+@@ -16,6 +16,8 @@ out=`echo all_functional_test | @builddir@/grub-shell --timeout=3600 --files="/b
+
+ if [ "$(echo "$out" | tail -n 1)" != "ALL TESTS PASSED" ]; then
+ echo "Functional test failure: $out"
+- exit 1
++ # Disabled temporarily due to unrecognised video checksum failures.
++ #exit 1
++ exit 0
+ fi
+
diff --git a/debian/patches/ignore_checksum_seed_incompat_feature.patch b/debian/patches/ignore_checksum_seed_incompat_feature.patch
new file mode 100644
index 0000000..cd9b897
--- /dev/null
+++ b/debian/patches/ignore_checksum_seed_incompat_feature.patch
@@ -0,0 +1,54 @@
+commit 7fd5feff97c4b1f446f8fcf6d37aca0c64e7c763
+Author: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri Jun 11 21:36:16 2021 +0200
+
+ 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
+ changing the UUID on a mounted metdata_csum filesystem without having
+ to rewrite all the disk metadata. However, the GRUB doesn't use the
+ metadata checksum at all. So, it can just ignore this feature if it
+ is enabled. This is consistent with the GRUB filesystem code in general
+ which just does a best effort to access the filesystem's data.
+
+ The checksum seed incompat feature has to be removed from the ignore
+ list if the support for metadata checksum verification is added to the
+ GRUB ext2 driver later.
+
+ Suggested-by: Eric Sandeen <esandeen@redhat.com>
+ Suggested-by: Lukas Czerner <lczerner@redhat.com>
+ Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+ Reviewed-by: Lukas Czerner <lczerner@redhat.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
+index e7dd78e66..4953a1591 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,10 +124,15 @@ 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. However, it
++ * has to be removed from this list if the 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/debian/patches/ignore_the_large_dir_incompat_feature.patch b/debian/patches/ignore_the_large_dir_incompat_feature.patch
new file mode 100644
index 0000000..ea6ec5f
--- /dev/null
+++ b/debian/patches/ignore_the_large_dir_incompat_feature.patch
@@ -0,0 +1,53 @@
+commit 2e9fa73a040462b81bfbfe56c0bc7ad2d30b446b
+Author: Theodore Ts'o <tytso@mit.edu>
+Date: Tue Aug 30 22:41:59 2022 -0400
+
+ fs/ext2: Ignore the large_dir incompat feature
+
+ Recently, ext4 added the large_dir feature, which adds support for
+ a 3 level htree directory support.
+
+ The GRUB supports existing file systems with htree directories by
+ ignoring their existence, and since the index nodes for the hash tree
+ look like deleted directory entries (by design), the GRUB can simply do
+ a brute force O(n) linear search of directories. The same is true for
+ 3 level deep htrees indicated by large_dir feature flag.
+
+ Hence, it is safe for the GRUB to ignore the large_dir incompat feature.
+
+ Fixes: https://savannah.gnu.org/bugs/?61606
+
+ Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
+index 0989e26e1..e1cc5e62a 100644
+--- a/grub-core/fs/ext2.c
++++ b/grub-core/fs/ext2.c
+@@ -104,6 +104,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+ #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+ #define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000
++#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3 level htree */
+ #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
+
+ /* The set of back-incompatible features this driver DOES support. Add (OR)
+@@ -129,10 +130,17 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ * checksummed filesystem. Safe to ignore for now since the
+ * driver doesn't support checksum verification. However, it
+ * has to be removed from this list if the support is added later.
++ * large_dir: Not back-incompatible given that the GRUB ext2 driver does
++ * not implement EXT2_FEATURE_COMPAT_DIR_INDEX. If the GRUB
++ * eventually supports the htree feature (aka dir_index)
++ * it should support 3 level htrees and then move
++ * EXT4_FEATURE_INCOMPAT_LARGEDIR to
++ * EXT2_DRIVER_SUPPORTED_INCOMPAT.
+ */
+ #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
+ | EXT4_FEATURE_INCOMPAT_MMP \
+- | EXT4_FEATURE_INCOMPAT_CSUM_SEED)
++ | EXT4_FEATURE_INCOMPAT_CSUM_SEED \
++ | EXT4_FEATURE_INCOMPAT_LARGEDIR)
+
+ #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
+
diff --git a/debian/patches/insmod-xzio-and-lzopio-on-xen.patch b/debian/patches/insmod-xzio-and-lzopio-on-xen.patch
new file mode 100644
index 0000000..fb48118
--- /dev/null
+++ b/debian/patches/insmod-xzio-and-lzopio-on-xen.patch
@@ -0,0 +1,33 @@
+From bc8ec86089a4f6eb2ea19499a2b335dccdebd577 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ijc@debian.org>
+Date: Sun, 30 Nov 2014 12:12:52 +0000
+Subject: Arrange to insmod xzio and lzopio when booting a kernel as a Xen
+ guest
+
+This is needed in case the Linux kernel is compiled with CONFIG_KERNEL_XZ or
+CONFIG_KERNEL_LZO rather than CONFIG_KERNEL_GZ (gzio is already loaded by
+grub.cfg today).
+
+Signed-off-by: Ian Campbell <ijc@debian.org>
+
+Bug-Debian: https://bugs.debian.org/755256
+Forwarded: http://lists.gnu.org/archive/html/grub-devel/2014-11/msg00091.html
+Last-Update: 2014-11-30
+
+Patch-Name: insmod-xzio-and-lzopio-on-xen.patch
+---
+ util/grub.d/10_linux.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index f88a2de10..635c609d6 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -162,6 +162,7 @@ linux_entry ()
+ fi
+
+ echo " insmod gzio" | sed "s/^/$submenu_indentation/"
++ echo " if [ x\$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi" | sed "s/^/$submenu_indentation/"
+
+ if [ x$dirname = x/ ]; then
+ if [ -z "${prepare_root_cache}" ]; then
diff --git a/debian/patches/install-efi-adjust-distributor.patch b/debian/patches/install-efi-adjust-distributor.patch
new file mode 100644
index 0000000..f802618
--- /dev/null
+++ b/debian/patches/install-efi-adjust-distributor.patch
@@ -0,0 +1,34 @@
+From 11ea79546da850296fabeb94bfc8c110a98fe7f6 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:27 +0000
+Subject: Adjust efi_distributor for some distributions
+
+This is not a very good approach, and certainly not sanely upstreamable;
+we probably need to split GRUB_DISTRIBUTOR into a couple of different
+variables.
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1242417
+Bug-Debian: https://bugs.debian.org/932966
+Forwarded: not-needed
+Last-Update: 2019-08-06
+
+Patch-Name: install-efi-adjust-distributor.patch
+---
+ util/grub-install.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index f49c78d0b..48c8c0364 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1123,6 +1123,10 @@ main (int argc, char *argv[])
+ */
+ char *t;
+ efi_distributor = bootloader_id;
++ if (strcmp (efi_distributor, "kubuntu") == 0)
++ efi_distributor = "ubuntu";
++ else if (strcmp (efi_distributor, "devuan") == 0)
++ efi_distributor = "debian";
+ switch (platform)
+ {
+ case GRUB_INSTALL_PLATFORM_I386_EFI:
diff --git a/debian/patches/install-efi-fallback.patch b/debian/patches/install-efi-fallback.patch
new file mode 100644
index 0000000..6501d8a
--- /dev/null
+++ b/debian/patches/install-efi-fallback.patch
@@ -0,0 +1,91 @@
+From 7cf3ac7be59ef377a98ead5c7d3d5cb537c159c4 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:05 +0000
+Subject: Fall back to non-EFI if booted using EFI but -efi is missing
+
+It may be possible, particularly in recovery situations, to be booted
+using EFI on x86 when only the i386-pc target is installed, or on ARM
+when only the arm-uboot target is installed. There's nothing actually
+stopping us installing i386-pc or arm-uboot from an EFI environment, and
+it's better than returning a confusing error.
+
+Author: Steve McIntyre <93sam@debian.org>
+Forwarded: no
+Last-Update: 2019-05-24
+
+Patch-Name: install-efi-fallback.patch
+---
+ grub-core/osdep/linux/platform.c | 40 ++++++++++++++++++++++++++++----
+ 1 file changed, 35 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/osdep/linux/platform.c b/grub-core/osdep/linux/platform.c
+index e28a79dab..2e7f72086 100644
+--- a/grub-core/osdep/linux/platform.c
++++ b/grub-core/osdep/linux/platform.c
+@@ -19,10 +19,12 @@
+ #include <config.h>
+
+ #include <grub/util/install.h>
++#include <grub/emu/config.h>
+ #include <grub/emu/exec.h>
+ #include <grub/emu/misc.h>
+ #include <sys/types.h>
+ #include <dirent.h>
++#include <stdlib.h>
+ #include <string.h>
+
+ #include <sys/utsname.h>
+@@ -128,9 +130,24 @@ const char *
+ grub_install_get_default_arm_platform (void)
+ {
+ if (is_efi_system())
+- return "arm-efi";
+- else
+- return "arm-uboot";
++ {
++ const char *pkglibdir = grub_util_get_pkglibdir ();
++ const char *platform;
++ char *pd;
++ int found;
++
++ platform = "arm-efi";
++
++ pd = grub_util_path_concat (2, pkglibdir, platform);
++ found = grub_util_is_directory (pd);
++ free (pd);
++ if (found)
++ return platform;
++ else
++ grub_util_info ("... but %s platform not available", platform);
++ }
++
++ return "arm-uboot";
+ }
+
+ const char *
+@@ -138,10 +155,23 @@ grub_install_get_default_x86_platform (void)
+ {
+ if (is_efi_system())
+ {
++ const char *pkglibdir = grub_util_get_pkglibdir ();
++ const char *platform;
++ char *pd;
++ int found;
++
+ if (read_platform_size() == 64)
+- return "x86_64-efi";
++ platform = "x86_64-efi";
++ else
++ platform = "i386-efi";
++
++ pd = grub_util_path_concat (2, pkglibdir, platform);
++ found = grub_util_is_directory (pd);
++ free (pd);
++ if (found)
++ return platform;
+ else
+- return "i386-efi";
++ grub_util_info ("... but %s platform not available", platform);
+ }
+
+ grub_util_info ("Looking for /proc/device-tree ..");
diff --git a/debian/patches/install-locale-langpack.patch b/debian/patches/install-locale-langpack.patch
new file mode 100644
index 0000000..ae96bab
--- /dev/null
+++ b/debian/patches/install-locale-langpack.patch
@@ -0,0 +1,116 @@
+From 31e9c5eaec14e18251db1fb7e6e44add22e56526 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:07 +0000
+Subject: Prefer translations from Ubuntu language packs if available
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/537998
+Forwarded: not-needed
+Last-Update: 2013-12-25
+
+Patch-Name: install-locale-langpack.patch
+---
+ util/grub-install-common.c | 37 ++++++++++++++++++++++++++++++-------
+ 1 file changed, 30 insertions(+), 7 deletions(-)
+
+diff --git a/util/grub-install-common.c b/util/grub-install-common.c
+index 4e212e690..e53730485 100644
+--- a/util/grub-install-common.c
++++ b/util/grub-install-common.c
+@@ -774,17 +774,25 @@ get_localedir (void)
+ }
+
+ static void
+-copy_locales (const char *dstd)
++copy_locales (const char *dstd, int langpack)
+ {
+ grub_util_fd_dir_t d;
+ grub_util_fd_dirent_t de;
+ const char *locale_dir = get_localedir ();
++ char *dir;
+
+- d = grub_util_fd_opendir (locale_dir);
++ if (langpack)
++ dir = xasprintf ("%s-langpack", locale_dir);
++ else
++ dir = xstrdup (locale_dir);
++
++ d = grub_util_fd_opendir (dir);
+ if (!d)
+ {
+- grub_util_warn (_("cannot open directory `%s': %s"),
+- locale_dir, grub_util_fd_strerror ());
++ if (!langpack)
++ grub_util_warn (_("cannot open directory `%s': %s"),
++ dir, grub_util_fd_strerror ());
++ free (dir);
+ return;
+ }
+
+@@ -801,14 +809,14 @@ copy_locales (const char *dstd)
+ if (ext && (grub_strcmp (ext, ".mo") == 0
+ || grub_strcmp (ext, ".gmo") == 0))
+ {
+- srcf = grub_util_path_concat (2, locale_dir, de->d_name);
++ srcf = grub_util_path_concat (2, dir, de->d_name);
+ dstf = grub_util_path_concat (2, dstd, de->d_name);
+ ext = grub_strrchr (dstf, '.');
+ grub_strcpy (ext, ".mo");
+ }
+ else
+ {
+- srcf = grub_util_path_concat_ext (4, locale_dir, de->d_name,
++ srcf = grub_util_path_concat_ext (4, dir, de->d_name,
+ "LC_MESSAGES", PACKAGE, ".mo");
+ dstf = grub_util_path_concat_ext (2, dstd, de->d_name, ".mo");
+ }
+@@ -817,6 +825,7 @@ copy_locales (const char *dstd)
+ free (dstf);
+ }
+ grub_util_fd_closedir (d);
++ free (dir);
+ }
+ #endif
+
+@@ -835,13 +844,15 @@ grub_install_copy_nls(const char *src __attribute__ ((unused)),
+ {
+ char *srcd = grub_util_path_concat (2, src, "po");
+ copy_by_ext (srcd, dst_locale, ".mo", 0);
+- copy_locales (dst_locale);
++ copy_locales (dst_locale, 0);
++ copy_locales (dst_locale, 1);
+ free (srcd);
+ }
+ else
+ {
+ size_t i;
+ const char *locale_dir = get_localedir ();
++ char *locale_langpack_dir = xasprintf ("%s-langpack", locale_dir);
+
+ for (i = 0; i < install_locales.n_entries; i++)
+ {
+@@ -858,6 +869,16 @@ grub_install_copy_nls(const char *src __attribute__ ((unused)),
+ continue;
+ }
+ free (srcf);
++ srcf = grub_util_path_concat_ext (4, locale_langpack_dir,
++ install_locales.entries[i],
++ "LC_MESSAGES", PACKAGE, ".mo");
++ if (grub_install_compress_file (srcf, dstf, 0))
++ {
++ free (srcf);
++ free (dstf);
++ continue;
++ }
++ free (srcf);
+ srcf = grub_util_path_concat_ext (4, locale_dir,
+ install_locales.entries[i],
+ "LC_MESSAGES", PACKAGE, ".mo");
+@@ -867,6 +888,8 @@ grub_install_copy_nls(const char *src __attribute__ ((unused)),
+ free (srcf);
+ free (dstf);
+ }
++
++ free (locale_langpack_dir);
+ }
+ free (dst_locale);
+ #endif
diff --git a/debian/patches/install-powerpc-machtypes.patch b/debian/patches/install-powerpc-machtypes.patch
new file mode 100644
index 0000000..385174f
--- /dev/null
+++ b/debian/patches/install-powerpc-machtypes.patch
@@ -0,0 +1,220 @@
+From 4b6f846398109576c218394c3d10bcb075c065a7 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Tue, 28 Jan 2014 14:40:02 +0000
+Subject: Port yaboot logic for various powerpc machine types
+
+Some powerpc machines require not updating the NVRAM. This can be handled
+by existing grub-install command-line options, but it's friendlier to detect
+this automatically.
+
+On chrp_ibm machines, use the nvram utility rather than nvsetenv. (This
+is possibly suitable for other machines too, but that needs to be
+verified.)
+
+Forwarded: no
+Last-Update: 2014-10-15
+
+Patch-Name: install-powerpc-machtypes.patch
+---
+ grub-core/osdep/basic/platform.c | 5 +++
+ grub-core/osdep/linux/platform.c | 72 ++++++++++++++++++++++++++++++
+ grub-core/osdep/unix/platform.c | 28 +++++++++---
+ grub-core/osdep/windows/platform.c | 6 +++
+ include/grub/util/install.h | 3 ++
+ util/grub-install.c | 11 +++++
+ 6 files changed, 119 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/osdep/basic/platform.c b/grub-core/osdep/basic/platform.c
+index a7dafd85a..6c293ed2d 100644
+--- a/grub-core/osdep/basic/platform.c
++++ b/grub-core/osdep/basic/platform.c
+@@ -30,3 +30,8 @@ grub_install_get_default_x86_platform (void)
+ return "i386-pc";
+ }
+
++const char *
++grub_install_get_default_powerpc_machtype (void)
++{
++ return "generic";
++}
+diff --git a/grub-core/osdep/linux/platform.c b/grub-core/osdep/linux/platform.c
+index 2e7f72086..5b37366d4 100644
+--- a/grub-core/osdep/linux/platform.c
++++ b/grub-core/osdep/linux/platform.c
+@@ -24,6 +24,7 @@
+ #include <grub/emu/misc.h>
+ #include <sys/types.h>
+ #include <dirent.h>
++#include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+@@ -184,3 +185,74 @@ grub_install_get_default_x86_platform (void)
+ grub_util_info ("... not found");
+ return "i386-pc";
+ }
++
++const char *
++grub_install_get_default_powerpc_machtype (void)
++{
++ FILE *fp;
++ char *buf = NULL;
++ size_t len = 0;
++ const char *machtype = "generic";
++
++ fp = grub_util_fopen ("/proc/cpuinfo", "r");
++ if (! fp)
++ return machtype;
++
++ while (getline (&buf, &len, fp) > 0)
++ {
++ if (strncmp (buf, "pmac-generation",
++ sizeof ("pmac-generation") - 1) == 0)
++ {
++ if (strstr (buf, "NewWorld"))
++ {
++ machtype = "pmac_newworld";
++ break;
++ }
++ if (strstr (buf, "OldWorld"))
++ {
++ machtype = "pmac_oldworld";
++ break;
++ }
++ }
++
++ if (strncmp (buf, "motherboard", sizeof ("motherboard") - 1) == 0 &&
++ strstr (buf, "AAPL"))
++ {
++ machtype = "pmac_oldworld";
++ break;
++ }
++
++ if (strncmp (buf, "machine", sizeof ("machine") - 1) == 0 &&
++ strstr (buf, "CHRP IBM"))
++ {
++ if (strstr (buf, "qemu"))
++ {
++ machtype = "chrp_ibm_qemu";
++ break;
++ }
++ else
++ {
++ machtype = "chrp_ibm";
++ break;
++ }
++ }
++
++ if (strncmp (buf, "platform", sizeof ("platform") - 1) == 0)
++ {
++ if (strstr (buf, "Maple"))
++ {
++ machtype = "maple";
++ break;
++ }
++ if (strstr (buf, "Cell"))
++ {
++ machtype = "cell";
++ break;
++ }
++ }
++ }
++
++ free (buf);
++ fclose (fp);
++ return machtype;
++}
+diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c
+index 55b8f4016..9c439326a 100644
+--- a/grub-core/osdep/unix/platform.c
++++ b/grub-core/osdep/unix/platform.c
+@@ -218,13 +218,29 @@ grub_install_register_ieee1275 (int is_prep, const char *install_device,
+ else
+ boot_device = get_ofpathname (install_device);
+
+- if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device",
+- boot_device, NULL }))
++ if (strcmp (grub_install_get_default_powerpc_machtype (), "chrp_ibm") == 0)
+ {
+- char *cmd = xasprintf ("setenv boot-device %s", boot_device);
+- grub_util_error (_("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"),
+- cmd);
+- free (cmd);
++ char *arg = xasprintf ("boot-device=%s", boot_device);
++ if (grub_util_exec ((const char * []){ "nvram",
++ "--update-config", arg, NULL }))
++ {
++ char *cmd = xasprintf ("setenv boot-device %s", boot_device);
++ grub_util_error (_("`nvram' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"),
++ cmd);
++ free (cmd);
++ }
++ free (arg);
++ }
++ else
++ {
++ if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device",
++ boot_device, NULL }))
++ {
++ char *cmd = xasprintf ("setenv boot-device %s", boot_device);
++ grub_util_error (_("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"),
++ cmd);
++ free (cmd);
++ }
+ }
+
+ free (boot_device);
+diff --git a/grub-core/osdep/windows/platform.c b/grub-core/osdep/windows/platform.c
+index 253f8d101..d18488f20 100644
+--- a/grub-core/osdep/windows/platform.c
++++ b/grub-core/osdep/windows/platform.c
+@@ -128,6 +128,12 @@ grub_install_get_default_x86_platform (void)
+ return "i386-efi";
+ }
+
++const char *
++grub_install_get_default_powerpc_machtype (void)
++{
++ return "generic";
++}
++
+ static void *
+ get_efi_variable (const wchar_t *varname, ssize_t *len)
+ {
+diff --git a/include/grub/util/install.h b/include/grub/util/install.h
+index 7df3191f4..135ba48d2 100644
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -223,6 +223,9 @@ grub_install_get_default_arm_platform (void);
+ const char *
+ grub_install_get_default_x86_platform (void);
+
++const char *
++grub_install_get_default_powerpc_machtype (void);
++
+ int
+ grub_install_register_efi (grub_device_t efidir_grub_dev,
+ const char *efifile_path,
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 48c8c0364..d02bd488a 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1187,7 +1187,18 @@ main (int argc, char *argv[])
+
+ if (platform == GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
+ {
++ const char *machtype = grub_install_get_default_powerpc_machtype ();
+ int is_guess = 0;
++
++ if (strcmp (machtype, "pmac_oldworld") == 0)
++ update_nvram = 0;
++ else if (strcmp (machtype, "cell") == 0)
++ update_nvram = 0;
++ else if (strcmp (machtype, "generic") == 0)
++ update_nvram = 0;
++ else if (strcmp (machtype, "chrp_ibm_qemu") == 0)
++ update_nvram = 0;
++
+ if (!macppcdir)
+ {
+ char *d;
diff --git a/debian/patches/install-signed.patch b/debian/patches/install-signed.patch
new file mode 100644
index 0000000..62f315f
--- /dev/null
+++ b/debian/patches/install-signed.patch
@@ -0,0 +1,309 @@
+From 0bd31f4c7468f0b42ff6673f47112b9167c6381c Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:22 +0000
+Subject: Install signed images if UEFI Secure Boot is enabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Author: Stéphane Graber <stgraber@ubuntu.com>
+Author: Steve Langasek <steve.langasek@ubuntu.com>
+Author: Linn Crosetto <linn@hpe.com>
+Author: Mathieu Trudel-Lapierre <cyphermox@ubuntu.com>
+Forwarded: no
+Last-Update: 2023-01-15
+
+Patch-Name: install-signed.patch
+---
+ util/grub-install.c | 212 ++++++++++++++++++++++++++++++++------------
+ 1 file changed, 153 insertions(+), 59 deletions(-)
+
+Index: grub.git/util/grub-install.c
+===================================================================
+--- grub.git.orig/util/grub-install.c
++++ grub.git/util/grub-install.c
+@@ -79,6 +79,7 @@ static char *label_color;
+ static char *label_bgcolor;
+ static char *product_version;
+ static int add_rs_codes = 1;
++static int uefi_secure_boot = 1;
+
+ enum
+ {
+@@ -109,7 +110,9 @@ enum
+ OPTION_LABEL_FONT,
+ OPTION_LABEL_COLOR,
+ OPTION_LABEL_BGCOLOR,
+- OPTION_PRODUCT_VERSION
++ OPTION_PRODUCT_VERSION,
++ OPTION_UEFI_SECURE_BOOT,
++ OPTION_NO_UEFI_SECURE_BOOT
+ };
+
+ static int fs_probe = 1;
+@@ -233,6 +236,14 @@ argp_parser (int key, char *arg, struct
+ bootloader_id = xstrdup (arg);
+ return 0;
+
++ case OPTION_UEFI_SECURE_BOOT:
++ uefi_secure_boot = 1;
++ return 0;
++
++ case OPTION_NO_UEFI_SECURE_BOOT:
++ uefi_secure_boot = 0;
++ return 0;
++
+ case ARGP_KEY_ARG:
+ if (install_device)
+ grub_util_error ("%s", _("More than one install device?"));
+@@ -302,6 +313,14 @@ static struct argp_option options[] = {
+ {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2},
+ {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2},
+ {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2},
++ {"uefi-secure-boot", OPTION_UEFI_SECURE_BOOT, 0, 0,
++ N_("install an image usable with UEFI Secure Boot. "
++ "This option is only available on EFI and if the grub-efi-amd64-signed "
++ "package is installed."), 2},
++ {"no-uefi-secure-boot", OPTION_NO_UEFI_SECURE_BOOT, 0, 0,
++ N_("do not install an image usable with UEFI Secure Boot, even if the "
++ "system was currently started using it. "
++ "This option is only available on EFI."), 2},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+@@ -832,7 +851,8 @@ main (int argc, char *argv[])
+ {
+ int is_efi = 0;
+ const char *efi_distributor = NULL;
+- const char *efi_file = NULL;
++ const char *efi_suffix = NULL, *efi_suffix_upper = NULL;
++ char *efi_file = NULL;
+ char **grub_devices;
+ grub_fs_t grub_fs;
+ grub_device_t grub_dev = NULL;
+@@ -1102,6 +1122,39 @@ main (int argc, char *argv[])
+ */
+ char *t;
+ efi_distributor = bootloader_id;
++ switch (platform)
++ {
++ case GRUB_INSTALL_PLATFORM_I386_EFI:
++ efi_suffix = "ia32";
++ efi_suffix_upper = "IA32";
++ break;
++ case GRUB_INSTALL_PLATFORM_X86_64_EFI:
++ efi_suffix = "x64";
++ efi_suffix_upper = "X64";
++ break;
++ case GRUB_INSTALL_PLATFORM_IA64_EFI:
++ efi_suffix = "ia64";
++ efi_suffix_upper = "IA64";
++ break;
++ case GRUB_INSTALL_PLATFORM_ARM_EFI:
++ efi_suffix = "arm";
++ efi_suffix_upper = "ARM";
++ break;
++ case GRUB_INSTALL_PLATFORM_ARM64_EFI:
++ efi_suffix = "aa64";
++ efi_suffix_upper = "AA64";
++ break;
++ case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
++ efi_suffix = "riscv32";
++ efi_suffix_upper = "RISCV32";
++ break;
++ case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
++ efi_suffix = "riscv64";
++ efi_suffix_upper = "RISCV64";
++ break;
++ default:
++ break;
++ }
+ if (removable)
+ {
+ /* The specification makes stricter requirements of removable
+@@ -1110,66 +1163,16 @@ main (int argc, char *argv[])
+ must have a specific file name depending on the architecture.
+ */
+ efi_distributor = "BOOT";
+- switch (platform)
+- {
+- case GRUB_INSTALL_PLATFORM_I386_EFI:
+- efi_file = "BOOTIA32.EFI";
+- break;
+- case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+- efi_file = "BOOTX64.EFI";
+- break;
+- case GRUB_INSTALL_PLATFORM_IA64_EFI:
+- efi_file = "BOOTIA64.EFI";
+- break;
+- case GRUB_INSTALL_PLATFORM_ARM_EFI:
+- efi_file = "BOOTARM.EFI";
+- break;
+- case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+- efi_file = "BOOTAA64.EFI";
+- break;
+- case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
+- efi_file = "BOOTRISCV32.EFI";
+- break;
+- case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+- efi_file = "BOOTRISCV64.EFI";
+- break;
+- default:
+- grub_util_error ("%s", _("You've found a bug"));
+- break;
+- }
++ if (!efi_suffix)
++ grub_util_error ("%s", _("You've found a bug"));
++ efi_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper);
+ }
+ else
+ {
+ /* It is convenient for each architecture to have a different
+ efi_file, so that different versions can be installed in parallel.
+ */
+- switch (platform)
+- {
+- case GRUB_INSTALL_PLATFORM_I386_EFI:
+- efi_file = "grubia32.efi";
+- break;
+- case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+- efi_file = "grubx64.efi";
+- break;
+- case GRUB_INSTALL_PLATFORM_IA64_EFI:
+- efi_file = "grubia64.efi";
+- break;
+- case GRUB_INSTALL_PLATFORM_ARM_EFI:
+- efi_file = "grubarm.efi";
+- break;
+- case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+- efi_file = "grubaa64.efi";
+- break;
+- case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
+- efi_file = "grubriscv32.efi";
+- break;
+- case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+- efi_file = "grubriscv64.efi";
+- break;
+- default:
+- efi_file = "grub.efi";
+- break;
+- }
++ efi_file = xasprintf ("grub%s.efi", efi_suffix);
+ }
+ t = grub_util_path_concat (3, efidir, "EFI", efi_distributor);
+ free (efidir);
+@@ -1375,14 +1378,38 @@ main (int argc, char *argv[])
+ }
+ }
+
+- if (!have_abstractions)
++ char *efi_signed = NULL;
++ switch (platform)
++ {
++ case GRUB_INSTALL_PLATFORM_I386_EFI:
++ case GRUB_INSTALL_PLATFORM_X86_64_EFI:
++ case GRUB_INSTALL_PLATFORM_ARM_EFI:
++ case GRUB_INSTALL_PLATFORM_ARM64_EFI:
++ case GRUB_INSTALL_PLATFORM_IA64_EFI:
++ {
++ char *dir = xasprintf ("%s-signed", grub_install_source_directory);
++ char *signed_image;
++ signed_image = xasprintf ("grub%s.efi.signed", efi_suffix);
++ efi_signed = grub_util_path_concat (2, dir, signed_image);
++ break;
++ }
++
++ default:
++ break;
++ }
++
++ if (!efi_signed || !grub_util_is_regular (efi_signed))
++ uefi_secure_boot = 0;
++
++ if (!have_abstractions || uefi_secure_boot)
+ {
+ if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0)
+ || grub_drives[1]
+ || (!install_drive
+ && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
+ || (install_drive && !is_same_disk (grub_drives[0], install_drive))
+- || !have_bootdev (platform))
++ || !have_bootdev (platform)
++ || uefi_secure_boot)
+ {
+ char *uuid = NULL;
+ /* generic method (used on coreboot and ata mod). */
+@@ -1927,7 +1957,72 @@ main (int argc, char *argv[])
+ case GRUB_INSTALL_PLATFORM_IA64_EFI:
+ {
+ char *dst = grub_util_path_concat (2, efidir, efi_file);
+- grub_install_copy_file (imgfile, dst, 1);
++ if (uefi_secure_boot)
++ {
++ char *shim_signed = NULL;
++ char *mok_signed = NULL, *mok_file = NULL;
++ char *fb_signed = NULL, *fb_file = NULL;
++ char *config_dst;
++ FILE *config_dst_f;
++
++ shim_signed = xasprintf ("/usr/lib/shim/shim%s.efi.signed", efi_suffix);
++ mok_signed = xasprintf ("mm%s.efi.signed", efi_suffix);
++ mok_file = xasprintf ("mm%s.efi", efi_suffix);
++ fb_signed = xasprintf ("fb%s.efi.signed", efi_suffix);
++ fb_file = xasprintf ("fb%s.efi", efi_suffix);
++
++ if (grub_util_is_regular (shim_signed))
++ {
++ char *chained_base, *chained_dst;
++ char *mok_src, *mok_dst, *fb_src, *fb_dst;
++ if (!removable)
++ {
++ free (efi_file);
++ efi_file = xasprintf ("shim%s.efi", efi_suffix);
++ free (dst);
++ dst = grub_util_path_concat (2, efidir, efi_file);
++ }
++ grub_install_copy_file (shim_signed, dst, 1);
++ chained_base = xasprintf ("grub%s.efi", efi_suffix);
++ chained_dst = grub_util_path_concat (2, efidir, chained_base);
++ grub_install_copy_file (efi_signed, chained_dst, 1);
++ free (chained_dst);
++ free (chained_base);
++
++ /* Not critical, so not an error if they are not present (as it
++ won't be for older releases); but if we have them, make
++ sure they are installed. */
++ mok_src = grub_util_path_concat (2, "/usr/lib/shim/",
++ mok_signed);
++ mok_dst = grub_util_path_concat (2, efidir,
++ mok_file);
++ grub_install_copy_file (mok_src,
++ mok_dst, 0);
++ free (mok_src);
++ free (mok_dst);
++
++ fb_src = grub_util_path_concat (2, "/usr/lib/shim/",
++ fb_signed);
++ fb_dst = grub_util_path_concat (2, efidir,
++ fb_file);
++ if (!removable)
++ grub_install_copy_file (fb_src,
++ fb_dst, 0);
++ free (fb_src);
++ free (fb_dst);
++ }
++ else
++ grub_install_copy_file (efi_signed, dst, 1);
++
++ config_dst = grub_util_path_concat (2, efidir, "grub.cfg");
++ grub_install_copy_file (load_cfg, config_dst, 1);
++ config_dst_f = grub_util_fopen (config_dst, "ab");
++ fprintf (config_dst_f, "configfile $prefix/grub.cfg\n");
++ fclose (config_dst_f);
++ free (config_dst);
++ }
++ else
++ grub_install_copy_file (imgfile, dst, 1);
+
+ grub_set_install_backup_ponr ();
+
diff --git a/debian/patches/install-stage2-confusion.patch b/debian/patches/install-stage2-confusion.patch
new file mode 100644
index 0000000..d7e60d3
--- /dev/null
+++ b/debian/patches/install-stage2-confusion.patch
@@ -0,0 +1,46 @@
+From 07ebcd8f769c2522b9a3a79c3d92082747f83781 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:12:58 +0000
+Subject: If GRUB Legacy is still around, tell packaging to ignore it
+
+Bug-Debian: http://bugs.debian.org/586143
+Forwarded: not-needed
+Last-Update: 2021-09-24
+
+Patch-Name: install-stage2-confusion.patch
+---
+ util/grub-install.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 0fbe7f78c..48e2d3779 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -42,6 +42,7 @@
+ #include <grub/emu/config.h>
+ #include <grub/util/ofpath.h>
+ #include <grub/hfsplus.h>
++#include <grub/emu/hostfile.h>
+
+ #include <string.h>
+
+@@ -1727,6 +1728,19 @@ main (int argc, char *argv[])
+
+ grub_set_install_backup_ponr ();
+ }
++
++ /* If vestiges of GRUB Legacy still exist, tell the Debian packaging
++ that they can ignore them. */
++ if (!rootdir && grub_util_is_regular ("/boot/grub/stage2") &&
++ grub_util_is_regular ("/boot/grub/menu.lst"))
++ {
++ grub_util_fd_t fd;
++
++ fd = grub_util_fd_open ("/boot/grub/grub2-installed",
++ GRUB_UTIL_FD_O_WRONLY);
++ grub_util_fd_close (fd);
++ }
++
+ break;
+ }
+ case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
diff --git a/debian/patches/kern-file-Fix-error-handling-in-grub_file_open.patch b/debian/patches/kern-file-Fix-error-handling-in-grub_file_open.patch
new file mode 100644
index 0000000..d64c88e
--- /dev/null
+++ b/debian/patches/kern-file-Fix-error-handling-in-grub_file_open.patch
@@ -0,0 +1,37 @@
+From aee575ddefd35f0fd6592171ae48ab6a4bb27464 Mon Sep 17 00:00:00 2001
+From: Steve McIntyre <steve@einval.com>
+Date: Mon, 5 Dec 2022 23:14:10 +0000
+Subject: [PATCH] kern/file: Fix error handling in grub_file_open()
+
+grub_file_open() calls grub_file_get_device_name(), but doesn't check
+the return. Instead, it checks if grub_errno is set.
+
+However, nothing initialises grub_errno here when grub_file_open()
+starts. This means that trying to open one file that doesn't exist and
+then trying to open another file that does will (incorrectly) also
+fail to open that second file.
+
+Let's fix that.
+
+Signed-off-by: Steve McIntyre <steve@einval.com>
+---
+ grub-core/kern/file.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
+index 8d48fd50d..668b149c3 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -66,6 +66,9 @@ grub_file_open (const char *name, enum grub_file_type type)
+ const char *file_name;
+ grub_file_filter_id_t filter;
+
++ /* Reset grub_errno before we start */
++ grub_errno = GRUB_ERR_NONE;
++
+ device_name = grub_file_get_device_name (name);
+ if (grub_errno)
+ goto fail;
+--
+2.30.2
+
diff --git a/debian/patches/linuxefi.patch b/debian/patches/linuxefi.patch
new file mode 100644
index 0000000..20fe4de
--- /dev/null
+++ b/debian/patches/linuxefi.patch
@@ -0,0 +1,552 @@
+From fc550c31c25dcf9eb58ca1e987f3ce2be8ebac28 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Mon, 13 Jan 2014 12:13:15 +0000
+Subject: Add "linuxefi" loader which avoids ExitBootServices
+
+Origin: vendor, http://pkgs.fedoraproject.org/cgit/grub2.git/tree/grub2-linuxefi.patch
+Author: Colin Watson <cjwatson@ubuntu.com>
+Author: Steve Langasek <steve.langasek@canonical.com>
+Author: Linn Crosetto <linn@hpe.com>
+Forwarded: no
+Last-Update: 2021-09-24
+
+Patch-Name: linuxefi.patch
+---
+ grub-core/Makefile.core.def | 7 +
+ grub-core/kern/efi/mm.c | 32 +++
+ grub-core/loader/i386/efi/linux.c | 383 ++++++++++++++++++++++++++++++
+ grub-core/loader/i386/linux.c | 41 ++++
+ include/grub/efi/efi.h | 3 +
+ 5 files changed, 466 insertions(+)
+ create mode 100644 grub-core/loader/i386/efi/linux.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 8022e1c0a..e5b3d27f5 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1874,6 +1874,13 @@ module = {
+ enable = x86_64_efi;
+ };
+
++module = {
++ name = linuxefi;
++ efi = loader/i386/efi/linux.c;
++ enable = i386_efi;
++ enable = x86_64_efi;
++};
++
+ module = {
+ name = chain;
+ efi = loader/efi/chainloader.c;
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 9838fb2f5..f6aef0ef6 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -113,6 +113,38 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address,
+ }
+ }
+
++/* Allocate pages below a specified address */
++void *
++grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
++ grub_efi_uintn_t pages)
++{
++ grub_efi_status_t status;
++ grub_efi_boot_services_t *b;
++ grub_efi_physical_address_t address = max;
++
++ if (max > 0xffffffff)
++ return 0;
++
++ b = grub_efi_system_table->boot_services;
++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
++
++ if (status != GRUB_EFI_SUCCESS)
++ return 0;
++
++ if (address == 0)
++ {
++ /* Uggh, the address 0 was allocated... This is too annoying,
++ so reallocate another one. */
++ address = max;
++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
++ grub_efi_free_pages (0, pages);
++ if (status != GRUB_EFI_SUCCESS)
++ return 0;
++ }
++
++ return (void *) ((grub_addr_t) address);
++}
++
+ /* Allocate pages. Return the pointer to the first of allocated pages. */
+ void *
+ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+new file mode 100644
+index 000000000..45b68c05a
+--- /dev/null
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -0,0 +1,383 @@
++/*
++ * 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 <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/loader.h>
++#include <grub/file.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include <grub/mm.h>
++#include <grub/cpu/linux.h>
++#include <grub/command.h>
++#include <grub/i18n.h>
++#include <grub/lib/cmdline.h>
++#include <grub/linux.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/sb.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_dl_t my_mod;
++static int loaded;
++static void *kernel_mem;
++static grub_uint64_t kernel_size;
++static grub_uint8_t *initrd_mem;
++static grub_uint32_t handover_offset;
++struct linux_kernel_params *params;
++static char *linux_cmdline;
++
++#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12)
++
++#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;
++
++static grub_efi_boolean_t
++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;
++
++ if (grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED)
++ {
++ grub_dprintf ("linuxefi", "secure boot not enabled, not validating");
++ return 1;
++ }
++
++ grub_dprintf ("linuxefi", "Locating shim protocol\n");
++ shim_lock = grub_efi_locate_protocol(&guid, NULL);
++
++ if (!shim_lock)
++ {
++ grub_dprintf ("linuxefi", "shim not available\n");
++ return 0;
++ }
++
++ grub_dprintf ("linuxefi", "Asking shim to verify kernel signature\n");
++ status = shim_lock->verify(data, size);
++ if (status == GRUB_EFI_SUCCESS)
++ {
++ grub_dprintf ("linuxefi", "Kernel signature verification passed\n");
++ return 1;
++ }
++
++ grub_dprintf ("linuxefi", "Kernel signature verification failed (0x%lx)\n",
++ (unsigned long) status);
++ return 0;
++}
++
++typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *);
++
++static grub_err_t
++grub_linuxefi_boot (void)
++{
++ handover_func hf;
++ int offset = 0;
++
++#ifdef __x86_64__
++ offset = 512;
++#endif
++
++ hf = (handover_func)((char *)kernel_mem + handover_offset + offset);
++
++ asm volatile ("cli");
++
++ hf (grub_efi_image_handle, grub_efi_system_table, params);
++
++ /* Not reached */
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_linuxefi_unload (void)
++{
++ grub_dl_unref (my_mod);
++ loaded = 0;
++ if (initrd_mem)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size));
++ if (linux_cmdline)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1));
++ if (kernel_mem)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
++ if (params)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384));
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_size_t size = 0;
++ struct grub_linux_initrd_context initrd_ctx;
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++ goto fail;
++ }
++
++ if (!loaded)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
++ goto fail;
++ }
++
++ if (grub_initrd_init (argc, argv, &initrd_ctx))
++ goto fail;
++
++ size = grub_get_initrd_size (&initrd_ctx);
++
++ initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
++
++ if (!initrd_mem)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
++ goto fail;
++ }
++
++ grub_dprintf ("linuxefi", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
++
++ params->ramdisk_size = size;
++ params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
++
++ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
++ goto fail;
++
++ params->ramdisk_size = size;
++
++ fail:
++ grub_initrd_close (&initrd_ctx);
++
++ if (initrd_mem && grub_errno)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(size));
++
++ return grub_errno;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_file_t file = 0;
++ struct linux_i386_kernel_header lh;
++ grub_ssize_t len, start, filelen;
++ void *kernel;
++
++ grub_dl_ref (my_mod);
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++ goto fail;
++ }
++
++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
++ if (! file)
++ goto fail;
++
++ filelen = grub_file_size (file);
++
++ kernel = grub_malloc(filelen);
++
++ if (!kernel)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
++ goto fail;
++ }
++
++ if (grub_file_read (file, kernel, filelen) != filelen)
++ {
++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
++ goto fail;
++ }
++
++ if (! grub_linuxefi_secure_validate (kernel, filelen))
++ {
++ grub_error (GRUB_ERR_ACCESS_DENIED, N_("%s has invalid signature"), argv[0]);
++ grub_free (kernel);
++ goto fail;
++ }
++
++ grub_file_seek (file, 0);
++
++ grub_free(kernel);
++
++ params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));
++
++ if (! params)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
++ goto fail;
++ }
++
++ grub_dprintf ("linuxefi", "params = %lx\n", (unsigned long) params);
++
++ grub_memset (params, 0, 16384);
++
++ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
++ {
++ if (!grub_errno)
++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
++ argv[0]);
++ goto fail;
++ }
++
++ if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
++ {
++ grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
++ goto fail;
++ }
++
++ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
++ {
++ grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
++ goto fail;
++ }
++
++ if (lh.version < grub_cpu_to_le16 (0x020b))
++ {
++ grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
++ goto fail;
++ }
++
++ if (!lh.handover_offset)
++ {
++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
++ goto fail;
++ }
++
++ linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
++ BYTES_TO_PAGES(lh.cmdline_size + 1));
++
++ if (!linux_cmdline)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
++ goto fail;
++ }
++
++ grub_dprintf ("linuxefi", "linux_cmdline = %lx\n",
++ (unsigned long) linux_cmdline);
++
++ grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
++ {
++ grub_err_t err;
++ err = grub_create_loader_cmdline (argc, argv,
++ linux_cmdline
++ + sizeof (LINUX_IMAGE) - 1,
++ lh.cmdline_size
++ - (sizeof (LINUX_IMAGE) - 1),
++ GRUB_VERIFY_KERNEL_CMDLINE);
++ if (err)
++ goto fail;
++ }
++
++ lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
++
++ handover_offset = lh.handover_offset;
++
++ start = (lh.setup_sects + 1) * 512;
++ len = grub_file_size(file) - start;
++
++ kernel_mem = grub_efi_allocate_fixed(lh.pref_address,
++ BYTES_TO_PAGES(lh.init_size));
++
++ if (!kernel_mem)
++ kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
++ BYTES_TO_PAGES(lh.init_size));
++
++ if (!kernel_mem)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
++ goto fail;
++ }
++ grub_errno = GRUB_ERR_NONE;
++
++ grub_dprintf ("linuxefi", "kernel_mem = %lx\n", (unsigned long) kernel_mem);
++
++ if (grub_file_seek (file, start) == (grub_off_t) -1)
++ {
++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
++ argv[0]);
++ goto fail;
++ }
++
++ if (grub_file_read (file, kernel_mem, len) != len && !grub_errno)
++ {
++ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
++ argv[0]);
++ }
++
++ if (grub_errno == GRUB_ERR_NONE)
++ {
++ grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
++ loaded = 1;
++ lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
++ }
++
++ grub_memcpy (params, &lh, 2 * 512);
++
++ params->type_of_loader = 0x21;
++
++ fail:
++
++ if (file)
++ grub_file_close (file);
++
++ if (grub_errno != GRUB_ERR_NONE)
++ {
++ grub_dl_unref (my_mod);
++ loaded = 0;
++ }
++
++ if (linux_cmdline && !loaded)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1));
++
++ if (kernel_mem && !loaded)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
++
++ if (params && !loaded)
++ grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384));
++
++ return grub_errno;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++
++GRUB_MOD_INIT(linuxefi)
++{
++ cmd_linux =
++ grub_register_command ("linuxefi", grub_cmd_linux,
++ 0, N_("Load Linux."));
++ cmd_initrd =
++ grub_register_command ("initrdefi", grub_cmd_initrd,
++ 0, N_("Load initrd."));
++ my_mod = mod;
++}
++
++GRUB_MOD_FINI(linuxefi)
++{
++ grub_unregister_command (cmd_linux);
++ grub_unregister_command (cmd_initrd);
++}
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 9f74a96b1..be37a1640 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -78,6 +78,8 @@ static grub_size_t maximal_cmdline_size;
+ static struct linux_kernel_params linux_params;
+ static char *linux_cmdline;
+ #ifdef GRUB_MACHINE_EFI
++static int using_linuxefi;
++static grub_command_t initrdefi_cmd;
+ static grub_efi_uintn_t efi_mmap_size;
+ #else
+ static const grub_size_t efi_mmap_size = 0;
+@@ -659,6 +661,39 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+
+ grub_dl_ref (my_mod);
+
++#ifdef GRUB_MACHINE_EFI
++ using_linuxefi = 0;
++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
++ {
++ /* linuxefi requires a successful signature check and then hand over
++ to the kernel without calling ExitBootServices. */
++ grub_dl_t mod;
++ grub_command_t linuxefi_cmd;
++
++ grub_dprintf ("linux", "Secure Boot enabled: trying linuxefi\n");
++
++ mod = grub_dl_load ("linuxefi");
++ if (mod)
++ {
++ grub_dl_ref (mod);
++ linuxefi_cmd = grub_command_find ("linuxefi");
++ initrdefi_cmd = grub_command_find ("initrdefi");
++ if (linuxefi_cmd && initrdefi_cmd)
++ {
++ (linuxefi_cmd->func) (linuxefi_cmd, argc, argv);
++ if (grub_errno == GRUB_ERR_NONE)
++ {
++ grub_dprintf ("linux", "Handing off to linuxefi\n");
++ using_linuxefi = 1;
++ return GRUB_ERR_NONE;
++ }
++ grub_dprintf ("linux", "linuxefi failed (%d)\n", grub_errno);
++ goto fail;
++ }
++ }
++ }
++#endif
++
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+@@ -1042,6 +1077,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ grub_err_t err;
+ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
+
++#ifdef GRUB_MACHINE_EFI
++ /* If we're using linuxefi, just forward to initrdefi. */
++ if (using_linuxefi && initrdefi_cmd)
++ return (initrdefi_cmd->func) (initrdefi_cmd, argc, argv);
++#endif
++
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 83d958f99..08f6ee00a 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -47,6 +47,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address,
+ grub_efi_uintn_t pages);
+ void *
+ EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages);
++void *
++EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max,
++ grub_efi_uintn_t pages);
+ void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
+ grub_efi_uintn_t pages);
+ grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void);
diff --git a/debian/patches/maybe-quiet.patch b/debian/patches/maybe-quiet.patch
new file mode 100644
index 0000000..33d1e0f
--- /dev/null
+++ b/debian/patches/maybe-quiet.patch
@@ -0,0 +1,386 @@
+From 0b33def5d9ace3488fa612e09a5bb813c5e3cd90 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:26 +0000
+Subject: Add configure option to reduce visual clutter at boot time
+
+If this option is enabled, then do all of the following:
+
+Don't display introductory message about line editing unless we're
+actually offering a shell prompt. (This is believed to be a workaround
+for a different bug. We'll go with this for now, but will drop this in
+favour of a better fix upstream if somebody figures out what that is.)
+
+Don't clear the screen just before booting if we never drew the menu in
+the first place.
+
+Remove verbose messages printed before reading configuration. In some
+ways this is awkward because it makes debugging harder, but it's a
+requirement for a smooth-looking boot process; we may be able to do
+better in future. Upstream doesn't want this, though.
+
+Disable the cursor as well, for similar reasons of tidiness.
+
+Suppress kernel/initrd progress messages, except in recovery mode.
+
+Suppress "GRUB loading" message unless Shift is held down. Upstream
+doesn't want this, as it makes debugging harder. Ubuntu wants it to
+provide a cleaner boot experience.
+
+Author: Will Thompson <will@willthompson.co.uk>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/386922
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/861048
+Forwarded: (partial) http://lists.gnu.org/archive/html/grub-devel/2009-09/msg00056.html
+Last-Update: 2021-09-24
+
+Patch-Name: maybe-quiet.patch
+---
+ config.h.in | 2 ++
+ configure.ac | 16 ++++++++++++++++
+ grub-core/boot/i386/pc/boot.S | 11 +++++++++++
+ grub-core/boot/i386/pc/diskboot.S | 26 ++++++++++++++++++++++++++
+ grub-core/kern/main.c | 17 +++++++++++++++++
+ grub-core/kern/rescue_reader.c | 2 ++
+ grub-core/normal/main.c | 11 +++++++++++
+ grub-core/normal/menu.c | 17 +++++++++++++++--
+ util/grub.d/10_linux.in | 15 +++++++++++----
+ 9 files changed, 111 insertions(+), 6 deletions(-)
+
+diff --git a/config.h.in b/config.h.in
+index 9e8f9911b..d2c4ce8e5 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -12,6 +12,8 @@
+ /* Define to 1 to enable disk cache statistics. */
+ #define DISK_CACHE_STATS @DISK_CACHE_STATS@
+ #define BOOT_TIME_STATS @BOOT_TIME_STATS@
++/* Define to 1 to make GRUB quieter at boot time. */
++#define QUIET_BOOT @QUIET_BOOT@
+
+ /* We don't need those. */
+ #define MINILZO_CFG_SKIP_LZO_PTR 1
+diff --git a/configure.ac b/configure.ac
+index 74778a6f8..256fc44ef 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1915,6 +1915,17 @@ else
+ fi
+ AC_SUBST([UBUNTU_RECOVERY])
+
++AC_ARG_ENABLE([quiet-boot],
++ [AS_HELP_STRING([--enable-quiet-boot],
++ [emit fewer messages at boot time (default=no)])],
++ [], [enable_quiet_boot=no])
++if test x"$enable_quiet_boot" = xyes ; then
++ QUIET_BOOT=1
++else
++ QUIET_BOOT=0
++fi
++AC_SUBST([QUIET_BOOT])
++
+ LIBS=""
+
+ AC_SUBST([FONT_SOURCE])
+@@ -2177,5 +2188,10 @@ echo "With stack smashing protector: Yes"
+ else
+ echo "With stack smashing protector: No"
+ fi
++if [ x"$enable_quiet_boot" = xyes ]; then
++echo With quiet boot: Yes
++else
++echo With quiet boot: No
++fi
+ echo "*******************************************************"
+ ]
+diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S
+index 2bd0b2d28..b0c0f2225 100644
+--- a/grub-core/boot/i386/pc/boot.S
++++ b/grub-core/boot/i386/pc/boot.S
+@@ -19,6 +19,9 @@
+
+ #include <grub/symbol.h>
+ #include <grub/machine/boot.h>
++#if QUIET_BOOT && !defined(HYBRID_BOOT)
++#include <grub/machine/memory.h>
++#endif
+
+ /*
+ * defines for the code go here
+@@ -249,9 +252,17 @@ real_start:
+ /* save drive reference first thing! */
+ pushw %dx
+
++#if QUIET_BOOT && !defined(HYBRID_BOOT)
++ /* is either shift key held down? */
++ movw $(GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR + 0x17), %bx
++ testb $3, (%bx)
++ jz 2f
++#endif
++
+ /* print a notification message on the screen */
+ MSG(notification_string)
+
++2:
+ /* set %si to the disk address packet */
+ movw $disk_address_packet, %si
+
+diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S
+index c1addc0df..9b6d7a7ed 100644
+--- a/grub-core/boot/i386/pc/diskboot.S
++++ b/grub-core/boot/i386/pc/diskboot.S
+@@ -18,6 +18,9 @@
+
+ #include <grub/symbol.h>
+ #include <grub/machine/boot.h>
++#if QUIET_BOOT
++#include <grub/machine/memory.h>
++#endif
+
+ /*
+ * defines for the code go here
+@@ -25,6 +28,12 @@
+
+ #define MSG(x) movw $x, %si; call LOCAL(message)
+
++#if QUIET_BOOT
++#define SILENT(x) call LOCAL(check_silent); jz LOCAL(x)
++#else
++#define SILENT(x)
++#endif
++
+ .file "diskboot.S"
+
+ .text
+@@ -50,11 +59,14 @@ _start:
+ /* save drive reference first thing! */
+ pushw %dx
+
++ SILENT(after_notification_string)
++
+ /* print a notification message on the screen */
+ pushw %si
+ MSG(notification_string)
+ popw %si
+
++LOCAL(after_notification_string):
+ /* this sets up for the first run through "bootloop" */
+ movw $LOCAL(firstlist), %di
+
+@@ -279,7 +291,10 @@ LOCAL(copy_buffer):
+ /* restore addressing regs and print a dot with correct DS
+ (MSG modifies SI, which is saved, and unused AX and BX) */
+ popw %ds
++ SILENT(after_notification_step)
+ MSG(notification_step)
++
++LOCAL(after_notification_step):
+ popa
+
+ /* check if finished with this dataset */
+@@ -295,8 +310,11 @@ LOCAL(copy_buffer):
+ /* END OF MAIN LOOP */
+
+ LOCAL(bootit):
++ SILENT(after_notification_done)
+ /* print a newline */
+ MSG(notification_done)
++
++LOCAL(after_notification_done):
+ popw %dx /* this makes sure %dl is our "boot" drive */
+ ljmp $0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
+
+@@ -320,6 +338,14 @@ LOCAL(general_error):
+ /* go here when you need to stop the machine hard after an error condition */
+ LOCAL(stop): jmp LOCAL(stop)
+
++#if QUIET_BOOT
++LOCAL(check_silent):
++ /* is either shift key held down? */
++ movw $(GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR + 0x17), %bx
++ testb $3, (%bx)
++ ret
++#endif
++
+ notification_string: .asciz "loading"
+
+ notification_step: .asciz "."
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index 73967e2f5..2879d644a 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -265,15 +265,25 @@ reclaim_module_space (void)
+ void __attribute__ ((noreturn))
+ grub_main (void)
+ {
++#if QUIET_BOOT
++ struct grub_term_output *term;
++#endif
++
+ /* First of all, initialize the machine. */
+ grub_machine_init ();
+
+ grub_boot_time ("After machine init.");
+
++#if QUIET_BOOT
++ /* Disable the cursor until we need it. */
++ FOR_ACTIVE_TERM_OUTPUTS(term)
++ grub_term_setcursor (term, 0);
++#else
+ /* 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 ();
+@@ -312,5 +322,12 @@ grub_main (void)
+ grub_boot_time ("After execution of embedded config. Attempt to go to normal mode");
+
+ grub_load_normal_mode ();
++
++#if QUIET_BOOT
++ /* If we have to enter rescue mode, enable the cursor again. */
++ FOR_ACTIVE_TERM_OUTPUTS(term)
++ grub_term_setcursor (term, 1);
++#endif
++
+ grub_rescue_run ();
+ }
+diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c
+index dcd7d4439..a93524eab 100644
+--- a/grub-core/kern/rescue_reader.c
++++ b/grub-core/kern/rescue_reader.c
+@@ -78,7 +78,9 @@ grub_rescue_read_line (char **line, int cont,
+ void __attribute__ ((noreturn))
+ grub_rescue_run (void)
+ {
++#if QUIET_BOOT
+ grub_printf ("Entering rescue mode...\n");
++#endif
+
+ while (1)
+ {
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index c4ebe9e22..a1750e09c 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -407,6 +407,15 @@ static grub_err_t
+ grub_normal_read_line_real (char **line, int cont, int nested)
+ {
+ const char *prompt;
++#if QUIET_BOOT
++ static int displayed_intro;
++
++ if (! displayed_intro)
++ {
++ grub_normal_reader_init (nested);
++ displayed_intro = 1;
++ }
++#endif
+
+ if (cont)
+ /* TRANSLATORS: it's command line prompt. */
+@@ -459,7 +468,9 @@ grub_cmdline_run (int nested, int force_auth)
+ return;
+ }
+
++#if !QUIET_BOOT
+ grub_normal_reader_init (nested);
++#endif
+
+ while (1)
+ {
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index 8397886fa..e9d8444b5 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -807,12 +807,18 @@ 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,
++notify_booting (grub_menu_entry_t entry
++#if QUIET_BOOT
++ __attribute__((unused))
++#endif
++ ,
+ void *userdata __attribute__((unused)))
+ {
++#if !QUIET_BOOT
+ grub_printf (" ");
+ grub_printf_ (N_("Booting `%s'"), entry->title);
+ grub_printf ("\n\n");
++#endif
+ }
+
+ /* Callback invoked when a default menu entry executed because of a timeout
+@@ -860,6 +866,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
+ int boot_entry;
+ grub_menu_entry_t e;
+ int auto_boot;
++#if QUIET_BOOT
++ int initial_timeout = grub_menu_get_timeout ();
++#endif
+
+ boot_entry = run_menu (menu, nested, &auto_boot);
+ if (boot_entry < 0)
+@@ -869,7 +878,11 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
+ if (! e)
+ continue; /* Menu is empty. */
+
+- grub_cls ();
++#if QUIET_BOOT
++ /* Only clear the screen if we drew the menu in the first place. */
++ if (initial_timeout != 0)
++#endif
++ grub_cls ();
+
+ if (auto_boot)
+ grub_menu_execute_with_fallback (menu, e, autobooted,
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 1b8c6e146..869a7eec5 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -21,6 +21,7 @@ prefix="@prefix@"
+ exec_prefix="@exec_prefix@"
+ datarootdir="@datarootdir@"
+ ubuntu_recovery="@UBUNTU_RECOVERY@"
++quiet_boot="@QUIET_BOOT@"
+
+ . "$pkgdatadir/grub-mkconfig_lib"
+
+@@ -158,10 +159,12 @@ linux_entry ()
+ fi
+ printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+ fi
+- message="$(gettext_printf "Loading Linux %s ..." ${version})"
+- sed "s/^/$submenu_indentation/" << EOF
++ if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then
++ message="$(gettext_printf "Loading Linux %s ..." ${version})"
++ sed "s/^/$submenu_indentation/" << EOF
+ echo '$(echo "$message" | grub_quote)'
+ EOF
++ fi
+ if test -d /sys/firmware/efi && test -e "${linux}.efi.signed"; then
+ sed "s/^/$submenu_indentation/" << EOF
+ linux ${rel_dirname}/${basename}.efi.signed root=${linux_root_device_thisversion} ro ${args}
+@@ -173,13 +176,17 @@ EOF
+ fi
+ if test -n "${initrd}" ; then
+ # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+- message="$(gettext_printf "Loading initial ramdisk ...")"
++ if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then
++ message="$(gettext_printf "Loading initial ramdisk ...")"
++ sed "s/^/$submenu_indentation/" << EOF
++ echo '$(echo "$message" | grub_quote)'
++EOF
++ fi
+ initrd_path=
+ for i in ${initrd}; do
+ initrd_path="${initrd_path} ${rel_dirname}/${i}"
+ done
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$(echo "$message" | grub_quote)'
+ initrd $(echo $initrd_path)
+ EOF
+ fi
diff --git a/debian/patches/minilzo-2.10.patch b/debian/patches/minilzo-2.10.patch
new file mode 100644
index 0000000..9dfce7c
--- /dev/null
+++ b/debian/patches/minilzo-2.10.patch
@@ -0,0 +1,2539 @@
+From dbcbb3e5b9fac665b92d630eb24de7bd8c43652e Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Sun, 28 Nov 2021 23:42:30 +0000
+Subject: minilzo: Update to minilzo-2.10
+
+minilzo fails to build on a number of Debian release architectures
+(armel, mips64el, mipsel, ppc64el) with errors such as:
+
+ ../../grub-core/lib/minilzo/minilzo.c: In function 'lzo_memops_get_le16':
+ ../../grub-core/lib/minilzo/minilzo.c:3479:11: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
+ 3479 | * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss); \
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ../../grub-core/lib/minilzo/minilzo.c:3530:5: note: in expansion of macro 'LZO_MEMOPS_COPY2'
+ 3530 | LZO_MEMOPS_COPY2(&v, ss);
+ | ^~~~~~~~~~~~~~~~
+
+The latest upstream version is 2.10, so updating to it seems like a good
+idea on general principles, and it fixes builds on all the above
+architectures.
+
+The update procedure documented in the GRUB Developers Manual worked; I
+just updated the version numbers to make it clear that it's been
+executed recently.
+
+Signed-off-by: Colin Watson <cjwatson@debian.org>
+
+Forwarded: https://lists.gnu.org/archive/html/grub-devel/2021-11/msg00095.html
+Last-Update: 2021-11-29
+
+Patch-Name: minilzo-2.10.patch
+---
+ docs/grub-dev.texi | 10 +-
+ grub-core/lib/minilzo/lzoconf.h | 41 ++-
+ grub-core/lib/minilzo/lzodefs.h | 416 +++++++++++++++++++-----
+ grub-core/lib/minilzo/minilzo.c | 542 +++++++++++++++++++++++++-------
+ grub-core/lib/minilzo/minilzo.h | 22 +-
+ 5 files changed, 817 insertions(+), 214 deletions(-)
+
+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
+index 6c629a23e..eb755d998 100644
+--- a/docs/grub-dev.texi
++++ b/docs/grub-dev.texi
+@@ -575,12 +575,12 @@ To upgrade to a new version of the miniLZO library, download the release
+ tarball and copy the files into the target directory:
+
+ @example
+-curl -L -O http://www.oberhumer.com/opensource/lzo/download/minilzo-2.08.tar.gz
+-tar -zxf minilzo-2.08.tar.gz
+-rm minilzo-2.08/testmini.c
++curl -L -O http://www.oberhumer.com/opensource/lzo/download/minilzo-2.10.tar.gz
++tar -zxf minilzo-2.10.tar.gz
++rm minilzo-2.10/testmini.c
+ rm -r grub-core/lib/minilzo/*
+-cp minilzo-2.08/*.[hc] grub-core/lib/minilzo
+-rm -r minilzo-2.08*
++cp minilzo-2.10/*.[hc] grub-core/lib/minilzo
++rm -r minilzo-2.10*
+ @end example
+
+ @node Porting
+diff --git a/grub-core/lib/minilzo/lzoconf.h b/grub-core/lib/minilzo/lzoconf.h
+index 61be29c5d..f9a8bdbee 100644
+--- a/grub-core/lib/minilzo/lzoconf.h
++++ b/grub-core/lib/minilzo/lzoconf.h
+@@ -2,7 +2,7 @@
+
+ This file is part of the LZO real-time data compression library.
+
+- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library is free software; you can redistribute it and/or
+@@ -29,9 +29,9 @@
+ #ifndef __LZOCONF_H_INCLUDED
+ #define __LZOCONF_H_INCLUDED 1
+
+-#define LZO_VERSION 0x2080
+-#define LZO_VERSION_STRING "2.08"
+-#define LZO_VERSION_DATE "Jun 29 2014"
++#define LZO_VERSION 0x20a0 /* 2.10 */
++#define LZO_VERSION_STRING "2.10"
++#define LZO_VERSION_DATE "Mar 01 2017"
+
+ /* internal Autoconf configuration file - only used when building LZO */
+ #if defined(LZO_HAVE_CONFIG_H)
+@@ -57,7 +57,7 @@
+
+ /* get OS and architecture defines */
+ #ifndef __LZODEFS_H_INCLUDED
+-#include "lzodefs.h"
++#include <lzo/lzodefs.h>
+ #endif
+
+
+@@ -94,25 +94,29 @@ extern "C" {
+ # if (LZO_OS_WIN64)
+ typedef unsigned __int64 lzo_uint;
+ typedef __int64 lzo_int;
++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF___INT64
+ # else
+ typedef lzo_ullong_t lzo_uint;
+ typedef lzo_llong_t lzo_int;
++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG_LONG
+ # endif
+-# define LZO_SIZEOF_LZO_UINT 8
++# define LZO_SIZEOF_LZO_INT 8
+ # define LZO_UINT_MAX 0xffffffffffffffffull
+ # define LZO_INT_MAX 9223372036854775807LL
+ # define LZO_INT_MIN (-1LL - LZO_INT_MAX)
+ # elif (LZO_ABI_IP32L64) /* MIPS R5900 */
+ typedef unsigned int lzo_uint;
+ typedef int lzo_int;
+-# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_INT
++# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT
+ # define LZO_UINT_MAX UINT_MAX
+ # define LZO_INT_MAX INT_MAX
+ # define LZO_INT_MIN INT_MIN
+ # elif (ULONG_MAX >= LZO_0xffffffffL)
+ typedef unsigned long lzo_uint;
+ typedef long lzo_int;
+-# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LONG
++# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_LONG
++# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG
+ # define LZO_UINT_MAX ULONG_MAX
+ # define LZO_INT_MAX LONG_MAX
+ # define LZO_INT_MIN LONG_MIN
+@@ -122,7 +126,7 @@ extern "C" {
+ #endif
+
+ /* The larger type of lzo_uint and lzo_uint32_t. */
+-#if (LZO_SIZEOF_LZO_UINT >= 4)
++#if (LZO_SIZEOF_LZO_INT >= 4)
+ # define lzo_xint lzo_uint
+ #else
+ # define lzo_xint lzo_uint32_t
+@@ -131,7 +135,8 @@ extern "C" {
+ typedef int lzo_bool;
+
+ /* sanity checks */
+-LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_UINT)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int) == LZO_SIZEOF_LZO_INT)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_INT)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint))
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t))
+
+@@ -163,14 +168,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t))
+ #endif
+
+ /* Older LZO versions used to support ancient systems and memory models
+- * like 16-bit MSDOS with __huge pointers and Cray PVP, but these
++ * such as 16-bit MSDOS with __huge pointers or Cray PVP, but these
+ * obsolete configurations are not supported any longer.
+ */
+ #if defined(__LZO_MMODEL_HUGE)
+-#error "__LZO_MMODEL_HUGE is unsupported"
++#error "__LZO_MMODEL_HUGE memory model is unsupported"
+ #endif
+ #if (LZO_MM_PVP)
+-#error "LZO_MM_PVP is unsupported"
++#error "LZO_MM_PVP memory model is unsupported"
+ #endif
+ #if (LZO_SIZEOF_INT < 4)
+ #error "LZO_SIZEOF_INT < 4 is unsupported"
+@@ -221,13 +226,13 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_bytep))
+
+ /* __cdecl calling convention for public C and assembly functions */
+ #if !defined(LZO_PUBLIC)
+-# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
++# define LZO_PUBLIC(r) __LZO_EXPORT1 r __LZO_EXPORT2 __LZO_CDECL
+ #endif
+ #if !defined(LZO_EXTERN)
+-# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
++# define LZO_EXTERN(r) __LZO_EXTERN_C LZO_PUBLIC(r)
+ #endif
+ #if !defined(LZO_PRIVATE)
+-# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
++# define LZO_PRIVATE(r) static r __LZO_CDECL
+ #endif
+
+ /* function types */
+@@ -399,6 +404,10 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
+ /* deprecated types */
+ typedef union { lzo_bytep a; lzo_uint b; } __lzo_pu_u;
+ typedef union { lzo_bytep a; lzo_uint32_t b; } __lzo_pu32_u;
++/* deprecated defines */
++#if !defined(LZO_SIZEOF_LZO_UINT)
++# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LZO_INT
++#endif
+
+ #if defined(LZO_CFG_COMPAT)
+
+diff --git a/grub-core/lib/minilzo/lzodefs.h b/grub-core/lib/minilzo/lzodefs.h
+index f4ae9487e..c3e2bcf5d 100644
+--- a/grub-core/lib/minilzo/lzodefs.h
++++ b/grub-core/lib/minilzo/lzodefs.h
+@@ -2,7 +2,7 @@
+
+ This file is part of the LZO real-time data compression library.
+
+- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library is free software; you can redistribute it and/or
+@@ -40,6 +40,33 @@
+ # define __LONG_MAX__ 9223372036854775807L
+ # endif
+ #endif
++#if 0
++#elif !defined(__LZO_LANG_OVERRIDE)
++#if (defined(__clang__) || defined(__GNUC__)) && defined(__ASSEMBLER__)
++# if (__ASSEMBLER__+0) <= 0
++# error "__ASSEMBLER__"
++# else
++# define LZO_LANG_ASSEMBLER 1
++# endif
++#elif defined(__cplusplus)
++# if (__cplusplus+0) <= 0
++# error "__cplusplus"
++# elif (__cplusplus < 199711L)
++# define LZO_LANG_CXX 1
++# elif defined(_MSC_VER) && defined(_MSVC_LANG) && (_MSVC_LANG+0 >= 201402L) && 1
++# define LZO_LANG_CXX _MSVC_LANG
++# else
++# define LZO_LANG_CXX __cplusplus
++# endif
++# define LZO_LANG_CPLUSPLUS LZO_LANG_CXX
++#else
++# if defined(__STDC_VERSION__) && (__STDC_VERSION__+0 >= 199409L)
++# define LZO_LANG_C __STDC_VERSION__
++# else
++# define LZO_LANG_C 1
++# endif
++#endif
++#endif
+ #if !defined(LZO_CFG_NO_DISABLE_WUNDEF)
+ #if defined(__ARMCC_VERSION)
+ # pragma diag_suppress 193
+@@ -135,10 +162,12 @@
+ # endif
+ #endif
+ #endif
+-#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
++#if (UINT_MAX == LZO_0xffffL)
++#if defined(_MSC_VER) && defined(M_I86HM)
+ # define ptrdiff_t long
+ # define _PTRDIFF_T_DEFINED 1
+ #endif
++#endif
+ #if (UINT_MAX == LZO_0xffffL)
+ # undef __LZO_RENAME_A
+ # undef __LZO_RENAME_B
+@@ -287,7 +316,7 @@
+ #define LZO_CPP_ECONCAT6(a,b,c,d,e,f) LZO_CPP_CONCAT6(a,b,c,d,e,f)
+ #define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g)
+ #endif
+-#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b))
++#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-((b)!=0))) - (o)) << 1) + (o)*((b)!=0))
+ #if 1 && defined(__cplusplus)
+ # if !defined(__STDC_CONSTANT_MACROS)
+ # define __STDC_CONSTANT_MACROS 1
+@@ -398,7 +427,7 @@
+ #elif defined(__TOS__) || defined(__atarist__)
+ # define LZO_OS_TOS 1
+ # define LZO_INFO_OS "tos"
+-#elif defined(macintosh) && !defined(__ppc__)
++#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__)
+ # define LZO_OS_MACCLASSIC 1
+ # define LZO_INFO_OS "macclassic"
+ #elif defined(__VMS)
+@@ -538,6 +567,12 @@
+ # define LZO_CC_ARMCC __ARMCC_VERSION
+ # define LZO_INFO_CC "ARM C Compiler"
+ # define LZO_INFO_CCVER __VERSION__
++#elif defined(__clang__) && defined(__c2__) && defined(__c2_version__) && defined(_MSC_VER)
++# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))
++# define LZO_CC_CLANG_C2 _MSC_VER
++# define LZO_CC_CLANG_VENDOR_MICROSOFT 1
++# define LZO_INFO_CC "clang/c2"
++# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__c2_version__)
+ #elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__)
+ # if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+ # define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))
+@@ -549,8 +584,18 @@
+ # elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ # endif
+-# define LZO_INFO_CC "clang"
+-# define LZO_INFO_CCVER __VERSION__
++# if defined(__APPLE_CC__)
++# define LZO_CC_CLANG_VENDOR_APPLE 1
++# define LZO_INFO_CC "clang/apple"
++# else
++# define LZO_CC_CLANG_VENDOR_LLVM 1
++# define LZO_INFO_CC "clang"
++# endif
++# if defined(__clang_version__)
++# define LZO_INFO_CCVER __clang_version__
++# else
++# define LZO_INFO_CCVER __VERSION__
++# endif
+ #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ # if defined(__GNUC_PATCHLEVEL__)
+ # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+@@ -770,7 +815,7 @@
+ #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ # define LZO_ARCH_I086 1
+ # define LZO_INFO_ARCH "i086"
+-#elif defined(__aarch64__)
++#elif defined(__aarch64__) || defined(_M_ARM64)
+ # define LZO_ARCH_ARM64 1
+ # define LZO_INFO_ARCH "arm64"
+ #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+@@ -782,22 +827,11 @@
+ #elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
+ # define LZO_ARCH_AMD64 1
+ # define LZO_INFO_ARCH "amd64"
+-#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB))
++#elif defined(__arm__) || defined(_M_ARM)
+ # define LZO_ARCH_ARM 1
+-# define LZO_ARCH_ARM_THUMB 1
+-# define LZO_INFO_ARCH "arm_thumb"
++# define LZO_INFO_ARCH "arm"
+ #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+ # define LZO_ARCH_ARM 1
+-# if defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 1)
+-# define LZO_ARCH_ARM_THUMB 1
+-# define LZO_INFO_ARCH "arm_thumb"
+-# elif defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 2)
+-# define LZO_INFO_ARCH "arm"
+-# else
+-# define LZO_INFO_ARCH "arm"
+-# endif
+-#elif defined(__arm__) || defined(_M_ARM)
+-# define LZO_ARCH_ARM 1
+ # define LZO_INFO_ARCH "arm"
+ #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
+ # define LZO_ARCH_AVR 1
+@@ -871,6 +905,15 @@
+ #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
+ # define LZO_ARCH_POWERPC 1
+ # define LZO_INFO_ARCH "powerpc"
++#elif defined(__powerpc64__) || defined(__powerpc64) || defined(__ppc64__) || defined(__PPC64__)
++# define LZO_ARCH_POWERPC 1
++# define LZO_INFO_ARCH "powerpc"
++#elif defined(__powerpc64le__) || defined(__powerpc64le) || defined(__ppc64le__) || defined(__PPC64LE__)
++# define LZO_ARCH_POWERPC 1
++# define LZO_INFO_ARCH "powerpc"
++#elif defined(__riscv)
++# define LZO_ARCH_RISCV 1
++# define LZO_INFO_ARCH "riscv"
+ #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
+ # define LZO_ARCH_S390 1
+ # define LZO_INFO_ARCH "s390"
+@@ -905,6 +948,23 @@
+ # define LZO_INFO_ARCH "unknown"
+ #endif
+ #endif
++#if !defined(LZO_ARCH_ARM_THUMB2)
++#if (LZO_ARCH_ARM)
++# if defined(__thumb__) || defined(__thumb) || defined(_M_THUMB)
++# if defined(__thumb2__)
++# define LZO_ARCH_ARM_THUMB2 1
++# elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4)
++# define LZO_ARCH_ARM_THUMB2 1
++# elif 1 && defined(_MSC_VER) && defined(_M_THUMB) && ((_M_THUMB)+0 >= 7)
++# define LZO_ARCH_ARM_THUMB2 1
++# endif
++# endif
++#endif
++#endif
++#if (LZO_ARCH_ARM_THUMB2)
++# undef LZO_INFO_ARCH
++# define LZO_INFO_ARCH "arm_thumb2"
++#endif
+ #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)
+ # error "FIXME - missing define for CPU architecture"
+ #endif
+@@ -947,13 +1007,10 @@
+ #if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86)
+ # error "unexpected configuration - check your compiler defines"
+ #endif
+-#if (LZO_ARCH_ARM_THUMB && !LZO_ARCH_ARM)
+-# error "unexpected configuration - check your compiler defines"
+-#endif
+-#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM_THUMB)
++#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM)
+ # error "unexpected configuration - check your compiler defines"
+ #endif
+-#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM_THUMB)
++#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM)
+ # error "unexpected configuration - check your compiler defines"
+ #endif
+ #if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2)
+@@ -985,7 +1042,9 @@
+ # if !defined(LZO_TARGET_FEATURE_SSE2)
+ # if defined(__SSE2__)
+ # define LZO_TARGET_FEATURE_SSE2 1
+-# elif defined(_MSC_VER) && ((defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) || defined(_M_AMD64))
++# elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2))
++# define LZO_TARGET_FEATURE_SSE2 1
++# elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64)
+ # define LZO_TARGET_FEATURE_SSE2 1
+ # endif
+ # endif
+@@ -1034,7 +1093,11 @@
+ #endif
+ #if (LZO_ARCH_ARM)
+ # if !defined(LZO_TARGET_FEATURE_NEON)
+-# if defined(__ARM_NEON__)
++# if defined(__ARM_NEON) && ((__ARM_NEON)+0)
++# define LZO_TARGET_FEATURE_NEON 1
++# elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0)
++# define LZO_TARGET_FEATURE_NEON 1
++# elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0)
+ # define LZO_TARGET_FEATURE_NEON 1
+ # endif
+ # endif
+@@ -1105,7 +1168,7 @@
+ # error "unexpected configuration - check your compiler defines"
+ # endif
+ #endif
+-#ifdef __cplusplus
++#if defined(__cplusplus)
+ extern "C" {
+ #endif
+ #if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))
+@@ -1128,7 +1191,7 @@ extern "C" {
+ #else
+ # error "FIXME - implement LZO_MM_AHSHIFT"
+ #endif
+-#ifdef __cplusplus
++#if defined(__cplusplus)
+ }
+ #endif
+ #endif
+@@ -1214,12 +1277,53 @@ extern "C" {
+ # define __lzo_gnuc_extension__ __extension__
+ #elif (LZO_CC_IBMC >= 600)
+ # define __lzo_gnuc_extension__ __extension__
+-#else
+ #endif
+ #endif
+ #if !defined(__lzo_gnuc_extension__)
+ # define __lzo_gnuc_extension__ /*empty*/
+ #endif
++#if !defined(lzo_has_builtin)
++#if (LZO_CC_CLANG) && defined(__has_builtin)
++# define lzo_has_builtin __has_builtin
++#endif
++#endif
++#if !defined(lzo_has_builtin)
++# define lzo_has_builtin(x) 0
++#endif
++#if !defined(lzo_has_attribute)
++#if (LZO_CC_CLANG) && defined(__has_attribute)
++# define lzo_has_attribute __has_attribute
++#endif
++#endif
++#if !defined(lzo_has_attribute)
++# define lzo_has_attribute(x) 0
++#endif
++#if !defined(lzo_has_declspec_attribute)
++#if (LZO_CC_CLANG) && defined(__has_declspec_attribute)
++# define lzo_has_declspec_attribute __has_declspec_attribute
++#endif
++#endif
++#if !defined(lzo_has_declspec_attribute)
++# define lzo_has_declspec_attribute(x) 0
++#endif
++#if !defined(lzo_has_feature)
++#if (LZO_CC_CLANG) && defined(__has_feature)
++# define lzo_has_feature __has_feature
++#endif
++#endif
++#if !defined(lzo_has_feature)
++# define lzo_has_feature(x) 0
++#endif
++#if !defined(lzo_has_extension)
++#if (LZO_CC_CLANG) && defined(__has_extension)
++# define lzo_has_extension __has_extension
++#elif (LZO_CC_CLANG) && defined(__has_feature)
++# define lzo_has_extension __has_feature
++#endif
++#endif
++#if !defined(lzo_has_extension)
++# define lzo_has_extension(x) 0
++#endif
+ #if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0
+ # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul))
+ # define LZO_CFG_USE_NEW_STYLE_CASTS 0
+@@ -1356,7 +1460,7 @@ extern "C" {
+ # elif (LZO_CC_MSC && (_MSC_VER < 900))
+ # define LZO_UNUSED(var) if (&var) ; else
+ # elif (LZO_CC_KEILC)
+-# define LZO_UNUSED(var) {LZO_EXTERN_C int lzo_unused__[1-2*!(sizeof(var)>0)];}
++# define LZO_UNUSED(var) {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;}
+ # elif (LZO_CC_PACIFICC)
+ # define LZO_UNUSED(var) ((void) sizeof(var))
+ # elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+@@ -1365,6 +1469,9 @@ extern "C" {
+ # define LZO_UNUSED(var) ((void) &var)
+ # endif
+ #endif
++#if !defined(LZO_UNUSED_RESULT)
++# define LZO_UNUSED_RESULT(var) LZO_UNUSED(var)
++#endif
+ #if !defined(LZO_UNUSED_FUNC)
+ # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+ # define LZO_UNUSED_FUNC(func) ((void) func)
+@@ -1377,7 +1484,7 @@ extern "C" {
+ # elif (LZO_CC_MSC)
+ # define LZO_UNUSED_FUNC(func) ((void) &func)
+ # elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+-# define LZO_UNUSED_FUNC(func) {LZO_EXTERN_C int lzo_unused_func__[1-2*!(sizeof((int)func)>0)];}
++# define LZO_UNUSED_FUNC(func) {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;}
+ # else
+ # define LZO_UNUSED_FUNC(func) ((void) func)
+ # endif
+@@ -1783,6 +1890,7 @@ extern "C" {
+ #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+ # define __lzo_likely(e) (__builtin_expect(!!(e),1))
+ # define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
++#elif (LZO_CC_CLANG && LZO_CC_CLANG_C2)
+ #elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+ # define __lzo_likely(e) (__builtin_expect(!!(e),1))
+ # define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+@@ -1793,21 +1901,28 @@ extern "C" {
+ # define __lzo_HAVE_likely 1
+ # endif
+ #else
+-# define __lzo_likely(e) (e)
++# define __lzo_likely(e) (e)
++#endif
++#if defined(__lzo_very_likely)
++# ifndef __lzo_HAVE_very_likely
++# define __lzo_HAVE_very_likely 1
++# endif
++#else
++# define __lzo_very_likely(e) __lzo_likely(e)
+ #endif
+ #if defined(__lzo_unlikely)
+ # ifndef __lzo_HAVE_unlikely
+ # define __lzo_HAVE_unlikely 1
+ # endif
+ #else
+-# define __lzo_unlikely(e) (e)
++# define __lzo_unlikely(e) (e)
+ #endif
+-#if !defined(__lzo_static_unused_void_func)
+-# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-# define __lzo_static_unused_void_func(f) static void __attribute__((__unused__)) f(void)
+-# else
+-# define __lzo_static_unused_void_func(f) static __lzo_inline void f(void)
++#if defined(__lzo_very_unlikely)
++# ifndef __lzo_HAVE_very_unlikely
++# define __lzo_HAVE_very_unlikely 1
+ # endif
++#else
++# define __lzo_very_unlikely(e) __lzo_unlikely(e)
+ #endif
+ #if !defined(__lzo_loop_forever)
+ # if (LZO_CC_IBMC)
+@@ -1817,7 +1932,7 @@ extern "C" {
+ # endif
+ #endif
+ #if !defined(__lzo_unreachable)
+-#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul))
++#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable)
+ # define __lzo_unreachable() __builtin_unreachable();
+ #elif (LZO_CC_GNUC >= 0x040500ul)
+ # define __lzo_unreachable() __builtin_unreachable();
+@@ -1836,6 +1951,15 @@ extern "C" {
+ # define __lzo_unreachable() __lzo_loop_forever();
+ # endif
+ #endif
++#if !defined(lzo_unused_funcs_impl)
++# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++# define lzo_unused_funcs_impl(r,f) static r __attribute__((__unused__)) f
++# elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC)
++# define lzo_unused_funcs_impl(r,f) static r f
++# else
++# define lzo_unused_funcs_impl(r,f) __lzo_static_forceinline r f
++# endif
++#endif
+ #ifndef __LZO_CTA_NAME
+ #if (LZO_CFG_USE_COUNTER)
+ # define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__COUNTER__)
+@@ -1861,6 +1985,8 @@ extern "C" {
+ #if !defined(LZO_COMPILE_TIME_ASSERT)
+ # if (LZO_CC_AZTECC)
+ # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];}
++# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul))
++# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}
+ # elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+ # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+ # elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)
+@@ -1877,11 +2003,16 @@ extern "C" {
+ # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];}
+ # endif
+ #endif
++#if (LZO_LANG_ASSEMBLER)
++# undef LZO_COMPILE_TIME_ASSERT_HEADER
++# define LZO_COMPILE_TIME_ASSERT_HEADER(e) /*empty*/
++#else
+ LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1)
+ #if defined(__cplusplus)
+ extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) }
+ #endif
+ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
++#endif
+ #if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+ # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+ # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+@@ -1948,7 +2079,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
+ #if !defined(LZO_HAVE_WINDOWS_H)
+ #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+ # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+-# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
++# elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul)))
+ # elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+ # else
+ # define LZO_HAVE_WINDOWS_H 1
+@@ -1956,6 +2087,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
+ #endif
+ #endif
+ #endif
++#define LZO_SIZEOF_CHAR 1
+ #ifndef LZO_SIZEOF_SHORT
+ #if defined(SIZEOF_SHORT)
+ # define LZO_SIZEOF_SHORT (SIZEOF_SHORT)
+@@ -2154,12 +2286,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long))
+ # define LZO_WORDSIZE 8
+ #elif (LZO_ARCH_AMD64)
+ # define LZO_WORDSIZE 8
++#elif (LZO_ARCH_ARM64)
++# define LZO_WORDSIZE 8
+ #elif (LZO_ARCH_AVR)
+ # define LZO_WORDSIZE 1
+ #elif (LZO_ARCH_H8300)
+-# if defined(__NORMAL_MODE__)
+-# define LZO_WORDSIZE 4
+-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+ # define LZO_WORDSIZE 4
+ # else
+ # define LZO_WORDSIZE 2
+@@ -2202,11 +2334,15 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)
+ #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+ # define LZO_SIZEOF_VOID_P 2
+ #elif (LZO_ARCH_H8300)
+-# if defined(__NORMAL_MODE__)
+-# define LZO_SIZEOF_VOID_P 2
+-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+-# define LZO_SIZEOF_VOID_P 4
++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 4)
++# if defined(__NORMAL_MODE__)
++# define LZO_SIZEOF_VOID_P 2
++# else
++# define LZO_SIZEOF_VOID_P 4
++# endif
+ # else
++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 2)
+ # define LZO_SIZEOF_VOID_P 2
+ # endif
+ # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+@@ -2296,7 +2432,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+ # define LZO_ABI_LITTLE_ENDIAN 1
+-#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
++#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430 || LZO_ARCH_RISCV)
+ # define LZO_ABI_LITTLE_ENDIAN 1
+ #elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU)
+ # define LZO_ABI_BIG_ENDIAN 1
+@@ -2310,10 +2446,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)
++# define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM) && defined(_MSC_VER) && defined(_WIN32)
++# define LZO_ABI_LITTLE_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC)
+ # if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)
+ # error "unexpected configuration - check your compiler defines"
+@@ -2323,10 +2463,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_LITTLE_ENDIAN 1
+ # endif
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)
++# define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__)
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__)
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM64) && defined(_MSC_VER) && defined(_WIN32)
++# define LZO_ABI_LITTLE_ENDIAN 1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+@@ -2368,6 +2512,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_IP32L64 1
+ # define LZO_INFO_ABI_PM "ip32l64"
+ #endif
++#if (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_VOID_P == 4 && LZO_WORDSIZE == 8)
++# define LZO_ABI_IP32W64 1
++# ifndef LZO_INFO_ABI_PM
++# define LZO_INFO_ABI_PM "ip32w64"
++# endif
++#endif
+ #if 0
+ #elif !defined(__LZO_LIBC_OVERRIDE)
+ #if (LZO_LIBC_NAKED)
+@@ -2455,20 +2605,43 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # endif
+ #elif (LZO_ARCH_ARM)
+ # if defined(__ARM_FEATURE_UNALIGNED)
++# if ((__ARM_FEATURE_UNALIGNED)+0)
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# endif
++# elif 1 && (LZO_ARCH_ARM_THUMB2)
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# elif 1 && defined(__ARM_ARCH) && ((__ARM_ARCH)+0 >= 7)
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+ # ifndef LZO_OPT_UNALIGNED32
+ # define LZO_OPT_UNALIGNED32 1
+ # endif
+-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 7)
++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R))
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+ # ifndef LZO_OPT_UNALIGNED32
+ # define LZO_OPT_UNALIGNED32 1
+ # endif
+-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 6) && !defined(__TARGET_PROFILE_M)
++# elif 1 && defined(_MSC_VER) && defined(_M_ARM) && ((_M_ARM)+0 >= 7)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+@@ -2520,7 +2693,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ #elif (LZO_ARCH_POWERPC)
+ # define LZO_OPT_PREFER_PREINC 1
+ # define LZO_OPT_PREFER_PREDEC 1
+-# if (LZO_ABI_BIG_ENDIAN)
++# if (LZO_ABI_BIG_ENDIAN) || (LZO_WORDSIZE == 8)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+@@ -2533,6 +2706,19 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # endif
+ # endif
+ # endif
++#elif (LZO_ARCH_RISCV)
++# define LZO_OPT_AVOID_UINT_INDEX 1
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# if (LZO_WORDSIZE == 8)
++# ifndef LZO_OPT_UNALIGNED64
++# define LZO_OPT_UNALIGNED64 1
++# endif
++# endif
+ #elif (LZO_ARCH_S390)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+@@ -2624,32 +2810,61 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ #if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0))
+ # error "missing defines for sizes"
+ #endif
++#define LZO_TYPEOF_CHAR 1u
++#define LZO_TYPEOF_SHORT 2u
++#define LZO_TYPEOF_INT 3u
++#define LZO_TYPEOF_LONG 4u
++#define LZO_TYPEOF_LONG_LONG 5u
++#define LZO_TYPEOF___INT8 17u
++#define LZO_TYPEOF___INT16 18u
++#define LZO_TYPEOF___INT32 19u
++#define LZO_TYPEOF___INT64 20u
++#define LZO_TYPEOF___INT128 21u
++#define LZO_TYPEOF___INT256 22u
++#define LZO_TYPEOF___MODE_QI 33u
++#define LZO_TYPEOF___MODE_HI 34u
++#define LZO_TYPEOF___MODE_SI 35u
++#define LZO_TYPEOF___MODE_DI 36u
++#define LZO_TYPEOF___MODE_TI 37u
++#define LZO_TYPEOF_CHAR_P 129u
+ #if !defined(lzo_llong_t)
+ #if (LZO_SIZEOF_LONG_LONG+0 > 0)
+-__lzo_gnuc_extension__ typedef long long lzo_llong_t__;
+-__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
++# if !(LZO_LANG_ASSEMBLER)
++ __lzo_gnuc_extension__ typedef long long lzo_llong_t__;
++ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
++# endif
+ # define lzo_llong_t lzo_llong_t__
+ # define lzo_ullong_t lzo_ullong_t__
+ #endif
+ #endif
+ #if !defined(lzo_int16e_t)
+-#if (LZO_SIZEOF_LONG == 2)
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) && (LZO_SIZEOF_SHORT != 2)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T
++#endif
++#if (LZO_SIZEOF_LONG == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT)
+ # define lzo_int16e_t long
+ # define lzo_uint16e_t unsigned long
+-#elif (LZO_SIZEOF_INT == 2)
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG
++#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT)
+ # define lzo_int16e_t int
+ # define lzo_uint16e_t unsigned int
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_SHORT == 2)
+ # define lzo_int16e_t short int
+ # define lzo_uint16e_t unsigned short int
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_SHORT
+ #elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)
++# if !(LZO_LANG_ASSEMBLER)
+ typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));
+ typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));
++# endif
+ # define lzo_int16e_t lzo_int16e_hi_t__
+ # define lzo_uint16e_t lzo_uint16e_hi_t__
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI
+ #elif (LZO_SIZEOF___INT16 == 2)
+ # define lzo_int16e_t __int16
+ # define lzo_uint16e_t unsigned __int16
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16
+ #else
+ #endif
+ #endif
+@@ -2659,33 +2874,47 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T)
+ #endif
+ #if !defined(lzo_int32e_t)
+-#if (LZO_SIZEOF_LONG == 4)
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) && (LZO_SIZEOF_INT != 4)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T
++#endif
++#if (LZO_SIZEOF_LONG == 4) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT)
+ # define lzo_int32e_t long int
+ # define lzo_uint32e_t unsigned long int
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG
+ #elif (LZO_SIZEOF_INT == 4)
+ # define lzo_int32e_t int
+ # define lzo_uint32e_t unsigned int
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_SHORT == 4)
+ # define lzo_int32e_t short int
+ # define lzo_uint32e_t unsigned short int
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_SHORT
+ #elif (LZO_SIZEOF_LONG_LONG == 4)
+ # define lzo_int32e_t lzo_llong_t
+ # define lzo_uint32e_t lzo_ullong_t
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG_LONG
+ #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)
++# if !(LZO_LANG_ASSEMBLER)
+ typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
+ typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++# endif
+ # define lzo_int32e_t lzo_int32e_si_t__
+ # define lzo_uint32e_t lzo_uint32e_si_t__
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI
+ #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)
++# if !(LZO_LANG_ASSEMBLER)
+ typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
+ typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++# endif
+ # define lzo_int32e_t lzo_int32e_si_t__
+ # define lzo_uint32e_t lzo_uint32e_si_t__
+ # define LZO_INT32_C(c) (c##LL)
+ # define LZO_UINT32_C(c) (c##ULL)
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI
+ #elif (LZO_SIZEOF___INT32 == 4)
+ # define lzo_int32e_t __int32
+ # define lzo_uint32e_t unsigned __int32
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32
+ #else
+ #endif
+ #endif
+@@ -2696,21 +2925,28 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #endif
+ #if !defined(lzo_int64e_t)
+ #if (LZO_SIZEOF___INT64 == 8)
+-# if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64)
+-# define LZO_CFG_TYPE_PREFER___INT64 1
++# if (LZO_CC_BORLANDC) && !defined(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T)
++# define LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T LZO_TYPEOF___INT64
+ # endif
+ #endif
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && (LZO_SIZEOF_LONG_LONG != 8)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T
++#endif
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) && (LZO_SIZEOF___INT64 != 8)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T
++#endif
+ #if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
+ # define lzo_int64e_t int
+ # define lzo_uint64e_t unsigned int
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_INT
+-#elif (LZO_SIZEOF_LONG == 8)
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT
++#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64)
+ # define lzo_int64e_t long int
+ # define lzo_uint64e_t unsigned long int
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG
+-#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64)
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG
++#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64)
+ # define lzo_int64e_t lzo_llong_t
+ # define lzo_uint64e_t lzo_ullong_t
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG_LONG
+ # if (LZO_CC_BORLANDC)
+ # define LZO_INT64_C(c) ((c) + 0ll)
+ # define LZO_UINT64_C(c) ((c) + 0ull)
+@@ -2721,10 +2957,10 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define LZO_INT64_C(c) (c##LL)
+ # define LZO_UINT64_C(c) (c##ULL)
+ # endif
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG_LONG
+ #elif (LZO_SIZEOF___INT64 == 8)
+ # define lzo_int64e_t __int64
+ # define lzo_uint64e_t unsigned __int64
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF___INT64
+ # if (LZO_CC_BORLANDC)
+ # define LZO_INT64_C(c) ((c) + 0i64)
+ # define LZO_UINT64_C(c) ((c) + 0ui64)
+@@ -2732,11 +2968,11 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define LZO_INT64_C(c) (c##i64)
+ # define LZO_UINT64_C(c) (c##ui64)
+ # endif
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF___INT64
+ #else
+ #endif
+ #endif
+ #if defined(lzo_int64e_t)
++# define LZO_SIZEOF_LZO_INT64E_T 8
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T)
+ #endif
+@@ -2745,14 +2981,17 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int32l_t lzo_int32e_t
+ # define lzo_uint32l_t lzo_uint32e_t
+ # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LZO_INT32E_T
++# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T
+ #elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
+ # define lzo_int32l_t int
+ # define lzo_uint32l_t unsigned int
+ # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT
+ #elif (LZO_SIZEOF_LONG >= 4)
+ # define lzo_int32l_t long int
+ # define lzo_uint32l_t unsigned long int
+ # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LONG
++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_LONG
+ #else
+ # error "lzo_int32l_t"
+ #endif
+@@ -2766,6 +3005,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int64l_t lzo_int64e_t
+ # define lzo_uint64l_t lzo_uint64e_t
+ # define LZO_SIZEOF_LZO_INT64L_T LZO_SIZEOF_LZO_INT64E_T
++# define LZO_TYPEOF_LZO_INT64L_T LZO_TYPEOF_LZO_INT64E_T
+ #else
+ #endif
+ #endif
+@@ -2778,10 +3018,12 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int32f_t lzo_int64l_t
+ # define lzo_uint32f_t lzo_uint64l_t
+ # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT64L_T
+ #else
+ # define lzo_int32f_t lzo_int32l_t
+ # define lzo_uint32f_t lzo_uint32l_t
+ # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT32L_T
++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT32L_T
+ #endif
+ #endif
+ #if 1
+@@ -2793,6 +3035,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int64f_t lzo_int64l_t
+ # define lzo_uint64f_t lzo_uint64l_t
+ # define LZO_SIZEOF_LZO_INT64F_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_INT64F_T LZO_TYPEOF_LZO_INT64L_T
+ #else
+ #endif
+ #endif
+@@ -2803,33 +3046,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #if !defined(lzo_intptr_t)
+ #if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16))
+ # define __LZO_INTPTR_T_IS_POINTER 1
+- typedef char* lzo_intptr_t;
+- typedef char* lzo_uintptr_t;
++# if !(LZO_LANG_ASSEMBLER)
++ typedef char * lzo_intptr_t;
++ typedef char * lzo_uintptr_t;
++# endif
+ # define lzo_intptr_t lzo_intptr_t
+ # define lzo_uintptr_t lzo_uintptr_t
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_VOID_P
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_CHAR_P
+ #elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))
++# if !(LZO_LANG_ASSEMBLER)
+ typedef __w64 int lzo_intptr_t;
+ typedef __w64 unsigned int lzo_uintptr_t;
++# endif
+ # define lzo_intptr_t lzo_intptr_t
+ # define lzo_uintptr_t lzo_uintptr_t
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P)
+ # define lzo_intptr_t short
+ # define lzo_uintptr_t unsigned short
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_SHORT
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT
+ #elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
+ # define lzo_intptr_t int
+ # define lzo_uintptr_t unsigned int
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)
+ # define lzo_intptr_t long
+ # define lzo_uintptr_t unsigned long
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LONG
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LONG
+ #elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P)
+ # define lzo_intptr_t lzo_int64l_t
+ # define lzo_uintptr_t lzo_uint64l_t
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LZO_INT64L_T
+ #else
+ # error "lzo_intptr_t"
+ #endif
+@@ -2843,34 +3096,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER)
+ # define lzo_word_t lzo_uintptr_t
+ # define lzo_sword_t lzo_intptr_t
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LZO_INTPTR_T
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_LONG)
+ # define lzo_word_t unsigned long
+ # define lzo_sword_t long
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_INT)
+ # define lzo_word_t unsigned int
+ # define lzo_sword_t int
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT)
+ # define lzo_word_t unsigned short
+ # define lzo_sword_t short
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_SHORT
+ #elif (LZO_WORDSIZE == 1)
+ # define lzo_word_t unsigned char
+ # define lzo_sword_t signed char
+-# define LZO_SIZEOF_LZO_WORD_T 1
++# define LZO_SIZEOF_LZO_WORD_T 1
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_CHAR
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T)
+ # define lzo_word_t lzo_uint64l_t
+ # define lzo_sword_t lzo_int64l_t
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
+ #elif (LZO_ARCH_SPU) && (LZO_CC_GNUC)
+ #if 0
++# if !(LZO_LANG_ASSEMBLER)
+ typedef unsigned lzo_word_t __attribute__((__mode__(__V16QI__)));
+ typedef int lzo_sword_t __attribute__((__mode__(__V16QI__)));
++# endif
+ # define lzo_word_t lzo_word_t
+ # define lzo_sword_t lzo_sword_t
+ # define LZO_SIZEOF_LZO_WORD_T 16
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF___MODE_V16QI
+ #endif
+ #else
+ # error "lzo_word_t"
+@@ -2885,6 +3147,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #define lzo_int8_t signed char
+ #define lzo_uint8_t unsigned char
+ #define LZO_SIZEOF_LZO_INT8_T 1
++#define LZO_TYPEOF_LZO_INT8_T LZO_TYPEOF_CHAR
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))
+ #endif
+@@ -2892,6 +3155,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))
+ #define lzo_int16_t lzo_int16e_t
+ #define lzo_uint16_t lzo_uint16e_t
+ #define LZO_SIZEOF_LZO_INT16_T LZO_SIZEOF_LZO_INT16E_T
++#define LZO_TYPEOF_LZO_INT16_T LZO_TYPEOF_LZO_INT16E_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))
+ #endif
+@@ -2899,6 +3163,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))
+ #define lzo_int32_t lzo_int32e_t
+ #define lzo_uint32_t lzo_uint32e_t
+ #define LZO_SIZEOF_LZO_INT32_T LZO_SIZEOF_LZO_INT32E_T
++#define LZO_TYPEOF_LZO_INT32_T LZO_TYPEOF_LZO_INT32E_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))
+ #endif
+@@ -2906,6 +3171,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))
+ #define lzo_int64_t lzo_int64e_t
+ #define lzo_uint64_t lzo_uint64e_t
+ #define LZO_SIZEOF_LZO_INT64_T LZO_SIZEOF_LZO_INT64E_T
++#define LZO_TYPEOF_LZO_INT64_T LZO_TYPEOF_LZO_INT64E_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))
+ #endif
+@@ -2913,6 +3179,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))
+ #define lzo_int_least32_t lzo_int32l_t
+ #define lzo_uint_least32_t lzo_uint32l_t
+ #define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T
++#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t))
+ #endif
+@@ -2920,6 +3187,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_leas
+ #define lzo_int_least64_t lzo_int64l_t
+ #define lzo_uint_least64_t lzo_uint64l_t
+ #define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T
++#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t))
+ #endif
+@@ -2927,6 +3195,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_leas
+ #define lzo_int_fast32_t lzo_int32f_t
+ #define lzo_uint_fast32_t lzo_uint32f_t
+ #define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T
++#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t))
+ #endif
+@@ -2934,6 +3203,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast3
+ #define lzo_int_fast64_t lzo_int64f_t
+ #define lzo_uint_fast64_t lzo_uint64f_t
+ #define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T
++#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t))
+ #endif
+diff --git a/grub-core/lib/minilzo/minilzo.c b/grub-core/lib/minilzo/minilzo.c
+index ab2be5f4f..8fd866450 100644
+--- a/grub-core/lib/minilzo/minilzo.c
++++ b/grub-core/lib/minilzo/minilzo.c
+@@ -2,7 +2,7 @@
+
+ This file is part of the LZO real-time data compression library.
+
+- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library is free software; you can redistribute it and/or
+@@ -60,6 +60,33 @@
+ # define __LONG_MAX__ 9223372036854775807L
+ # endif
+ #endif
++#if 0
++#elif !defined(__LZO_LANG_OVERRIDE)
++#if (defined(__clang__) || defined(__GNUC__)) && defined(__ASSEMBLER__)
++# if (__ASSEMBLER__+0) <= 0
++# error "__ASSEMBLER__"
++# else
++# define LZO_LANG_ASSEMBLER 1
++# endif
++#elif defined(__cplusplus)
++# if (__cplusplus+0) <= 0
++# error "__cplusplus"
++# elif (__cplusplus < 199711L)
++# define LZO_LANG_CXX 1
++# elif defined(_MSC_VER) && defined(_MSVC_LANG) && (_MSVC_LANG+0 >= 201402L) && 1
++# define LZO_LANG_CXX _MSVC_LANG
++# else
++# define LZO_LANG_CXX __cplusplus
++# endif
++# define LZO_LANG_CPLUSPLUS LZO_LANG_CXX
++#else
++# if defined(__STDC_VERSION__) && (__STDC_VERSION__+0 >= 199409L)
++# define LZO_LANG_C __STDC_VERSION__
++# else
++# define LZO_LANG_C 1
++# endif
++#endif
++#endif
+ #if !defined(LZO_CFG_NO_DISABLE_WUNDEF)
+ #if defined(__ARMCC_VERSION)
+ # pragma diag_suppress 193
+@@ -155,10 +182,12 @@
+ # endif
+ #endif
+ #endif
+-#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
++#if (UINT_MAX == LZO_0xffffL)
++#if defined(_MSC_VER) && defined(M_I86HM)
+ # define ptrdiff_t long
+ # define _PTRDIFF_T_DEFINED 1
+ #endif
++#endif
+ #if (UINT_MAX == LZO_0xffffL)
+ # undef __LZO_RENAME_A
+ # undef __LZO_RENAME_B
+@@ -307,7 +336,7 @@
+ #define LZO_CPP_ECONCAT6(a,b,c,d,e,f) LZO_CPP_CONCAT6(a,b,c,d,e,f)
+ #define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g)
+ #endif
+-#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b))
++#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-((b)!=0))) - (o)) << 1) + (o)*((b)!=0))
+ #if 1 && defined(__cplusplus)
+ # if !defined(__STDC_CONSTANT_MACROS)
+ # define __STDC_CONSTANT_MACROS 1
+@@ -418,7 +447,7 @@
+ #elif defined(__TOS__) || defined(__atarist__)
+ # define LZO_OS_TOS 1
+ # define LZO_INFO_OS "tos"
+-#elif defined(macintosh) && !defined(__ppc__)
++#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__)
+ # define LZO_OS_MACCLASSIC 1
+ # define LZO_INFO_OS "macclassic"
+ #elif defined(__VMS)
+@@ -558,6 +587,12 @@
+ # define LZO_CC_ARMCC __ARMCC_VERSION
+ # define LZO_INFO_CC "ARM C Compiler"
+ # define LZO_INFO_CCVER __VERSION__
++#elif defined(__clang__) && defined(__c2__) && defined(__c2_version__) && defined(_MSC_VER)
++# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))
++# define LZO_CC_CLANG_C2 _MSC_VER
++# define LZO_CC_CLANG_VENDOR_MICROSOFT 1
++# define LZO_INFO_CC "clang/c2"
++# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__c2_version__)
+ #elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__)
+ # if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+ # define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))
+@@ -569,8 +604,18 @@
+ # elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ # define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ # endif
+-# define LZO_INFO_CC "clang"
+-# define LZO_INFO_CCVER __VERSION__
++# if defined(__APPLE_CC__)
++# define LZO_CC_CLANG_VENDOR_APPLE 1
++# define LZO_INFO_CC "clang/apple"
++# else
++# define LZO_CC_CLANG_VENDOR_LLVM 1
++# define LZO_INFO_CC "clang"
++# endif
++# if defined(__clang_version__)
++# define LZO_INFO_CCVER __clang_version__
++# else
++# define LZO_INFO_CCVER __VERSION__
++# endif
+ #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ # if defined(__GNUC_PATCHLEVEL__)
+ # define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+@@ -790,7 +835,7 @@
+ #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ # define LZO_ARCH_I086 1
+ # define LZO_INFO_ARCH "i086"
+-#elif defined(__aarch64__)
++#elif defined(__aarch64__) || defined(_M_ARM64)
+ # define LZO_ARCH_ARM64 1
+ # define LZO_INFO_ARCH "arm64"
+ #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+@@ -802,22 +847,11 @@
+ #elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
+ # define LZO_ARCH_AMD64 1
+ # define LZO_INFO_ARCH "amd64"
+-#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB))
++#elif defined(__arm__) || defined(_M_ARM)
+ # define LZO_ARCH_ARM 1
+-# define LZO_ARCH_ARM_THUMB 1
+-# define LZO_INFO_ARCH "arm_thumb"
++# define LZO_INFO_ARCH "arm"
+ #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+ # define LZO_ARCH_ARM 1
+-# if defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 1)
+-# define LZO_ARCH_ARM_THUMB 1
+-# define LZO_INFO_ARCH "arm_thumb"
+-# elif defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 2)
+-# define LZO_INFO_ARCH "arm"
+-# else
+-# define LZO_INFO_ARCH "arm"
+-# endif
+-#elif defined(__arm__) || defined(_M_ARM)
+-# define LZO_ARCH_ARM 1
+ # define LZO_INFO_ARCH "arm"
+ #elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
+ # define LZO_ARCH_AVR 1
+@@ -891,6 +925,15 @@
+ #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
+ # define LZO_ARCH_POWERPC 1
+ # define LZO_INFO_ARCH "powerpc"
++#elif defined(__powerpc64__) || defined(__powerpc64) || defined(__ppc64__) || defined(__PPC64__)
++# define LZO_ARCH_POWERPC 1
++# define LZO_INFO_ARCH "powerpc"
++#elif defined(__powerpc64le__) || defined(__powerpc64le) || defined(__ppc64le__) || defined(__PPC64LE__)
++# define LZO_ARCH_POWERPC 1
++# define LZO_INFO_ARCH "powerpc"
++#elif defined(__riscv)
++# define LZO_ARCH_RISCV 1
++# define LZO_INFO_ARCH "riscv"
+ #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
+ # define LZO_ARCH_S390 1
+ # define LZO_INFO_ARCH "s390"
+@@ -925,6 +968,23 @@
+ # define LZO_INFO_ARCH "unknown"
+ #endif
+ #endif
++#if !defined(LZO_ARCH_ARM_THUMB2)
++#if (LZO_ARCH_ARM)
++# if defined(__thumb__) || defined(__thumb) || defined(_M_THUMB)
++# if defined(__thumb2__)
++# define LZO_ARCH_ARM_THUMB2 1
++# elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4)
++# define LZO_ARCH_ARM_THUMB2 1
++# elif 1 && defined(_MSC_VER) && defined(_M_THUMB) && ((_M_THUMB)+0 >= 7)
++# define LZO_ARCH_ARM_THUMB2 1
++# endif
++# endif
++#endif
++#endif
++#if (LZO_ARCH_ARM_THUMB2)
++# undef LZO_INFO_ARCH
++# define LZO_INFO_ARCH "arm_thumb2"
++#endif
+ #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)
+ # error "FIXME - missing define for CPU architecture"
+ #endif
+@@ -967,13 +1027,10 @@
+ #if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86)
+ # error "unexpected configuration - check your compiler defines"
+ #endif
+-#if (LZO_ARCH_ARM_THUMB && !LZO_ARCH_ARM)
+-# error "unexpected configuration - check your compiler defines"
+-#endif
+-#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM_THUMB)
++#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM)
+ # error "unexpected configuration - check your compiler defines"
+ #endif
+-#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM_THUMB)
++#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM)
+ # error "unexpected configuration - check your compiler defines"
+ #endif
+ #if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2)
+@@ -1005,7 +1062,9 @@
+ # if !defined(LZO_TARGET_FEATURE_SSE2)
+ # if defined(__SSE2__)
+ # define LZO_TARGET_FEATURE_SSE2 1
+-# elif defined(_MSC_VER) && ((defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) || defined(_M_AMD64))
++# elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2))
++# define LZO_TARGET_FEATURE_SSE2 1
++# elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64)
+ # define LZO_TARGET_FEATURE_SSE2 1
+ # endif
+ # endif
+@@ -1054,7 +1113,11 @@
+ #endif
+ #if (LZO_ARCH_ARM)
+ # if !defined(LZO_TARGET_FEATURE_NEON)
+-# if defined(__ARM_NEON__)
++# if defined(__ARM_NEON) && ((__ARM_NEON)+0)
++# define LZO_TARGET_FEATURE_NEON 1
++# elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0)
++# define LZO_TARGET_FEATURE_NEON 1
++# elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0)
+ # define LZO_TARGET_FEATURE_NEON 1
+ # endif
+ # endif
+@@ -1125,7 +1188,7 @@
+ # error "unexpected configuration - check your compiler defines"
+ # endif
+ #endif
+-#ifdef __cplusplus
++#if defined(__cplusplus)
+ extern "C" {
+ #endif
+ #if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))
+@@ -1148,7 +1211,7 @@ extern "C" {
+ #else
+ # error "FIXME - implement LZO_MM_AHSHIFT"
+ #endif
+-#ifdef __cplusplus
++#if defined(__cplusplus)
+ }
+ #endif
+ #endif
+@@ -1234,12 +1297,53 @@ extern "C" {
+ # define __lzo_gnuc_extension__ __extension__
+ #elif (LZO_CC_IBMC >= 600)
+ # define __lzo_gnuc_extension__ __extension__
+-#else
+ #endif
+ #endif
+ #if !defined(__lzo_gnuc_extension__)
+ # define __lzo_gnuc_extension__ /*empty*/
+ #endif
++#if !defined(lzo_has_builtin)
++#if (LZO_CC_CLANG) && defined(__has_builtin)
++# define lzo_has_builtin __has_builtin
++#endif
++#endif
++#if !defined(lzo_has_builtin)
++# define lzo_has_builtin(x) 0
++#endif
++#if !defined(lzo_has_attribute)
++#if (LZO_CC_CLANG) && defined(__has_attribute)
++# define lzo_has_attribute __has_attribute
++#endif
++#endif
++#if !defined(lzo_has_attribute)
++# define lzo_has_attribute(x) 0
++#endif
++#if !defined(lzo_has_declspec_attribute)
++#if (LZO_CC_CLANG) && defined(__has_declspec_attribute)
++# define lzo_has_declspec_attribute __has_declspec_attribute
++#endif
++#endif
++#if !defined(lzo_has_declspec_attribute)
++# define lzo_has_declspec_attribute(x) 0
++#endif
++#if !defined(lzo_has_feature)
++#if (LZO_CC_CLANG) && defined(__has_feature)
++# define lzo_has_feature __has_feature
++#endif
++#endif
++#if !defined(lzo_has_feature)
++# define lzo_has_feature(x) 0
++#endif
++#if !defined(lzo_has_extension)
++#if (LZO_CC_CLANG) && defined(__has_extension)
++# define lzo_has_extension __has_extension
++#elif (LZO_CC_CLANG) && defined(__has_feature)
++# define lzo_has_extension __has_feature
++#endif
++#endif
++#if !defined(lzo_has_extension)
++# define lzo_has_extension(x) 0
++#endif
+ #if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0
+ # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul))
+ # define LZO_CFG_USE_NEW_STYLE_CASTS 0
+@@ -1376,7 +1480,7 @@ extern "C" {
+ # elif (LZO_CC_MSC && (_MSC_VER < 900))
+ # define LZO_UNUSED(var) if (&var) ; else
+ # elif (LZO_CC_KEILC)
+-# define LZO_UNUSED(var) {LZO_EXTERN_C int lzo_unused__[1-2*!(sizeof(var)>0)];}
++# define LZO_UNUSED(var) {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;}
+ # elif (LZO_CC_PACIFICC)
+ # define LZO_UNUSED(var) ((void) sizeof(var))
+ # elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+@@ -1385,6 +1489,9 @@ extern "C" {
+ # define LZO_UNUSED(var) ((void) &var)
+ # endif
+ #endif
++#if !defined(LZO_UNUSED_RESULT)
++# define LZO_UNUSED_RESULT(var) LZO_UNUSED(var)
++#endif
+ #if !defined(LZO_UNUSED_FUNC)
+ # if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+ # define LZO_UNUSED_FUNC(func) ((void) func)
+@@ -1397,7 +1504,7 @@ extern "C" {
+ # elif (LZO_CC_MSC)
+ # define LZO_UNUSED_FUNC(func) ((void) &func)
+ # elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+-# define LZO_UNUSED_FUNC(func) {LZO_EXTERN_C int lzo_unused_func__[1-2*!(sizeof((int)func)>0)];}
++# define LZO_UNUSED_FUNC(func) {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;}
+ # else
+ # define LZO_UNUSED_FUNC(func) ((void) func)
+ # endif
+@@ -1803,6 +1910,7 @@ extern "C" {
+ #elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+ # define __lzo_likely(e) (__builtin_expect(!!(e),1))
+ # define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
++#elif (LZO_CC_CLANG && LZO_CC_CLANG_C2)
+ #elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+ # define __lzo_likely(e) (__builtin_expect(!!(e),1))
+ # define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+@@ -1813,21 +1921,28 @@ extern "C" {
+ # define __lzo_HAVE_likely 1
+ # endif
+ #else
+-# define __lzo_likely(e) (e)
++# define __lzo_likely(e) (e)
++#endif
++#if defined(__lzo_very_likely)
++# ifndef __lzo_HAVE_very_likely
++# define __lzo_HAVE_very_likely 1
++# endif
++#else
++# define __lzo_very_likely(e) __lzo_likely(e)
+ #endif
+ #if defined(__lzo_unlikely)
+ # ifndef __lzo_HAVE_unlikely
+ # define __lzo_HAVE_unlikely 1
+ # endif
+ #else
+-# define __lzo_unlikely(e) (e)
++# define __lzo_unlikely(e) (e)
+ #endif
+-#if !defined(__lzo_static_unused_void_func)
+-# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-# define __lzo_static_unused_void_func(f) static void __attribute__((__unused__)) f(void)
+-# else
+-# define __lzo_static_unused_void_func(f) static __lzo_inline void f(void)
++#if defined(__lzo_very_unlikely)
++# ifndef __lzo_HAVE_very_unlikely
++# define __lzo_HAVE_very_unlikely 1
+ # endif
++#else
++# define __lzo_very_unlikely(e) __lzo_unlikely(e)
+ #endif
+ #if !defined(__lzo_loop_forever)
+ # if (LZO_CC_IBMC)
+@@ -1837,7 +1952,7 @@ extern "C" {
+ # endif
+ #endif
+ #if !defined(__lzo_unreachable)
+-#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul))
++#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable)
+ # define __lzo_unreachable() __builtin_unreachable();
+ #elif (LZO_CC_GNUC >= 0x040500ul)
+ # define __lzo_unreachable() __builtin_unreachable();
+@@ -1856,6 +1971,15 @@ extern "C" {
+ # define __lzo_unreachable() __lzo_loop_forever();
+ # endif
+ #endif
++#if !defined(lzo_unused_funcs_impl)
++# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++# define lzo_unused_funcs_impl(r,f) static r __attribute__((__unused__)) f
++# elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC)
++# define lzo_unused_funcs_impl(r,f) static r f
++# else
++# define lzo_unused_funcs_impl(r,f) __lzo_static_forceinline r f
++# endif
++#endif
+ #ifndef __LZO_CTA_NAME
+ #if (LZO_CFG_USE_COUNTER)
+ # define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__COUNTER__)
+@@ -1881,6 +2005,8 @@ extern "C" {
+ #if !defined(LZO_COMPILE_TIME_ASSERT)
+ # if (LZO_CC_AZTECC)
+ # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];}
++# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul))
++# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}
+ # elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+ # define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+ # elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)
+@@ -1897,11 +2023,16 @@ extern "C" {
+ # define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];}
+ # endif
+ #endif
++#if (LZO_LANG_ASSEMBLER)
++# undef LZO_COMPILE_TIME_ASSERT_HEADER
++# define LZO_COMPILE_TIME_ASSERT_HEADER(e) /*empty*/
++#else
+ LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1)
+ #if defined(__cplusplus)
+ extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) }
+ #endif
+ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
++#endif
+ #if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+ # if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+ # elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+@@ -1968,7 +2099,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
+ #if !defined(LZO_HAVE_WINDOWS_H)
+ #if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+ # if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+-# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
++# elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul)))
+ # elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+ # else
+ # define LZO_HAVE_WINDOWS_H 1
+@@ -1976,6 +2107,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
+ #endif
+ #endif
+ #endif
++#define LZO_SIZEOF_CHAR 1
+ #ifndef LZO_SIZEOF_SHORT
+ #if defined(SIZEOF_SHORT)
+ # define LZO_SIZEOF_SHORT (SIZEOF_SHORT)
+@@ -2174,12 +2306,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long))
+ # define LZO_WORDSIZE 8
+ #elif (LZO_ARCH_AMD64)
+ # define LZO_WORDSIZE 8
++#elif (LZO_ARCH_ARM64)
++# define LZO_WORDSIZE 8
+ #elif (LZO_ARCH_AVR)
+ # define LZO_WORDSIZE 1
+ #elif (LZO_ARCH_H8300)
+-# if defined(__NORMAL_MODE__)
+-# define LZO_WORDSIZE 4
+-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+ # define LZO_WORDSIZE 4
+ # else
+ # define LZO_WORDSIZE 2
+@@ -2222,11 +2354,15 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)
+ #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+ # define LZO_SIZEOF_VOID_P 2
+ #elif (LZO_ARCH_H8300)
+-# if defined(__NORMAL_MODE__)
+-# define LZO_SIZEOF_VOID_P 2
+-# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+-# define LZO_SIZEOF_VOID_P 4
++# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 4)
++# if defined(__NORMAL_MODE__)
++# define LZO_SIZEOF_VOID_P 2
++# else
++# define LZO_SIZEOF_VOID_P 4
++# endif
+ # else
++ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 2)
+ # define LZO_SIZEOF_VOID_P 2
+ # endif
+ # if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+@@ -2316,7 +2452,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+ # define LZO_ABI_LITTLE_ENDIAN 1
+-#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
++#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430 || LZO_ARCH_RISCV)
+ # define LZO_ABI_LITTLE_ENDIAN 1
+ #elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU)
+ # define LZO_ABI_BIG_ENDIAN 1
+@@ -2330,10 +2466,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)
++# define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM) && defined(_MSC_VER) && defined(_WIN32)
++# define LZO_ABI_LITTLE_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC)
+ # if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)
+ # error "unexpected configuration - check your compiler defines"
+@@ -2343,10 +2483,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_LITTLE_ENDIAN 1
+ # endif
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0)
++# define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__)
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__)
+ # define LZO_ABI_LITTLE_ENDIAN 1
++#elif 1 && (LZO_ARCH_ARM64) && defined(_MSC_VER) && defined(_WIN32)
++# define LZO_ABI_LITTLE_ENDIAN 1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+ # define LZO_ABI_BIG_ENDIAN 1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+@@ -2388,6 +2532,12 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # define LZO_ABI_IP32L64 1
+ # define LZO_INFO_ABI_PM "ip32l64"
+ #endif
++#if (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_VOID_P == 4 && LZO_WORDSIZE == 8)
++# define LZO_ABI_IP32W64 1
++# ifndef LZO_INFO_ABI_PM
++# define LZO_INFO_ABI_PM "ip32w64"
++# endif
++#endif
+ #if 0
+ #elif !defined(__LZO_LIBC_OVERRIDE)
+ #if (LZO_LIBC_NAKED)
+@@ -2475,20 +2625,43 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # endif
+ #elif (LZO_ARCH_ARM)
+ # if defined(__ARM_FEATURE_UNALIGNED)
++# if ((__ARM_FEATURE_UNALIGNED)+0)
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# endif
++# elif 1 && (LZO_ARCH_ARM_THUMB2)
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# elif 1 && defined(__ARM_ARCH) && ((__ARM_ARCH)+0 >= 7)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+ # ifndef LZO_OPT_UNALIGNED32
+ # define LZO_OPT_UNALIGNED32 1
+ # endif
+-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 7)
++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+ # ifndef LZO_OPT_UNALIGNED32
+ # define LZO_OPT_UNALIGNED32 1
+ # endif
+-# elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 6) && !defined(__TARGET_PROFILE_M)
++# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R))
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# elif 1 && defined(_MSC_VER) && defined(_M_ARM) && ((_M_ARM)+0 >= 7)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+@@ -2540,7 +2713,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ #elif (LZO_ARCH_POWERPC)
+ # define LZO_OPT_PREFER_PREINC 1
+ # define LZO_OPT_PREFER_PREDEC 1
+-# if (LZO_ABI_BIG_ENDIAN)
++# if (LZO_ABI_BIG_ENDIAN) || (LZO_WORDSIZE == 8)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+ # endif
+@@ -2553,6 +2726,19 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ # endif
+ # endif
+ # endif
++#elif (LZO_ARCH_RISCV)
++# define LZO_OPT_AVOID_UINT_INDEX 1
++# ifndef LZO_OPT_UNALIGNED16
++# define LZO_OPT_UNALIGNED16 1
++# endif
++# ifndef LZO_OPT_UNALIGNED32
++# define LZO_OPT_UNALIGNED32 1
++# endif
++# if (LZO_WORDSIZE == 8)
++# ifndef LZO_OPT_UNALIGNED64
++# define LZO_OPT_UNALIGNED64 1
++# endif
++# endif
+ #elif (LZO_ARCH_S390)
+ # ifndef LZO_OPT_UNALIGNED16
+ # define LZO_OPT_UNALIGNED16 1
+@@ -2644,32 +2830,61 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
+ #if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0))
+ # error "missing defines for sizes"
+ #endif
++#define LZO_TYPEOF_CHAR 1u
++#define LZO_TYPEOF_SHORT 2u
++#define LZO_TYPEOF_INT 3u
++#define LZO_TYPEOF_LONG 4u
++#define LZO_TYPEOF_LONG_LONG 5u
++#define LZO_TYPEOF___INT8 17u
++#define LZO_TYPEOF___INT16 18u
++#define LZO_TYPEOF___INT32 19u
++#define LZO_TYPEOF___INT64 20u
++#define LZO_TYPEOF___INT128 21u
++#define LZO_TYPEOF___INT256 22u
++#define LZO_TYPEOF___MODE_QI 33u
++#define LZO_TYPEOF___MODE_HI 34u
++#define LZO_TYPEOF___MODE_SI 35u
++#define LZO_TYPEOF___MODE_DI 36u
++#define LZO_TYPEOF___MODE_TI 37u
++#define LZO_TYPEOF_CHAR_P 129u
+ #if !defined(lzo_llong_t)
+ #if (LZO_SIZEOF_LONG_LONG+0 > 0)
+-__lzo_gnuc_extension__ typedef long long lzo_llong_t__;
+-__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
++# if !(LZO_LANG_ASSEMBLER)
++ __lzo_gnuc_extension__ typedef long long lzo_llong_t__;
++ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
++# endif
+ # define lzo_llong_t lzo_llong_t__
+ # define lzo_ullong_t lzo_ullong_t__
+ #endif
+ #endif
+ #if !defined(lzo_int16e_t)
+-#if (LZO_SIZEOF_LONG == 2)
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) && (LZO_SIZEOF_SHORT != 2)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T
++#endif
++#if (LZO_SIZEOF_LONG == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT)
+ # define lzo_int16e_t long
+ # define lzo_uint16e_t unsigned long
+-#elif (LZO_SIZEOF_INT == 2)
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG
++#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT)
+ # define lzo_int16e_t int
+ # define lzo_uint16e_t unsigned int
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_SHORT == 2)
+ # define lzo_int16e_t short int
+ # define lzo_uint16e_t unsigned short int
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_SHORT
+ #elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)
++# if !(LZO_LANG_ASSEMBLER)
+ typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));
+ typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));
++# endif
+ # define lzo_int16e_t lzo_int16e_hi_t__
+ # define lzo_uint16e_t lzo_uint16e_hi_t__
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI
+ #elif (LZO_SIZEOF___INT16 == 2)
+ # define lzo_int16e_t __int16
+ # define lzo_uint16e_t unsigned __int16
++# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16
+ #else
+ #endif
+ #endif
+@@ -2679,33 +2894,47 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T)
+ #endif
+ #if !defined(lzo_int32e_t)
+-#if (LZO_SIZEOF_LONG == 4)
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) && (LZO_SIZEOF_INT != 4)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T
++#endif
++#if (LZO_SIZEOF_LONG == 4) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT)
+ # define lzo_int32e_t long int
+ # define lzo_uint32e_t unsigned long int
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG
+ #elif (LZO_SIZEOF_INT == 4)
+ # define lzo_int32e_t int
+ # define lzo_uint32e_t unsigned int
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_SHORT == 4)
+ # define lzo_int32e_t short int
+ # define lzo_uint32e_t unsigned short int
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_SHORT
+ #elif (LZO_SIZEOF_LONG_LONG == 4)
+ # define lzo_int32e_t lzo_llong_t
+ # define lzo_uint32e_t lzo_ullong_t
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG_LONG
+ #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)
++# if !(LZO_LANG_ASSEMBLER)
+ typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
+ typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++# endif
+ # define lzo_int32e_t lzo_int32e_si_t__
+ # define lzo_uint32e_t lzo_uint32e_si_t__
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI
+ #elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)
++# if !(LZO_LANG_ASSEMBLER)
+ typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
+ typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++# endif
+ # define lzo_int32e_t lzo_int32e_si_t__
+ # define lzo_uint32e_t lzo_uint32e_si_t__
+ # define LZO_INT32_C(c) (c##LL)
+ # define LZO_UINT32_C(c) (c##ULL)
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI
+ #elif (LZO_SIZEOF___INT32 == 4)
+ # define lzo_int32e_t __int32
+ # define lzo_uint32e_t unsigned __int32
++# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32
+ #else
+ #endif
+ #endif
+@@ -2716,21 +2945,28 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #endif
+ #if !defined(lzo_int64e_t)
+ #if (LZO_SIZEOF___INT64 == 8)
+-# if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64)
+-# define LZO_CFG_TYPE_PREFER___INT64 1
++# if (LZO_CC_BORLANDC) && !defined(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T)
++# define LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T LZO_TYPEOF___INT64
+ # endif
+ #endif
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && (LZO_SIZEOF_LONG_LONG != 8)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T
++#endif
++#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) && (LZO_SIZEOF___INT64 != 8)
++# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T
++#endif
+ #if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
+ # define lzo_int64e_t int
+ # define lzo_uint64e_t unsigned int
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_INT
+-#elif (LZO_SIZEOF_LONG == 8)
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT
++#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64)
+ # define lzo_int64e_t long int
+ # define lzo_uint64e_t unsigned long int
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG
+-#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64)
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG
++#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64)
+ # define lzo_int64e_t lzo_llong_t
+ # define lzo_uint64e_t lzo_ullong_t
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG_LONG
+ # if (LZO_CC_BORLANDC)
+ # define LZO_INT64_C(c) ((c) + 0ll)
+ # define LZO_UINT64_C(c) ((c) + 0ull)
+@@ -2741,10 +2977,10 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define LZO_INT64_C(c) (c##LL)
+ # define LZO_UINT64_C(c) (c##ULL)
+ # endif
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF_LONG_LONG
+ #elif (LZO_SIZEOF___INT64 == 8)
+ # define lzo_int64e_t __int64
+ # define lzo_uint64e_t unsigned __int64
++# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF___INT64
+ # if (LZO_CC_BORLANDC)
+ # define LZO_INT64_C(c) ((c) + 0i64)
+ # define LZO_UINT64_C(c) ((c) + 0ui64)
+@@ -2752,11 +2988,11 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define LZO_INT64_C(c) (c##i64)
+ # define LZO_UINT64_C(c) (c##ui64)
+ # endif
+-# define LZO_SIZEOF_LZO_INT64E_T LZO_SIZEOF___INT64
+ #else
+ #endif
+ #endif
+ #if defined(lzo_int64e_t)
++# define LZO_SIZEOF_LZO_INT64E_T 8
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T)
+ #endif
+@@ -2765,14 +3001,17 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int32l_t lzo_int32e_t
+ # define lzo_uint32l_t lzo_uint32e_t
+ # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LZO_INT32E_T
++# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T
+ #elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
+ # define lzo_int32l_t int
+ # define lzo_uint32l_t unsigned int
+ # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT
+ #elif (LZO_SIZEOF_LONG >= 4)
+ # define lzo_int32l_t long int
+ # define lzo_uint32l_t unsigned long int
+ # define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LONG
++# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_LONG
+ #else
+ # error "lzo_int32l_t"
+ #endif
+@@ -2786,6 +3025,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int64l_t lzo_int64e_t
+ # define lzo_uint64l_t lzo_uint64e_t
+ # define LZO_SIZEOF_LZO_INT64L_T LZO_SIZEOF_LZO_INT64E_T
++# define LZO_TYPEOF_LZO_INT64L_T LZO_TYPEOF_LZO_INT64E_T
+ #else
+ #endif
+ #endif
+@@ -2798,10 +3038,12 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int32f_t lzo_int64l_t
+ # define lzo_uint32f_t lzo_uint64l_t
+ # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT64L_T
+ #else
+ # define lzo_int32f_t lzo_int32l_t
+ # define lzo_uint32f_t lzo_uint32l_t
+ # define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT32L_T
++# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT32L_T
+ #endif
+ #endif
+ #if 1
+@@ -2813,6 +3055,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ # define lzo_int64f_t lzo_int64l_t
+ # define lzo_uint64f_t lzo_uint64l_t
+ # define LZO_SIZEOF_LZO_INT64F_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_INT64F_T LZO_TYPEOF_LZO_INT64L_T
+ #else
+ #endif
+ #endif
+@@ -2823,33 +3066,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #if !defined(lzo_intptr_t)
+ #if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16))
+ # define __LZO_INTPTR_T_IS_POINTER 1
+- typedef char* lzo_intptr_t;
+- typedef char* lzo_uintptr_t;
++# if !(LZO_LANG_ASSEMBLER)
++ typedef char * lzo_intptr_t;
++ typedef char * lzo_uintptr_t;
++# endif
+ # define lzo_intptr_t lzo_intptr_t
+ # define lzo_uintptr_t lzo_uintptr_t
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_VOID_P
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_CHAR_P
+ #elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))
++# if !(LZO_LANG_ASSEMBLER)
+ typedef __w64 int lzo_intptr_t;
+ typedef __w64 unsigned int lzo_uintptr_t;
++# endif
+ # define lzo_intptr_t lzo_intptr_t
+ # define lzo_uintptr_t lzo_uintptr_t
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P)
+ # define lzo_intptr_t short
+ # define lzo_uintptr_t unsigned short
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_SHORT
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT
+ #elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
+ # define lzo_intptr_t int
+ # define lzo_uintptr_t unsigned int
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT
+ #elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)
+ # define lzo_intptr_t long
+ # define lzo_uintptr_t unsigned long
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LONG
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LONG
+ #elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P)
+ # define lzo_intptr_t lzo_int64l_t
+ # define lzo_uintptr_t lzo_uint64l_t
+ # define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LZO_INT64L_T
+ #else
+ # error "lzo_intptr_t"
+ #endif
+@@ -2863,34 +3116,43 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER)
+ # define lzo_word_t lzo_uintptr_t
+ # define lzo_sword_t lzo_intptr_t
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LZO_INTPTR_T
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_LONG)
+ # define lzo_word_t unsigned long
+ # define lzo_sword_t long
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_INT)
+ # define lzo_word_t unsigned int
+ # define lzo_sword_t int
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT)
+ # define lzo_word_t unsigned short
+ # define lzo_sword_t short
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_SHORT
+ #elif (LZO_WORDSIZE == 1)
+ # define lzo_word_t unsigned char
+ # define lzo_sword_t signed char
+-# define LZO_SIZEOF_LZO_WORD_T 1
++# define LZO_SIZEOF_LZO_WORD_T 1
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_CHAR
+ #elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T)
+ # define lzo_word_t lzo_uint64l_t
+ # define lzo_sword_t lzo_int64l_t
+-# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
++# define LZO_TYPEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
+ #elif (LZO_ARCH_SPU) && (LZO_CC_GNUC)
+ #if 0
++# if !(LZO_LANG_ASSEMBLER)
+ typedef unsigned lzo_word_t __attribute__((__mode__(__V16QI__)));
+ typedef int lzo_sword_t __attribute__((__mode__(__V16QI__)));
++# endif
+ # define lzo_word_t lzo_word_t
+ # define lzo_sword_t lzo_sword_t
+ # define LZO_SIZEOF_LZO_WORD_T 16
++# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF___MODE_V16QI
+ #endif
+ #else
+ # error "lzo_word_t"
+@@ -2905,6 +3167,7 @@ __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
+ #define lzo_int8_t signed char
+ #define lzo_uint8_t unsigned char
+ #define LZO_SIZEOF_LZO_INT8_T 1
++#define LZO_TYPEOF_LZO_INT8_T LZO_TYPEOF_CHAR
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))
+ #endif
+@@ -2912,6 +3175,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))
+ #define lzo_int16_t lzo_int16e_t
+ #define lzo_uint16_t lzo_uint16e_t
+ #define LZO_SIZEOF_LZO_INT16_T LZO_SIZEOF_LZO_INT16E_T
++#define LZO_TYPEOF_LZO_INT16_T LZO_TYPEOF_LZO_INT16E_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))
+ #endif
+@@ -2919,6 +3183,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))
+ #define lzo_int32_t lzo_int32e_t
+ #define lzo_uint32_t lzo_uint32e_t
+ #define LZO_SIZEOF_LZO_INT32_T LZO_SIZEOF_LZO_INT32E_T
++#define LZO_TYPEOF_LZO_INT32_T LZO_TYPEOF_LZO_INT32E_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))
+ #endif
+@@ -2926,6 +3191,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))
+ #define lzo_int64_t lzo_int64e_t
+ #define lzo_uint64_t lzo_uint64e_t
+ #define LZO_SIZEOF_LZO_INT64_T LZO_SIZEOF_LZO_INT64E_T
++#define LZO_TYPEOF_LZO_INT64_T LZO_TYPEOF_LZO_INT64E_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))
+ #endif
+@@ -2933,6 +3199,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))
+ #define lzo_int_least32_t lzo_int32l_t
+ #define lzo_uint_least32_t lzo_uint32l_t
+ #define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T
++#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t))
+ #endif
+@@ -2940,6 +3207,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_leas
+ #define lzo_int_least64_t lzo_int64l_t
+ #define lzo_uint_least64_t lzo_uint64l_t
+ #define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T
++#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t))
+ #endif
+@@ -2947,6 +3215,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_leas
+ #define lzo_int_fast32_t lzo_int32f_t
+ #define lzo_uint_fast32_t lzo_uint32f_t
+ #define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T
++#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t))
+ #endif
+@@ -2954,6 +3223,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast3
+ #define lzo_int_fast64_t lzo_int64f_t
+ #define lzo_uint_fast64_t lzo_uint64f_t
+ #define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T
++#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t))
+ #endif
+@@ -3020,7 +3290,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6
+ #undef LZO_HAVE_CONFIG_H
+ #include "minilzo.h"
+
+-#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2080)
++#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x20a0)
+ # error "version mismatch in miniLZO source files"
+ #endif
+
+@@ -3042,13 +3312,23 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6
+ #if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED)
+ # error "include this file first"
+ #endif
+-#include "lzo/lzoconf.h"
++#if defined(LZO_CFG_BUILD_DLL) && (LZO_CFG_BUILD_DLL+0) && !defined(__LZO_EXPORT1) && !defined(__LZO_EXPORT2) && 0
++#ifndef __LZODEFS_H_INCLUDED
++#if defined(LZO_HAVE_CONFIG_H)
++# include <config.h>
++#endif
++#include <limits.h>
++#include <stddef.h>
++#include <lzo/lzodefs.h>
++#endif
++#endif
++#include <lzo/lzoconf.h>
+ #if defined(LZO_CFG_EXTRA_CONFIG_HEADER2)
+ # include LZO_CFG_EXTRA_CONFIG_HEADER2
+ #endif
+ #endif
+
+-#if (LZO_VERSION < 0x2080) || !defined(__LZOCONF_H_INCLUDED)
++#if !defined(__LZOCONF_H_INCLUDED) || (LZO_VERSION+0 != 0x20a0)
+ # error "version mismatch"
+ #endif
+
+@@ -3065,6 +3345,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6
+ #if (LZO_CC_MSC && (_MSC_VER >= 1800))
+ # pragma warning(disable: 4746)
+ #endif
++#if (LZO_CC_INTELC && (__INTEL_COMPILER >= 900))
++# pragma warning(disable: 1684)
++#endif
+
+ #if (LZO_CC_SUNPROC)
+ #if !defined(__cplusplus)
+@@ -3074,6 +3357,32 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast6
+ #endif
+ #endif
+
++#if !defined(__LZO_NOEXPORT1)
++# define __LZO_NOEXPORT1 /*empty*/
++#endif
++#if !defined(__LZO_NOEXPORT2)
++# define __LZO_NOEXPORT2 /*empty*/
++#endif
++
++#if 1
++# define LZO_PUBLIC_DECL(r) LZO_EXTERN(r)
++#endif
++#if 1
++# define LZO_PUBLIC_IMPL(r) LZO_PUBLIC(r)
++#endif
++#if !defined(LZO_LOCAL_DECL)
++# define LZO_LOCAL_DECL(r) __LZO_EXTERN_C LZO_LOCAL_IMPL(r)
++#endif
++#if !defined(LZO_LOCAL_IMPL)
++# define LZO_LOCAL_IMPL(r) __LZO_NOEXPORT1 r __LZO_NOEXPORT2 __LZO_CDECL
++#endif
++#if 1
++# define LZO_STATIC_DECL(r) LZO_PRIVATE(r)
++#endif
++#if 1
++# define LZO_STATIC_IMPL(r) LZO_PRIVATE(r)
++#endif
++
+ #if defined(__LZO_IN_MINILZO) || (LZO_CFG_FREESTANDING)
+ #elif 1
+ # include <string.h>
+@@ -3269,6 +3578,9 @@ __lzo_static_forceinline unsigned lzo_bitops_ctlz32_func(lzo_uint32_t v)
+ #elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT == 4)
+ unsigned r; r = (unsigned) __builtin_clz(v); return r;
+ #define lzo_bitops_ctlz32(v) ((unsigned) __builtin_clz(v))
++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG == 8) && (LZO_WORDSIZE >= 8)
++ unsigned r; r = (unsigned) __builtin_clzl(v); return r ^ 32;
++#define lzo_bitops_ctlz32(v) (((unsigned) __builtin_clzl(v)) ^ 32)
+ #else
+ LZO_UNUSED(v); return 0;
+ #endif
+@@ -3338,25 +3650,20 @@ __lzo_static_forceinline unsigned lzo_bitops_cttz64_func(lzo_uint64_t v)
+ }
+ #endif
+
+-#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-static void __attribute__((__unused__))
+-#else
+-__lzo_static_forceinline void
+-#endif
+-lzo_bitops_unused_funcs(void)
++lzo_unused_funcs_impl(void, lzo_bitops_unused_funcs)(void)
+ {
++ LZO_UNUSED_FUNC(lzo_bitops_unused_funcs);
+ LZO_UNUSED_FUNC(lzo_bitops_ctlz32_func);
+ LZO_UNUSED_FUNC(lzo_bitops_cttz32_func);
+ #if defined(lzo_uint64_t)
+ LZO_UNUSED_FUNC(lzo_bitops_ctlz64_func);
+ LZO_UNUSED_FUNC(lzo_bitops_cttz64_func);
+ #endif
+- LZO_UNUSED_FUNC(lzo_bitops_unused_funcs);
+ }
+
+ #if defined(__lzo_alignof) && !(LZO_CFG_NO_UNALIGNED)
+-#ifndef __lzo_memops_tcheck
+-#define __lzo_memops_tcheck(t,a,b) ((void)0, sizeof(t) == (a) && __lzo_alignof(t) == (b))
++#if !defined(lzo_memops_tcheck__) && 0
++#define lzo_memops_tcheck__(t,a,b) ((void)0, sizeof(t) == (a) && __lzo_alignof(t) == (b))
+ #endif
+ #endif
+ #ifndef lzo_memops_TU0p
+@@ -3473,9 +3780,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU1p)0)==1)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2)
+ #define LZO_MEMOPS_COPY2(dd,ss) \
+ * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)
+-#elif defined(__lzo_memops_tcheck)
++#elif defined(lzo_memops_tcheck__)
+ #define LZO_MEMOPS_COPY2(dd,ss) \
+- LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU2,2,1)) { \
++ LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU2,2,1)) { \
+ * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss); \
+ } else { LZO_MEMOPS_MOVE2(dd,ss); } LZO_BLOCK_END
+ #else
+@@ -3485,9 +3792,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4)
+ #define LZO_MEMOPS_COPY4(dd,ss) \
+ * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)
+-#elif defined(__lzo_memops_tcheck)
++#elif defined(lzo_memops_tcheck__)
+ #define LZO_MEMOPS_COPY4(dd,ss) \
+- LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU4,4,1)) { \
++ LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU4,4,1)) { \
+ * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss); \
+ } else { LZO_MEMOPS_MOVE4(dd,ss); } LZO_BLOCK_END
+ #else
+@@ -3504,9 +3811,9 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8)
+ #elif (LZO_OPT_UNALIGNED32)
+ #define LZO_MEMOPS_COPY8(dd,ss) \
+ LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END
+-#elif defined(__lzo_memops_tcheck)
++#elif defined(lzo_memops_tcheck__)
+ #define LZO_MEMOPS_COPY8(dd,ss) \
+- LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU8,8,1)) { \
++ LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU8,8,1)) { \
+ * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss); \
+ } else { LZO_MEMOPS_MOVE8(dd,ss); } LZO_BLOCK_END
+ #else
+@@ -3540,7 +3847,7 @@ __lzo_static_forceinline lzo_uint16_t lzo_memops_get_le16(const lzo_voidp ss)
+ return v;
+ }
+ #if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
+-#define LZO_MEMOPS_GET_LE16(ss) * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)
++#define LZO_MEMOPS_GET_LE16(ss) (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss))
+ #else
+ #define LZO_MEMOPS_GET_LE16(ss) lzo_memops_get_le16(ss)
+ #endif
+@@ -3562,13 +3869,13 @@ __lzo_static_forceinline lzo_uint32_t lzo_memops_get_le32(const lzo_voidp ss)
+ return v;
+ }
+ #if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN)
+-#define LZO_MEMOPS_GET_LE32(ss) * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)
++#define LZO_MEMOPS_GET_LE32(ss) (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss))
+ #else
+ #define LZO_MEMOPS_GET_LE32(ss) lzo_memops_get_le32(ss)
+ #endif
+
+ #if (LZO_OPT_UNALIGNED64) && (LZO_ABI_LITTLE_ENDIAN)
+-#define LZO_MEMOPS_GET_LE64(ss) * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)
++#define LZO_MEMOPS_GET_LE64(ss) (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss))
+ #endif
+
+ __lzo_static_forceinline lzo_uint16_t lzo_memops_get_ne16(const lzo_voidp ss)
+@@ -3578,7 +3885,8 @@ __lzo_static_forceinline lzo_uint16_t lzo_memops_get_ne16(const lzo_voidp ss)
+ return v;
+ }
+ #if (LZO_OPT_UNALIGNED16)
+-#define LZO_MEMOPS_GET_NE16(ss) * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2)
++#define LZO_MEMOPS_GET_NE16(ss) (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss))
+ #else
+ #define LZO_MEMOPS_GET_NE16(ss) lzo_memops_get_ne16(ss)
+ #endif
+@@ -3590,13 +3898,15 @@ __lzo_static_forceinline lzo_uint32_t lzo_memops_get_ne32(const lzo_voidp ss)
+ return v;
+ }
+ #if (LZO_OPT_UNALIGNED32)
+-#define LZO_MEMOPS_GET_NE32(ss) * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4)
++#define LZO_MEMOPS_GET_NE32(ss) (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss))
+ #else
+ #define LZO_MEMOPS_GET_NE32(ss) lzo_memops_get_ne32(ss)
+ #endif
+
+ #if (LZO_OPT_UNALIGNED64)
+-#define LZO_MEMOPS_GET_NE64(ss) * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8)
++#define LZO_MEMOPS_GET_NE64(ss) (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss))
+ #endif
+
+ __lzo_static_forceinline void lzo_memops_put_le16(lzo_voidp dd, lzo_uint16_t vv)
+@@ -3661,13 +3971,9 @@ __lzo_static_forceinline void lzo_memops_put_ne32(lzo_voidp dd, lzo_uint32_t vv)
+ #define LZO_MEMOPS_PUT_NE32(dd,vv) lzo_memops_put_ne32(dd,vv)
+ #endif
+
+-#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-static void __attribute__((__unused__))
+-#else
+-__lzo_static_forceinline void
+-#endif
+-lzo_memops_unused_funcs(void)
++lzo_unused_funcs_impl(void, lzo_memops_unused_funcs)(void)
+ {
++ LZO_UNUSED_FUNC(lzo_memops_unused_funcs);
+ LZO_UNUSED_FUNC(lzo_memops_get_le16);
+ LZO_UNUSED_FUNC(lzo_memops_get_le32);
+ LZO_UNUSED_FUNC(lzo_memops_get_ne16);
+@@ -3676,7 +3982,6 @@ lzo_memops_unused_funcs(void)
+ LZO_UNUSED_FUNC(lzo_memops_put_le32);
+ LZO_UNUSED_FUNC(lzo_memops_put_ne16);
+ LZO_UNUSED_FUNC(lzo_memops_put_ne32);
+- LZO_UNUSED_FUNC(lzo_memops_unused_funcs);
+ }
+
+ #endif
+@@ -3889,11 +4194,16 @@ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+ #error "__LZO_UINTPTR_T_IS_POINTER is unsupported"
+ #else
+ lzo_uintptr_t p, n;
++ if (size < 2) return 0;
+ p = __lzo_ptr_linear(ptr);
++#if 0
+ n = (((p + size - 1) / size) * size) - p;
++#else
++ if ((size & (size - 1)) != 0)
++ return 0;
++ n = size; n = ((p + n - 1) & ~(n - 1)) - p;
++#endif
+ #endif
+-
+- assert(size > 0);
+ assert((long)n >= 0);
+ assert(n <= size);
+ return (unsigned)n;
+@@ -3906,23 +4216,25 @@ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+ * keep this copyright string in the executable of your product.
+ */
+
+-static const char __lzo_copyright[] =
++static const char lzo_copyright_[] =
+ #if !defined(__LZO_IN_MINLZO)
+ LZO_VERSION_STRING;
+ #else
+ "\r\n\n"
+ "LZO data compression library.\n"
+- "$Copyright: LZO Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer\n"
++ "$Copyright: LZO Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer\n"
+ "<markus@oberhumer.com>\n"
+ "http://www.oberhumer.com $\n\n"
+ "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n"
+ "$Info: " LZO_INFO_STRING " $\n";
+ #endif
++static const char lzo_version_string_[] = LZO_VERSION_STRING;
++static const char lzo_version_date_[] = LZO_VERSION_DATE;
+
+ LZO_PUBLIC(const lzo_bytep)
+ lzo_copyright(void)
+ {
+- return (const lzo_bytep) __lzo_copyright;
++ return (const lzo_bytep) lzo_copyright_;
+ }
+
+ LZO_PUBLIC(unsigned)
+@@ -3934,25 +4246,25 @@ lzo_version(void)
+ LZO_PUBLIC(const char *)
+ lzo_version_string(void)
+ {
+- return LZO_VERSION_STRING;
++ return lzo_version_string_;
+ }
+
+ LZO_PUBLIC(const char *)
+ lzo_version_date(void)
+ {
+- return LZO_VERSION_DATE;
++ return lzo_version_date_;
+ }
+
+ LZO_PUBLIC(const lzo_charp)
+ _lzo_version_string(void)
+ {
+- return LZO_VERSION_STRING;
++ return lzo_version_string_;
+ }
+
+ LZO_PUBLIC(const lzo_charp)
+ _lzo_version_date(void)
+ {
+- return LZO_VERSION_DATE;
++ return lzo_version_date_;
+ }
+
+ #define LZO_BASE 65521u
+@@ -4324,7 +4636,7 @@ int __far __pascal LibMain ( int a, short b, short c, long d )
+ #endif
+
+ #if !defined(__LZO_IN_MINILZO)
+-#include "lzo/lzo1x.h"
++#include <lzo/lzo1x.h>
+ #endif
+
+ #ifndef LZO_EOF_CODE
+@@ -4516,7 +4828,7 @@ extern "C" {
+
+ #if !defined(DVAL_ASSERT)
+ #if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
+-#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM)
++#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+ static void __attribute__((__unused__))
+ #else
+ static void
+diff --git a/grub-core/lib/minilzo/minilzo.h b/grub-core/lib/minilzo/minilzo.h
+index 793745467..c1c229757 100644
+--- a/grub-core/lib/minilzo/minilzo.h
++++ b/grub-core/lib/minilzo/minilzo.h
+@@ -2,7 +2,7 @@
+
+ This file is part of the LZO real-time data compression library.
+
+- Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
++ Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library is free software; you can redistribute it and/or
+@@ -32,15 +32,25 @@
+ */
+
+
+-#ifndef __MINILZO_H
+-#define __MINILZO_H 1
++#ifndef __MINILZO_H_INCLUDED
++#define __MINILZO_H_INCLUDED 1
+
+-#define MINILZO_VERSION 0x2080
++#define MINILZO_VERSION 0x20a0 /* 2.10 */
+
+-#ifdef __LZOCONF_H
++#if defined(__LZOCONF_H_INCLUDED)
+ # error "you cannot use both LZO and miniLZO"
+ #endif
+
++/* internal Autoconf configuration file - only used when building miniLZO */
++#ifdef MINILZO_HAVE_CONFIG_H
++# include <config.h>
++#endif
++#include <limits.h>
++#include <stddef.h>
++
++#ifndef __LZODEFS_H_INCLUDED
++#include "lzodefs.h"
++#endif
+ #undef LZO_HAVE_CONFIG_H
+ #include "lzoconf.h"
+
+@@ -92,3 +102,5 @@ lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
+
+ #endif /* already included */
+
++
++/* vim:set ts=4 sw=4 et: */
diff --git a/debian/patches/mkconfig-loopback.patch b/debian/patches/mkconfig-loopback.patch
new file mode 100644
index 0000000..686117f
--- /dev/null
+++ b/debian/patches/mkconfig-loopback.patch
@@ -0,0 +1,96 @@
+From 3f0c88e2ffa15cfb34641397cc9bdbe39085f1ba Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:13:00 +0000
+Subject: Handle filesystems loop-mounted on file images
+
+Improve prepare_grub_to_access_device to emit appropriate commands for
+such filesystems, and ignore them in Linux grub.d scripts.
+
+This is needed for Ubuntu's Wubi installation method.
+
+This patch isn't inherently Debian/Ubuntu-specific. losetup and
+/proc/mounts are Linux-specific, though, so we might need to refine this
+before sending it upstream. The changes to the Linux grub.d scripts
+might be better handled by integrating 10_lupin properly instead.
+
+Patch-Name: mkconfig-loopback.patch
+---
+ util/grub-mkconfig_lib.in | 24 ++++++++++++++++++++++++
+ util/grub.d/10_linux.in | 5 +++++
+ util/grub.d/20_linux_xen.in | 5 +++++
+ 3 files changed, 34 insertions(+)
+
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 17f9b3e58..e62cfc22b 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -133,6 +133,22 @@ prepare_grub_to_access_device ()
+ esac
+ done
+
++ loop_file=
++ case $1 in
++ /dev/loop/*|/dev/loop[0-9])
++ grub_loop_device="${1#/dev/}"
++ loop_file=`losetup "$1" | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
++ case $loop_file in
++ /dev/*) ;;
++ *)
++ loop_device="$1"
++ shift
++ set -- `"${grub_probe}" --target=device "${loop_file}"` "$@"
++ ;;
++ esac
++ ;;
++ esac
++
+ # Abstraction modules aren't auto-loaded.
+ abstraction="`"${grub_probe}" --device $@ --target=abstraction`"
+ for module in ${abstraction} ; do
+@@ -169,6 +185,14 @@ prepare_grub_to_access_device ()
+ fi
+ fi
+ IFS="$old_ifs"
++
++ if [ "x${loop_file}" != x ]; then
++ loop_mountpoint="$(awk '"'${loop_file}'" ~ "^"$2 && $2 != "/" { print $2 }' /proc/mounts | tail -n1)"
++ if [ "x${loop_mountpoint}" != x ]; then
++ echo "loopback ${grub_loop_device} ${loop_file#$loop_mountpoint}"
++ echo "set root=(${grub_loop_device})"
++ fi
++ fi
+ }
+
+ grub_get_device_id ()
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 9446d6833..46696dd66 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -40,6 +40,11 @@ fi
+ case ${GRUB_DEVICE} in
+ /dev/loop/*|/dev/loop[0-9])
+ GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
++ # We can't cope with devices loop-mounted from files here.
++ case ${GRUB_DEVICE} in
++ /dev/*) ;;
++ *) exit 0 ;;
++ esac
+ ;;
+ esac
+
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index 3b1f47049..7620a14fa 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -40,6 +40,11 @@ fi
+ case ${GRUB_DEVICE} in
+ /dev/loop/*|/dev/loop[0-9])
+ GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
++ # We can't cope with devices loop-mounted from files here.
++ case ${GRUB_DEVICE} in
++ /dev/*) ;;
++ *) exit 0 ;;
++ esac
+ ;;
+ esac
+
diff --git a/debian/patches/mkconfig-nonexistent-loopback.patch b/debian/patches/mkconfig-nonexistent-loopback.patch
new file mode 100644
index 0000000..9c55c1d
--- /dev/null
+++ b/debian/patches/mkconfig-nonexistent-loopback.patch
@@ -0,0 +1,55 @@
+From 989f83d664999deeb28d03a847e8f00a28639d7d Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:08 +0000
+Subject: Avoid getting confused by inaccessible loop device backing paths
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/938724
+Forwarded: no
+Last-Update: 2021-09-24
+
+Patch-Name: mkconfig-nonexistent-loopback.patch
+---
+ util/grub-mkconfig_lib.in | 2 +-
+ util/grub.d/30_os-prober.in | 9 +++++----
+ 2 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index e62cfc22b..b6a1d7dec 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -143,7 +143,7 @@ prepare_grub_to_access_device ()
+ *)
+ loop_device="$1"
+ shift
+- set -- `"${grub_probe}" --target=device "${loop_file}"` "$@"
++ set -- `"${grub_probe}" --target=device "${loop_file}"` "$@" || return 0
+ ;;
+ esac
+ ;;
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 37d5f05b5..e2ec80eb9 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -222,6 +222,11 @@ EOF
+ LINITRD="${LINITRD#/boot}"
+ fi
+
++ if [ -z "${prepare_boot_cache}" ]; then
++ prepare_boot_cache="$(prepare_grub_to_access_device ${LBOOT} | grub_add_tab)"
++ [ "${prepare_boot_cache}" ] || continue
++ fi
++
+ onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+ recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true
+ counter=1
+@@ -233,10 +238,6 @@ EOF
+ fi
+ used_osprober_linux_ids="$used_osprober_linux_ids 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id'"
+
+- if [ -z "${prepare_boot_cache}" ]; then
+- prepare_boot_cache="$(prepare_grub_to_access_device ${LBOOT} | grub_add_tab)"
+- fi
+-
+ # The GRUB_DISABLE_SUBMENU option used to be different than others since it was
+ # mentioned in the documentation that has to be set to 'y' instead of 'true' to
+ # enable it. This caused a lot of confusion to users that set the option to 'y',
diff --git a/debian/patches/mkconfig-other-inits.patch b/debian/patches/mkconfig-other-inits.patch
new file mode 100644
index 0000000..75bf4e4
--- /dev/null
+++ b/debian/patches/mkconfig-other-inits.patch
@@ -0,0 +1,90 @@
+From f8382052a32839fbc3715d1c5076f1b6bbcbcb63 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Sat, 3 Jan 2015 12:04:59 +0000
+Subject: Generate alternative init entries in advanced menu
+
+Add fallback boot entries for alternative installed init systems. Based
+on patches from Michael Biebl and Didier Roche.
+
+Bug-Debian: https://bugs.debian.org/757298
+Bug-Debian: https://bugs.debian.org/773173
+Forwarded: no
+Last-Update: 2017-06-23
+
+Patch-Name: mkconfig-other-inits.patch
+---
+ util/grub.d/10_linux.in | 10 ++++++++++
+ util/grub.d/20_linux_xen.in | 11 +++++++++++
+ 2 files changed, 21 insertions(+)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 635c609d6..4e09797f8 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -32,6 +32,7 @@ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+
+ CLASS="--class gnu-linux --class gnu --class os"
++SUPPORTED_INITS="sysvinit:/lib/sysvinit/init systemd:/lib/systemd/systemd upstart:/sbin/upstart"
+
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+ OS=GNU/Linux
+@@ -127,6 +128,8 @@ linux_entry ()
+ case $type in
+ recovery)
+ title="$(gettext_printf "%s, with Linux %s (%s)" "${os}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" ;;
++ init-*)
++ title="$(gettext_printf "%s, with Linux %s (%s)" "${os}" "${version}" "${type#init-}")" ;;
+ *)
+ title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
+ esac
+@@ -389,6 +392,13 @@ while [ "x$list" != "x" ] ; do
+
+ linux_entry "${OS}" "${version}" advanced \
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++ for supported_init in ${SUPPORTED_INITS}; do
++ init_path="${supported_init#*:}"
++ if [ -x "${init_path}" ] && [ "$(readlink -f /sbin/init)" != "$(readlink -f "${init_path}")" ]; then
++ linux_entry "${OS}" "${version}" "init-${supported_init%%:*}" \
++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} init=${init_path}"
++ fi
++ done
+ if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+ linux_entry "${OS}" "${version}" recovery \
+ "${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}"
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index 64e26e4b4..d99751a94 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -27,6 +27,7 @@ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+
+ CLASS="--class gnu-linux --class gnu --class os --class xen"
++SUPPORTED_INITS="sysvinit:/lib/sysvinit/init systemd:/lib/systemd/systemd upstart:/sbin/upstart"
+
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+ OS=GNU/Linux
+@@ -123,6 +124,8 @@ linux_entry_xsm ()
+ if [ x$type != xsimple ] ; then
+ if [ x$type = xrecovery ] ; then
+ title="$(gettext_printf "%s, with Xen %s and Linux %s (%s)" "${os}" "${xen_version}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")"
++ elif [ "${type#init-}" != "$type" ] ; then
++ title="$(gettext_printf "%s, with Xen %s and Linux %s (%s)" "${os}" "${xen_version}" "${version}" "${type#init-}")"
+ else
+ title="$(gettext_printf "%s, with Xen %s and Linux %s" "${os}" "${xen_version}" "${version}")"
+ fi
+@@ -346,6 +349,14 @@ while [ "x${xen_list}" != "x" ] ; do
+
+ linux_entry "${OS}" "${version}" "${xen_version}" advanced \
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}"
++ for supported_init in ${SUPPORTED_INITS}; do
++ init_path="${supported_init#*:}"
++ if [ -x "${init_path}" ] && [ "$(readlink -f /sbin/init)" != "$(readlink -f "${init_path}")" ]; then
++ linux_entry "${OS}" "${version}" "${xen_version}" "init-${supported_init%%:*}" \
++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} init=${init_path}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}"
++
++ fi
++ done
+ if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+ linux_entry "${OS}" "${version}" "${xen_version}" recovery \
+ "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_XEN}"
diff --git a/debian/patches/mkconfig-recovery-title.patch b/debian/patches/mkconfig-recovery-title.patch
new file mode 100644
index 0000000..74c8b9e
--- /dev/null
+++ b/debian/patches/mkconfig-recovery-title.patch
@@ -0,0 +1,130 @@
+From fd81fffa2d498d66dce65b50da2532690c806ea4 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:33 +0000
+Subject: Add GRUB_RECOVERY_TITLE option
+
+This allows the controversial "recovery mode" text to be customised.
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1240360
+Forwarded: no
+Last-Update: 2013-12-25
+
+Patch-Name: mkconfig-recovery-title.patch
+---
+ docs/grub.texi | 5 +++++
+ util/grub-mkconfig.in | 7 ++++++-
+ util/grub.d/10_hurd.in | 4 ++--
+ util/grub.d/10_kfreebsd.in | 2 +-
+ util/grub.d/10_linux.in | 2 +-
+ util/grub.d/10_netbsd.in | 2 +-
+ util/grub.d/20_linux_xen.in | 2 +-
+ 7 files changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 0b58dafb2..86e46f33b 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -1577,6 +1577,11 @@ a console is restricted or limited.
+ This option is only effective when GRUB was configured with the
+ @option{--enable-quick-boot} option.
+
++@item GRUB_RECOVERY_TITLE
++This option sets the English text of the string that will be displayed in
++parentheses to indicate that a boot option is provided to help users recover
++a broken system. The default is "recovery mode".
++
+ @end table
+
+ The following options are still accepted for compatibility with existing
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index fa9c53a92..0d39c8f05 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -201,6 +201,10 @@ GRUB_ACTUAL_DEFAULT="$GRUB_DEFAULT"
+
+ if [ "x${GRUB_ACTUAL_DEFAULT}" = "xsaved" ] ; then GRUB_ACTUAL_DEFAULT="`"${grub_editenv}" - list | sed -n '/^saved_entry=/ s,^saved_entry=,,p'`" ; fi
+
++if [ "x${GRUB_RECOVERY_TITLE}" = "x" ]; then
++ GRUB_RECOVERY_TITLE="recovery mode"
++fi
++
+
+ # These are defined in this script, export them here so that user can
+ # override them.
+@@ -257,7 +261,8 @@ export GRUB_DEFAULT \
+ GRUB_BADRAM \
+ GRUB_OS_PROBER_SKIP_LIST \
+ GRUB_DISABLE_SUBMENU \
+- GRUB_RECORDFAIL_TIMEOUT
++ GRUB_RECORDFAIL_TIMEOUT \
++ GRUB_RECOVERY_TITLE
+
+ if test "x${grub_cfg}" != "x"; then
+ rm -f "${grub_cfg}.new"
+diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in
+index 3663d360e..8f6041894 100644
+--- a/util/grub.d/10_hurd.in
++++ b/util/grub.d/10_hurd.in
+@@ -88,8 +88,8 @@ hurd_entry () {
+
+ if [ x$type != xsimple ] ; then
+ if [ x$type = xrecovery ] ; then
+- title="$(gettext_printf "%s, with Hurd %s (recovery mode)" "${OS}" "${kernel_base}")"
+- oldtitle="$OS using $kernel_base (recovery mode)"
++ title="$(gettext_printf "%s, with Hurd %s (%s)" "${OS}" "${kernel_base}" "$(gettext "${GRUB_RECOVERY_TITLE}")")"
++ oldtitle="$OS using $kernel_base ($GRUB_RECOVERY_TITLE)"
+ else
+ title="$(gettext_printf "%s, with Hurd %s" "${OS}" "${kernel_base}")"
+ oldtitle="$OS using $kernel_base"
+diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in
+index 199b20e16..bbd63cf74 100644
+--- a/util/grub.d/10_kfreebsd.in
++++ b/util/grub.d/10_kfreebsd.in
+@@ -76,7 +76,7 @@ kfreebsd_entry ()
+ fi
+ if [ x$type != xsimple ] ; then
+ if [ x$type = xrecovery ] ; then
+- title="$(gettext_printf "%s, with kFreeBSD %s (recovery mode)" "${os}" "${version}")"
++ title="$(gettext_printf "%s, with kFreeBSD %s (%s)" "${os}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")"
+ else
+ title="$(gettext_printf "%s, with kFreeBSD %s" "${os}" "${version}")"
+ fi
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 64204c216..f88a2de10 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -126,7 +126,7 @@ linux_entry ()
+ 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 (%s)" "${os}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")" ;;
+ *)
+ title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
+ esac
+diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in
+index dc0cd1b17..336895012 100644
+--- a/util/grub.d/10_netbsd.in
++++ b/util/grub.d/10_netbsd.in
+@@ -102,7 +102,7 @@ netbsd_entry ()
+
+ if [ x$type != xsimple ] ; then
+ if [ x$type = xrecovery ] ; then
+- title="$(gettext_printf "%s, with kernel %s (via %s, recovery mode)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}")"
++ title="$(gettext_printf "%s, with kernel %s (via %s, %s)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}" "$(gettext "${GRUB_RECOVERY_TITLE}")")"
+ else
+ title="$(gettext_printf "%s, with kernel %s (via %s)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}")"
+ fi
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index 7620a14fa..64e26e4b4 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -122,7 +122,7 @@ linux_entry_xsm ()
+ fi
+ if [ x$type != xsimple ] ; then
+ if [ x$type = xrecovery ] ; then
+- title="$(gettext_printf "%s, with Xen %s and Linux %s (recovery mode)" "${os}" "${xen_version}" "${version}")"
++ title="$(gettext_printf "%s, with Xen %s and Linux %s (%s)" "${os}" "${xen_version}" "${version}" "$(gettext "${GRUB_RECOVERY_TITLE}")")"
+ else
+ title="$(gettext_printf "%s, with Xen %s and Linux %s" "${os}" "${xen_version}" "${version}")"
+ fi
diff --git a/debian/patches/mkconfig-signed-kernel.patch b/debian/patches/mkconfig-signed-kernel.patch
new file mode 100644
index 0000000..aa93fad
--- /dev/null
+++ b/debian/patches/mkconfig-signed-kernel.patch
@@ -0,0 +1,48 @@
+From 9eefe03f4b52e65cb4f372e0ff12a2b68cada425 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:21 +0000
+Subject: Generate configuration for signed UEFI kernels if available
+
+Forwarded: no
+Last-Update: 2013-12-25
+
+Patch-Name: mkconfig-signed-kernel.patch
+---
+ util/grub.d/10_linux.in | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 1603a75a7..1b8c6e146 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -161,8 +161,16 @@ linux_entry ()
+ message="$(gettext_printf "Loading Linux %s ..." ${version})"
+ sed "s/^/$submenu_indentation/" << EOF
+ echo '$(echo "$message" | grub_quote)'
++EOF
++ if test -d /sys/firmware/efi && test -e "${linux}.efi.signed"; then
++ sed "s/^/$submenu_indentation/" << EOF
++ linux ${rel_dirname}/${basename}.efi.signed root=${linux_root_device_thisversion} ro ${args}
++EOF
++ else
++ sed "s/^/$submenu_indentation/" << EOF
+ linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
+ EOF
++ fi
+ if test -n "${initrd}" ; then
+ # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+ message="$(gettext_printf "Loading initial ramdisk ...")"
+@@ -214,6 +222,13 @@ submenu_indentation=""
+ is_top_level=true
+ while [ "x$list" != "x" ] ; do
+ linux=`version_find_latest $list`
++ case $linux in
++ *.efi.signed)
++ # We handle these in linux_entry.
++ list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
++ continue
++ ;;
++ esac
+ gettext_printf "Found linux image: %s\n" "$linux" >&2
+ basename=`basename $linux`
+ dirname=`dirname $linux`
diff --git a/debian/patches/mkconfig-ubuntu-distributor.patch b/debian/patches/mkconfig-ubuntu-distributor.patch
new file mode 100644
index 0000000..8ec05e0
--- /dev/null
+++ b/debian/patches/mkconfig-ubuntu-distributor.patch
@@ -0,0 +1,37 @@
+From 84938bc37ee1cfabf84915ad4b6c8904b4770ef6 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <Mario_Limonciello@dell.com>
+Date: Mon, 13 Jan 2014 12:13:14 +0000
+Subject: Remove GNU/Linux from default distributor string for Ubuntu
+
+Ubuntu is called "Ubuntu", not "Ubuntu GNU/Linux".
+
+Author: Colin Watson <cjwatson@debian.org>
+Author: Harald Sitter <apachelogger@kubuntu.org>
+Forwarded: not-needed
+Last-Update: 2013-12-25
+
+Patch-Name: mkconfig-ubuntu-distributor.patch
+---
+ util/grub.d/10_linux.in | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index f215e3213..1603a75a7 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -32,7 +32,14 @@ CLASS="--class gnu-linux --class gnu --class os"
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+ OS=GNU/Linux
+ else
+- OS="${GRUB_DISTRIBUTOR} GNU/Linux"
++ case ${GRUB_DISTRIBUTOR} in
++ Ubuntu|Kubuntu)
++ OS="${GRUB_DISTRIBUTOR}"
++ ;;
++ *)
++ OS="${GRUB_DISTRIBUTOR} GNU/Linux"
++ ;;
++ esac
+ CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
+ fi
+
diff --git a/debian/patches/mkconfig-ubuntu-recovery.patch b/debian/patches/mkconfig-ubuntu-recovery.patch
new file mode 100644
index 0000000..1fa5bde
--- /dev/null
+++ b/debian/patches/mkconfig-ubuntu-recovery.patch
@@ -0,0 +1,107 @@
+From 13c9a7101d2611bbc02b464ef4e32b02cfc7860b Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:06 +0000
+Subject: "single" -> "recovery" when friendly-recovery is installed
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If configured with --enable-ubuntu-recovery, also set nomodeset for
+recovery mode, and disable 'set gfxpayload=keep' even if the system
+normally supports it. See
+https://launchpad.net/ubuntu/+spec/desktop-o-xorg-tools-and-processes.
+
+Author: Stéphane Graber <stgraber@ubuntu.com>
+Forwarded: no
+Last-Update: 2013-12-25
+
+Patch-Name: mkconfig-ubuntu-recovery.patch
+---
+ configure.ac | 11 +++++++++++
+ util/grub.d/10_linux.in | 16 ++++++++++++++--
+ util/grub.d/30_os-prober.in | 2 +-
+ 3 files changed, 26 insertions(+), 3 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 7517fc49d..74778a6f8 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1904,6 +1904,17 @@ fi
+ AC_SUBST([LIBZFS])
+ AC_SUBST([LIBNVPAIR])
+
++AC_ARG_ENABLE([ubuntu-recovery],
++ [AS_HELP_STRING([--enable-ubuntu-recovery],
++ [adjust boot options for the Ubuntu recovery mode (default=no)])],
++ [], [enable_ubuntu_recovery=no])
++if test x"$enable_ubuntu_recovery" = xyes ; then
++ UBUNTU_RECOVERY=1
++else
++ UBUNTU_RECOVERY=0
++fi
++AC_SUBST([UBUNTU_RECOVERY])
++
+ LIBS=""
+
+ AC_SUBST([FONT_SOURCE])
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 46696dd66..f215e3213 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -20,6 +20,7 @@ set -e
+ prefix="@prefix@"
+ exec_prefix="@exec_prefix@"
+ datarootdir="@datarootdir@"
++ubuntu_recovery="@UBUNTU_RECOVERY@"
+
+ . "$pkgdatadir/grub-mkconfig_lib"
+
+@@ -84,6 +85,15 @@ esac
+
+ title_correction_code=
+
++if [ -x /lib/recovery-mode/recovery-menu ]; then
++ GRUB_CMDLINE_LINUX_RECOVERY=recovery
++else
++ GRUB_CMDLINE_LINUX_RECOVERY=single
++fi
++if [ "$ubuntu_recovery" = 1 ]; then
++ GRUB_CMDLINE_LINUX_RECOVERY="$GRUB_CMDLINE_LINUX_RECOVERY nomodeset"
++fi
++
+ linux_entry ()
+ {
+ os="$1"
+@@ -123,7 +133,9 @@ linux_entry ()
+ if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
+ echo " load_video" | sed "s/^/$submenu_indentation/"
+ fi
+- echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
++ if [ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]; then
++ echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
++ fi
+ fi
+
+ echo " insmod gzio" | sed "s/^/$submenu_indentation/"
+@@ -288,7 +300,7 @@ while [ "x$list" != "x" ] ; do
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+ if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+ linux_entry "${OS}" "${version}" recovery \
+- "single ${GRUB_CMDLINE_LINUX}"
++ "${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}"
+ fi
+
+ list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '`
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 5984e92d2..37d5f05b5 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -223,7 +223,7 @@ EOF
+ fi
+
+ onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+- recovery_params="$(echo "${LPARAMS}" | grep single)" || true
++ recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true
+ counter=1
+ while echo "$used_osprober_linux_ids" | grep 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id' > /dev/null; do
+ counter=$((counter+1));
diff --git a/debian/patches/mkimage-fix-section-sizes.patch b/debian/patches/mkimage-fix-section-sizes.patch
new file mode 100644
index 0000000..107bd0e
--- /dev/null
+++ b/debian/patches/mkimage-fix-section-sizes.patch
@@ -0,0 +1,109 @@
+From e5be30174c7ed596ca2fd28d636a4fbc26a0199a Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 16 Apr 2021 21:37:23 +0200
+Subject: util/mkimage: Some fixes to PE binaries section size calculation
+
+Commit f60ba9e5945 (util/mkimage: Refactor section setup to use a helper)
+added a helper function to setup PE sections, but it caused regressions
+in some arches where the natural alignment lead to wrong section sizes.
+
+This patch fixes a few things that were caused the section sizes to be
+calculated wrongly. These fixes are:
+
+ * Only align the virtual memory addresses but not the raw data offsets.
+ * Use aligned sizes for virtual memory sizes but not for raw data sizes.
+ * Always align the sizes to set the virtual memory sizes.
+
+These seems to not cause problems for x64 and aa64 EFI platforms but was
+a problem for ia64. Because the size of the ".data" and "mods" sections
+were wrong and didn't have the correct content. Which lead to GRUB not
+being able to load any built-in module.
+
+Reported-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+
+Bug-Debian: https://bugs.debian.org/987103
+
+Patch-Name: mkimage-fix-section-sizes.patch
+---
+ util/mkimage.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+diff --git a/util/mkimage.c b/util/mkimage.c
+index a26cf76f7..b84311f1f 100644
+--- a/util/mkimage.c
++++ b/util/mkimage.c
+@@ -841,7 +841,7 @@ init_pe_section(const struct grub_install_image_target_desc *image_target,
+
+ section->raw_data_offset = grub_host_to_target32 (*rda);
+ section->raw_data_size = grub_host_to_target32 (rsz);
+- (*rda) = ALIGN_UP (*rda + rsz, GRUB_PE32_FILE_ALIGNMENT);
++ (*rda) = *rda + rsz;
+
+ section->characteristics = grub_host_to_target32 (characteristics);
+
+@@ -1309,7 +1309,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ char *pe_img, *pe_sbat, *header;
+ struct grub_pe32_section_table *section;
+ size_t n_sections = 4;
+- size_t scn_size;
++ size_t scn_size, raw_size;
+ grub_uint32_t vma, raw_data;
+ size_t pe_size, header_size;
+ struct grub_pe32_coff_header *c;
+@@ -1410,7 +1410,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ GRUB_PE32_SCN_MEM_EXECUTE |
+ GRUB_PE32_SCN_MEM_READ);
+
+- scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT);
++ raw_size = layout.kernel_size - layout.exec_size;
++ scn_size = ALIGN_UP (raw_size, GRUB_PE32_FILE_ALIGNMENT);
+ /* ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT) is done earlier. */
+ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + sbat_size +
+ ALIGN_UP (total_module_size,
+@@ -1418,15 +1419,16 @@ grub_install_generate_image (const char *dir, const char *prefix,
+
+ section = init_pe_section (image_target, section, ".data",
+ &vma, scn_size, image_target->section_align,
+- &raw_data, scn_size,
++ &raw_data, raw_size,
+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA |
+ GRUB_PE32_SCN_MEM_READ |
+ GRUB_PE32_SCN_MEM_WRITE);
+
+- scn_size = pe_size - layout.reloc_size - sbat_size - raw_data;
++ raw_size = pe_size - layout.reloc_size - sbat_size - raw_data;
++ scn_size = ALIGN_UP (raw_size, GRUB_PE32_FILE_ALIGNMENT);
+ section = init_pe_section (image_target, section, "mods",
+ &vma, scn_size, image_target->section_align,
+- &raw_data, scn_size,
++ &raw_data, raw_size,
+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA |
+ GRUB_PE32_SCN_MEM_READ |
+ GRUB_PE32_SCN_MEM_WRITE);
+@@ -1436,21 +1438,22 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ pe_sbat = pe_img + raw_data;
+ grub_util_load_image (sbat_path, pe_sbat);
+
++ scn_size = ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT);
+ section = init_pe_section (image_target, section, ".sbat",
+- &vma, sbat_size,
++ &vma, scn_size,
+ image_target->section_align,
+ &raw_data, sbat_size,
+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA |
+ GRUB_PE32_SCN_MEM_READ);
+ }
+
+- scn_size = layout.reloc_size;
++ scn_size = ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT);
+ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma);
+ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size);
+ memcpy (pe_img + raw_data, layout.reloc_section, scn_size);
+ init_pe_section (image_target, section, ".reloc",
+ &vma, scn_size, image_target->section_align,
+- &raw_data, scn_size,
++ &raw_data, layout.reloc_size,
+ GRUB_PE32_SCN_CNT_INITIALIZED_DATA |
+ GRUB_PE32_SCN_MEM_DISCARDABLE |
+ GRUB_PE32_SCN_MEM_READ);
diff --git a/debian/patches/mkrescue-efi-modules.patch b/debian/patches/mkrescue-efi-modules.patch
new file mode 100644
index 0000000..8b6df4f
--- /dev/null
+++ b/debian/patches/mkrescue-efi-modules.patch
@@ -0,0 +1,35 @@
+From 41f0edb8bebe40b7d9302418100034dead84dfe9 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <Mario_Limonciello@dell.com>
+Date: Mon, 13 Jan 2014 12:12:59 +0000
+Subject: Build vfat into EFI boot images
+
+Author: Colin Watson <cjwatson@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/677758
+Forwarded: http://lists.gnu.org/archive/html/grub-devel/2011-01/msg00028.html
+Last-Update: 2016-09-18
+
+Patch-Name: mkrescue-efi-modules.patch
+---
+ util/grub-mkrescue.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/util/grub-mkrescue.c b/util/grub-mkrescue.c
+index fb4dcc6d5..fcb35726c 100644
+--- a/util/grub-mkrescue.c
++++ b/util/grub-mkrescue.c
+@@ -753,6 +753,7 @@ main (int argc, char *argv[])
+
+ grub_install_push_module ("part_gpt");
+ grub_install_push_module ("part_msdos");
++ grub_install_push_module ("fat");
+
+ imgname = grub_util_path_concat (2, efidir_efi_boot, "bootia64.efi");
+ make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_IA64_EFI, "ia64-efi", imgname);
+@@ -830,6 +831,7 @@ main (int argc, char *argv[])
+ free (efidir);
+ grub_install_pop_module ();
+ grub_install_pop_module ();
++ grub_install_pop_module ();
+ }
+
+ grub_install_push_module ("part_apple");
diff --git a/debian/patches/net-read-bracketed-ipv6-addr.patch b/debian/patches/net-read-bracketed-ipv6-addr.patch
new file mode 100644
index 0000000..93ee7d7
--- /dev/null
+++ b/debian/patches/net-read-bracketed-ipv6-addr.patch
@@ -0,0 +1,255 @@
+From c7e2338904e5e1e2546f1097cad1a020615463cf Mon Sep 17 00:00:00 2001
+From: Aaron Miller <aaronmiller@fb.com>
+Date: Thu, 27 Oct 2016 17:39:49 -0400
+Subject: 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
+
+Last-Update: 2021-09-24
+
+Patch-Name: net-read-bracketed-ipv6-addr.patch
+---
+ grub-core/net/http.c | 21 ++++++++--
+ grub-core/net/net.c | 93 +++++++++++++++++++++++++++++++++++++++++---
+ grub-core/net/tftp.c | 6 ++-
+ include/grub/net.h | 1 +
+ 4 files changed, 110 insertions(+), 11 deletions(-)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index b616cf40b..3fe155f1b 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -312,12 +312,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 +358,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 +367,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 +401,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 4d3eb5c1a..15a2f29a9 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -442,6 +442,12 @@ 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;
+@@ -480,6 +486,9 @@ 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;
+@@ -1265,8 +1274,10 @@ grub_net_open_real (const char *name)
+ {
+ grub_net_app_level_t proto;
+ const char *protname, *server;
++ char *host;
+ grub_size_t protnamelen;
+ int try;
++ int port = 0;
+
+ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
+ {
+@@ -1304,6 +1315,72 @@ grub_net_open_real (const char *name)
+ return NULL;
+ }
+
++ char* port_start;
++ /* ipv6 or port specified? */
++ if ((port_start = grub_strchr (server, ':')))
++ {
++ char* ipv6_begin;
++ if((ipv6_begin = grub_strchr (server, '[')))
++ {
++ char* ipv6_end = grub_strchr (server, ']');
++ if(!ipv6_end)
++ {
++ grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++ N_("mismatched [ in address"));
++ return NULL;
++ }
++ /* port number after bracketed ipv6 addr */
++ if(ipv6_end[1] == ':')
++ {
++ port = grub_strtoul (ipv6_end + 2, NULL, 10);
++ if(port > 65535)
++ {
++ grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++ N_("bad port number"));
++ return NULL;
++ }
++ }
++ host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
++ }
++ else
++ {
++ if (grub_strchr (port_start + 1, ':'))
++ {
++ int iplen = grub_strlen (server);
++ /* bracket bare ipv6 addrs */
++ host = grub_malloc (iplen + 3);
++ if(!host)
++ {
++ return NULL;
++ }
++ host[0] = '[';
++ grub_memcpy (host + 1, server, iplen);
++ host[iplen + 1] = ']';
++ host[iplen + 2] = '\0';
++ }
++ else
++ {
++ /* hostname:port or ipv4:port */
++ port = grub_strtol (port_start + 1, NULL, 10);
++ if(port > 65535)
++ {
++ grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++ N_("bad port number"));
++ return NULL;
++ }
++ host = grub_strndup (server, port_start - server);
++ }
++ }
++ }
++ else
++ {
++ host = grub_strdup (server);
++ }
++ if (!host)
++ {
++ return NULL;
++ }
++
+ for (try = 0; try < 2; try++)
+ {
+ FOR_NET_APP_LEVEL (proto)
+@@ -1313,15 +1390,19 @@ 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 (host);
++ if (host)
+ {
+- grub_free (ret);
+- return NULL;
++ ret->server = grub_strdup (host);
++ if (!ret->server)
++ {
++ grub_free (ret);
++ return NULL;
++ }
+ }
+ ret->fs = &grub_net_fs;
++ ret->protocol = proto;
++ ret->port = port;
+ return ret;
+ }
+ }
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index 7f44b30f5..f3e787938 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)
+@@ -361,12 +362,15 @@ tftp_open (struct grub_file *file, const char *filename)
+ err = grub_net_resolve_address (file->device->net->server, &addr);
+ if (err)
+ {
++ grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
++ (unsigned long long)data->file_size,
++ (unsigned long long)data->block_size);
+ grub_free (data);
+ return err;
+ }
+
+ data->sock = grub_net_udp_open (addr,
+- TFTP_SERVER_PORT, tftp_receive,
++ port ? port : TFTP_SERVER_PORT, tftp_receive,
+ file);
+ if (!data->sock)
+ {
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 7ae4b6bd8..69bfe0947 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -270,6 +270,7 @@ typedef struct grub_net
+ {
+ char *server;
+ char *name;
++ int port;
+ grub_net_app_level_t protocol;
+ grub_net_packets_t packs;
+ grub_off_t offset;
diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch
new file mode 100644
index 0000000..24601f7
--- /dev/null
+++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch
@@ -0,0 +1,57 @@
+From: Maxim Suhanov <dfirblog@gmail.com>
+Date: Mon, 28 Aug 2023 16:38:19 +0300
+Subject: fs/ntfs: Fix an OOB read when parsing a volume label
+
+This fix introduces checks to ensure that an NTFS volume label is always
+read from the corresponding file record segment.
+
+The current NTFS code allows the volume label string to be read from an
+arbitrary, attacker-chosen memory location. However, the bytes read are
+always treated as UTF-16LE. So, the final string displayed is mostly
+unreadable and it can't be easily converted back to raw bytes.
+
+The lack of this check is a minor issue, likely not causing a significant
+data leak.
+
+Reported-by: Maxim Suhanov <dfirblog@gmail.com>
+Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/fs/ntfs.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
+index bb70c89..ff5e374 100644
+--- a/grub-core/fs/ntfs.c
++++ b/grub-core/fs/ntfs.c
+@@ -1213,13 +1213,29 @@ grub_ntfs_label (grub_device_t device, char **label)
+
+ init_attr (&mft->attr, mft);
+ pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME);
++
++ if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR))
++ {
++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label");
++ goto fail;
++ }
++
++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa < 0x16)
++ {
++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label");
++ goto fail;
++ }
++
+ if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10)))
+ {
+ int len;
+
+ len = u32at (pa, 0x10) / 2;
+ pa += u16at (pa, 0x14);
+- *label = get_utf8 (pa, len);
++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len)
++ *label = get_utf8 (pa, len);
++ else
++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label");
+ }
+
+ fail:
diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch
new file mode 100644
index 0000000..29b9dd5
--- /dev/null
+++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch
@@ -0,0 +1,46 @@
+From: Maxim Suhanov <dfirblog@gmail.com>
+Date: Mon, 28 Aug 2023 16:33:44 +0300
+Subject: fs/ntfs: Fix an OOB read when parsing bitmaps for index attributes
+
+This fix introduces checks to ensure that bitmaps for directory indices
+are never read beyond their actual sizes.
+
+The lack of this check is a minor issue, likely not exploitable in any way.
+
+Reported-by: Maxim Suhanov <dfirblog@gmail.com>
+Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/fs/ntfs.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
+index 2d78b96..bb70c89 100644
+--- a/grub-core/fs/ntfs.c
++++ b/grub-core/fs/ntfs.c
+@@ -843,6 +843,25 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
+
+ if (is_resident)
+ {
++ if (bitmap_len > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR))
++ {
++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap too large");
++ goto done;
++ }
++
++ if (cur_pos >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR))
++ {
++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range");
++ goto done;
++ }
++
++ if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) >
++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos)
++ {
++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range");
++ goto done;
++ }
++
+ grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14),
+ bitmap_len);
+ }
diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch
new file mode 100644
index 0000000..bbc90c3
--- /dev/null
+++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch
@@ -0,0 +1,69 @@
+From: Maxim Suhanov <dfirblog@gmail.com>
+Date: Mon, 28 Aug 2023 16:33:17 +0300
+Subject: fs/ntfs: Fix an OOB read when parsing directory entries from
+ resident and non-resident index attributes
+
+This fix introduces checks to ensure that index entries are never read
+beyond the corresponding directory index.
+
+The lack of this check is a minor issue, likely not exploitable in any way.
+
+Reported-by: Maxim Suhanov <dfirblog@gmail.com>
+Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/fs/ntfs.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
+index a68e173..2d78b96 100644
+--- a/grub-core/fs/ntfs.c
++++ b/grub-core/fs/ntfs.c
+@@ -599,7 +599,7 @@ get_utf8 (grub_uint8_t *in, grub_size_t len)
+ }
+
+ static int
+-list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
++list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, grub_uint8_t *end_pos,
+ grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+ {
+ grub_uint8_t *np;
+@@ -610,6 +610,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
+ grub_uint8_t namespace;
+ char *ustr;
+
++ if ((pos >= end_pos) || (end_pos - pos < 0x52))
++ break;
++
+ if (pos[0xC] & 2) /* end signature */
+ break;
+
+@@ -617,6 +620,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos,
+ ns = *(np++);
+ namespace = *(np++);
+
++ if (2 * ns > end_pos - pos - 0x52)
++ break;
++
+ /*
+ * Ignore files in DOS namespace, as they will reappear as Win32
+ * names.
+@@ -806,7 +812,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
+ }
+
+ cur_pos += 0x10; /* Skip index root */
+- ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data);
++ ret = list_file (mft, cur_pos + u16at (cur_pos, 0),
++ at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR),
++ hook, hook_data);
+ if (ret)
+ goto done;
+
+@@ -893,6 +901,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
+ (const grub_uint8_t *) "INDX")))
+ goto done;
+ ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)],
++ indx + (mft->data->idx_size << GRUB_NTFS_BLK_SHR),
+ hook, hook_data);
+ if (ret)
+ goto done;
diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch
new file mode 100644
index 0000000..d762c06
--- /dev/null
+++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch
@@ -0,0 +1,54 @@
+From: Maxim Suhanov <dfirblog@gmail.com>
+Date: Mon, 28 Aug 2023 16:32:33 +0300
+Subject: fs/ntfs: Fix an OOB read when reading data from the resident $DATA
+ attribute
+
+When reading a file containing resident data, i.e., the file data is stored in
+the $DATA attribute within the NTFS file record, not in external clusters,
+there are no checks that this resident data actually fits the corresponding
+file record segment.
+
+When parsing a specially-crafted file system image, the current NTFS code will
+read the file data from an arbitrary, attacker-chosen memory offset and of
+arbitrary, attacker-chosen length.
+
+This allows an attacker to display arbitrary chunks of memory, which could
+contain sensitive information like password hashes or even plain-text,
+obfuscated passwords from BS EFI variables.
+
+This fix implements a check to ensure that resident data is read from the
+corresponding file record segment only.
+
+Fixes: CVE-2023-4693
+
+Reported-by: Maxim Suhanov <dfirblog@gmail.com>
+Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/fs/ntfs.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
+index c3c4db1..a68e173 100644
+--- a/grub-core/fs/ntfs.c
++++ b/grub-core/fs/ntfs.c
+@@ -401,7 +401,18 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest,
+ {
+ if (ofs + len > u32at (pa, 0x10))
+ return grub_error (GRUB_ERR_BAD_FS, "read out of range");
+- grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len);
++
++ if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR))
++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large");
++
++ if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR))
++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range");
++
++ if (u16at (pa, 0x14) + u32at (pa, 0x10) >
++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa)
++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range");
++
++ grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len);
+ return 0;
+ }
+
diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch
new file mode 100644
index 0000000..06279b8
--- /dev/null
+++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch
@@ -0,0 +1,89 @@
+From: Maxim Suhanov <dfirblog@gmail.com>
+Date: Mon, 28 Aug 2023 16:31:57 +0300
+Subject: fs/ntfs: Fix an OOB write when parsing the $ATTRIBUTE_LIST attribute
+ for the $MFT file
+
+When parsing an extremely fragmented $MFT file, i.e., the file described
+using the $ATTRIBUTE_LIST attribute, current NTFS code will reuse a buffer
+containing bytes read from the underlying drive to store sector numbers,
+which are consumed later to read data from these sectors into another buffer.
+
+These sectors numbers, two 32-bit integers, are always stored at predefined
+offsets, 0x10 and 0x14, relative to first byte of the selected entry within
+the $ATTRIBUTE_LIST attribute. Usually, this won't cause any problem.
+
+However, when parsing a specially-crafted file system image, this may cause
+the NTFS code to write these integers beyond the buffer boundary, likely
+causing the GRUB memory allocator to misbehave or fail. These integers contain
+values which are controlled by on-disk structures of the NTFS file system.
+
+Such modification and resulting misbehavior may touch a memory range not
+assigned to the GRUB and owned by firmware or another EFI application/driver.
+
+This fix introduces checks to ensure that these sector numbers are never
+written beyond the boundary.
+
+Fixes: CVE-2023-4692
+
+Reported-by: Maxim Suhanov <dfirblog@gmail.com>
+Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/fs/ntfs.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
+index bbdbe24..c3c4db1 100644
+--- a/grub-core/fs/ntfs.c
++++ b/grub-core/fs/ntfs.c
+@@ -184,7 +184,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+ }
+ if (at->attr_end)
+ {
+- grub_uint8_t *pa;
++ grub_uint8_t *pa, *pa_end;
+
+ at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ if (at->emft_buf == NULL)
+@@ -209,11 +209,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+ }
+ at->attr_nxt = at->edat_buf;
+ at->attr_end = at->edat_buf + u32at (pa, 0x30);
++ pa_end = at->edat_buf + n;
+ }
+ else
+ {
+ at->attr_nxt = at->attr_end + u16at (pa, 0x14);
+ at->attr_end = at->attr_end + u32at (pa, 4);
++ pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ }
+ at->flags |= GRUB_NTFS_AF_ALST;
+ while (at->attr_nxt < at->attr_end)
+@@ -230,6 +232,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+ at->flags |= GRUB_NTFS_AF_GPOS;
+ at->attr_cur = at->attr_nxt;
+ pa = at->attr_cur;
++
++ if ((pa >= pa_end) || (pa_end - pa < 0x18))
++ {
++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list");
++ return NULL;
++ }
++
+ grub_set_unaligned32 ((char *) pa + 0x10,
+ grub_cpu_to_le32 (at->mft->data->mft_start));
+ grub_set_unaligned32 ((char *) pa + 0x14,
+@@ -240,6 +249,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+ {
+ if (*pa != attr)
+ break;
++
++ if ((pa >= pa_end) || (pa_end - pa < 0x18))
++ {
++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list");
++ return NULL;
++ }
++
+ if (read_attr
+ (at, pa + 0x10,
+ u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR),
diff --git a/debian/patches/ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch b/debian/patches/ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch
new file mode 100644
index 0000000..bc3bfd7
--- /dev/null
+++ b/debian/patches/ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch
@@ -0,0 +1,155 @@
+From: Maxim Suhanov <dfirblog@gmail.com>
+Date: Mon, 28 Aug 2023 16:40:07 +0300
+Subject: fs/ntfs: Make code more readable
+
+Move some calls used to access NTFS attribute header fields into
+functions with human-readable names.
+
+Suggested-by: Daniel Kiper <daniel.kiper@oracle.com>
+Signed-off-by: Maxim Suhanov <dfirblog@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/fs/ntfs.c | 48 +++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 33 insertions(+), 15 deletions(-)
+
+diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c
+index ff5e374..de435aa 100644
+--- a/grub-core/fs/ntfs.c
++++ b/grub-core/fs/ntfs.c
+@@ -52,6 +52,24 @@ u64at (void *ptr, grub_size_t ofs)
+ return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs));
+ }
+
++static grub_uint16_t
++first_attr_off (void *mft_buf_ptr)
++{
++ return u16at (mft_buf_ptr, 0x14);
++}
++
++static grub_uint16_t
++res_attr_data_off (void *res_attr_ptr)
++{
++ return u16at (res_attr_ptr, 0x14);
++}
++
++static grub_uint32_t
++res_attr_data_len (void *res_attr_ptr)
++{
++ return u32at (res_attr_ptr, 0x10);
++}
++
+ grub_ntfscomp_func_t grub_ntfscomp_func;
+
+ static grub_err_t
+@@ -106,7 +124,7 @@ init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft)
+ {
+ at->mft = mft;
+ at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0;
+- at->attr_nxt = mft->buf + u16at (mft->buf, 0x14);
++ at->attr_nxt = mft->buf + first_attr_off (mft->buf);
+ at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL;
+ }
+
+@@ -154,7 +172,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+ return NULL;
+ }
+
+- new_pos = &at->emft_buf[u16at (at->emft_buf, 0x14)];
++ new_pos = &at->emft_buf[first_attr_off (at->emft_buf)];
+ while (*new_pos != 0xFF)
+ {
+ if ((*new_pos == *at->attr_cur)
+@@ -213,7 +231,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr)
+ }
+ else
+ {
+- at->attr_nxt = at->attr_end + u16at (pa, 0x14);
++ at->attr_nxt = at->attr_end + res_attr_data_off (pa);
+ at->attr_end = at->attr_end + u32at (pa, 4);
+ pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR);
+ }
+@@ -399,20 +417,20 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest,
+
+ if (pa[8] == 0)
+ {
+- if (ofs + len > u32at (pa, 0x10))
++ if (ofs + len > res_attr_data_len (pa))
+ return grub_error (GRUB_ERR_BAD_FS, "read out of range");
+
+- if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR))
++ if (res_attr_data_len (pa) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR))
+ return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large");
+
+ if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR))
+ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range");
+
+- if (u16at (pa, 0x14) + u32at (pa, 0x10) >
++ if (res_attr_data_off (pa) + res_attr_data_len (pa) >
+ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa)
+ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range");
+
+- grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len);
++ grub_memcpy (dest, pa + res_attr_data_off (pa) + ofs, len);
+ return 0;
+ }
+
+@@ -556,7 +574,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno)
+ (unsigned long long) mftno);
+
+ if (!pa[8])
+- mft->size = u32at (pa, 0x10);
++ mft->size = res_attr_data_len (pa);
+ else
+ mft->size = u64at (pa, 0x30);
+
+@@ -805,7 +823,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
+ (u32at (cur_pos, 0x18) != 0x490024) ||
+ (u32at (cur_pos, 0x1C) != 0x300033))
+ continue;
+- cur_pos += u16at (cur_pos, 0x14);
++ cur_pos += res_attr_data_off (cur_pos);
+ if (*cur_pos != 0x30) /* Not filename index */
+ continue;
+ break;
+@@ -834,7 +852,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
+ {
+ int is_resident = (cur_pos[8] == 0);
+
+- bitmap_len = ((is_resident) ? u32at (cur_pos, 0x10) :
++ bitmap_len = ((is_resident) ? res_attr_data_len (cur_pos) :
+ u32at (cur_pos, 0x28));
+
+ bmp = grub_malloc (bitmap_len);
+@@ -855,14 +873,14 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir,
+ goto done;
+ }
+
+- if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) >
++ if (res_attr_data_off (cur_pos) + res_attr_data_len (cur_pos) >
+ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range");
+ goto done;
+ }
+
+- grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14),
++ grub_memcpy (bmp, cur_pos + res_attr_data_off (cur_pos),
+ bitmap_len);
+ }
+ else
+@@ -1226,12 +1244,12 @@ grub_ntfs_label (grub_device_t device, char **label)
+ goto fail;
+ }
+
+- if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10)))
++ if ((pa) && (pa[8] == 0) && (res_attr_data_len (pa)))
+ {
+ int len;
+
+- len = u32at (pa, 0x10) / 2;
+- pa += u16at (pa, 0x14);
++ len = res_attr_data_len (pa) / 2;
++ pa += res_attr_data_off (pa);
+ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len)
+ *label = get_utf8 (pa, len);
+ else
diff --git a/debian/patches/olpc-prefix-hack.patch b/debian/patches/olpc-prefix-hack.patch
new file mode 100644
index 0000000..6ba9b1e
--- /dev/null
+++ b/debian/patches/olpc-prefix-hack.patch
@@ -0,0 +1,51 @@
+From 39e079ec50c46fa2fc2f43a1a2e01172ef7dd7c6 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:12:50 +0000
+Subject: Hack prefix for OLPC
+
+This sucks, but it's better than what OFW was giving us.
+
+Patch-Name: olpc-prefix-hack.patch
+---
+ grub-core/kern/ieee1275/init.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index d483e35ee..8b089b48d 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -76,6 +76,7 @@ grub_exit (void)
+ grub_ieee1275_exit ();
+ }
+
++#ifndef __i386__
+ /* Translate an OF filesystem path (separated by backslashes), into a GRUB
+ path (separated by forward slashes). */
+ static void
+@@ -90,9 +91,18 @@ grub_translate_ieee1275_path (char *filepath)
+ backslash = grub_strchr (filepath, '\\');
+ }
+ }
++#endif
+
+ void (*grub_ieee1275_net_config) (const char *dev, char **device, char **path,
+ char *bootpath);
++#ifdef __i386__
++void
++grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
++ char **path __attribute__ ((unused)))
++{
++ grub_env_set ("prefix", "(sd,1)/");
++}
++#else
+ void
+ grub_machine_get_bootlocation (char **device, char **path)
+ {
+@@ -146,6 +156,7 @@ grub_machine_get_bootlocation (char **device, char **path)
+ }
+ grub_free (bootpath);
+ }
++#endif
+
+ /* Claim some available memory in the first /memory node. */
+ #ifdef __sparc__
diff --git a/debian/patches/os-prober-Allow-initrd-to-contain-spaces.patch b/debian/patches/os-prober-Allow-initrd-to-contain-spaces.patch
new file mode 100644
index 0000000..eb6c452
--- /dev/null
+++ b/debian/patches/os-prober-Allow-initrd-to-contain-spaces.patch
@@ -0,0 +1,50 @@
+From 1f982e2a7c35e14d5a92c76db998afafd1bd9e87 Mon Sep 17 00:00:00 2001
+From: General Chaos <debianbugs@toeai.com>
+Date: Tue, 12 Apr 2016 22:28:52 +0000
+Subject: [PATCH] os-prober: Allow initrd to contain spaces
+
+linux-boot-prober produces structured output with newline-terminated rows
+representing kernels, each with colon-delimited columns. We translate
+this into a sequence of space-separated words representing kernels,
+each containing colon-delimited fields where spaces are represented by
+carets.
+
+When we parse each of those words into colon-delimited fields, if the
+field could conceivably contain spaces then we need to translate
+carets back into spaces. We did this for label and parameters, but not
+for the initrd.
+
+In particular, when CPU microcode is installed on Arch Linux or its
+derivatives, they write CPU microcode into one initrd archive and the
+rest of early user-space into another, instead of concatenating the
+archives into a single file like Debian derivatives do. To boot Arch
+successfully from the grub menu, we need to add all of their initrds
+to the grub menu entry (detecting this situation requires an os-prober
+patch, for which see <https://bugs.debian.org/820838>).
+
+[Commit message added by Simon McVittie <smcv@collabora.com>]
+
+Bug: https://savannah.gnu.org/bugs/index.php?47681
+Bug-Debian: https://bugs.debian.org/838177
+Forwarded: https://savannah.gnu.org/bugs/index.php?47681
+Closes: #838177
+---
+ util/grub.d/30_os-prober.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index da5f28876..d0609d9a4 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -243,7 +243,7 @@ EOF
+ LBOOT="`echo ${LINUX} | cut -d ':' -f 2`"
+ LLABEL="`echo ${LINUX} | cut -d ':' -f 3 | tr '^' ' '`"
+ LKERNEL="`echo ${LINUX} | cut -d ':' -f 4`"
+- LINITRD="`echo ${LINUX} | cut -d ':' -f 5`"
++ LINITRD="`echo ${LINUX} | cut -d ':' -f 5 | tr '^' ' '`"
+ LPARAMS="`echo ${LINUX} | cut -d ':' -f 6- | tr '^' ' '`"
+
+ if [ -z "${LLABEL}" ] ; then
+--
+2.32.0
+
diff --git a/debian/patches/osdep-devmapper-getroot-have-devmapper-recognize-luks2.patch b/debian/patches/osdep-devmapper-getroot-have-devmapper-recognize-luks2.patch
new file mode 100644
index 0000000..667a5a1
--- /dev/null
+++ b/debian/patches/osdep-devmapper-getroot-have-devmapper-recognize-luks2.patch
@@ -0,0 +1,54 @@
+From: Josselin Poiret <dev@jpoiret.xyz>
+Date: Thu, 12 Jan 2023 17:05:08 -0600
+Subject: osdep/devmapper/getroot: Have devmapper recognize LUKS2
+Origin: https://git.savannah.gnu.org/cgit/grub.git/commit/?id=9022a48dd9984fc3e90a5b42c3b5483d6061ccfb
+Bug-Debian: https://bugs.debian.org/1028301
+
+Changes UUID comparisons so that LUKS1 and LUKS2 are both recognized
+as being LUKS cryptodisks.
+
+Signed-off-by: Josselin Poiret <dev@jpoiret.xyz>
+Tested-by: Glenn Washburn <development@efficientek.com>
+Reviewed-by: Patrick Steinhardt <ps@pks.im>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/osdep/devmapper/getroot.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/grub-core/osdep/devmapper/getroot.c
++++ b/grub-core/osdep/devmapper/getroot.c
+@@ -143,7 +143,8 @@ grub_util_get_dm_abstraction (const char
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_LVM;
+ }
+- if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0)
++ if (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
++ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
+ {
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_LUKS;
+@@ -184,7 +185,9 @@ grub_util_pull_devmapper (const char *os
+ grub_util_pull_device (subdev);
+ }
+ }
+- if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
++ if (uuid
++ && (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
++ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
+ && lastsubdev)
+ {
+ char *grdev = grub_util_get_grub_dev (lastsubdev);
+@@ -258,11 +261,11 @@ grub_util_get_devmapper_grub_dev (const
+ {
+ char *dash;
+
+- dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-');
++ dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS*-") - 1, '-');
+ if (dash)
+ *dash = 0;
+ grub_dev = grub_xasprintf ("cryptouuid/%s",
+- uuid + sizeof ("CRYPT-LUKS1-") - 1);
++ uuid + sizeof ("CRYPT-LUKS*-") - 1);
+ grub_free (uuid);
+ return grub_dev;
+ }
diff --git a/debian/patches/osdep-devmapper-getroot-set-up-cheated-luks2-cryptodisk-mount-from-dm-parameters.patch b/debian/patches/osdep-devmapper-getroot-set-up-cheated-luks2-cryptodisk-mount-from-dm-parameters.patch
new file mode 100644
index 0000000..a23d0f7
--- /dev/null
+++ b/debian/patches/osdep-devmapper-getroot-set-up-cheated-luks2-cryptodisk-mount-from-dm-parameters.patch
@@ -0,0 +1,154 @@
+From: Josselin Poiret <dev@jpoiret.xyz>
+Date: Thu, 12 Jan 2023 17:05:09 -0600
+Subject: osdep/devmapper/getroot: Set up cheated LUKS2 cryptodisk mount from
+ DM parameters
+Origin: https://git.savannah.gnu.org/cgit/grub.git/commit/?id=aa5172a55cfabdd0bed3161ad44fc228b9d019f7
+Bug-Debian: https://bugs.debian.org/1028301
+
+This lets a LUKS2 cryptodisk have its cipher and hash filled out,
+otherwise they wouldn't be initialized if cheat mounted.
+
+Signed-off-by: Josselin Poiret <dev@jpoiret.xyz>
+Tested-by: Glenn Washburn <development@efficientek.com>
+Reviewed-by: Patrick Steinhardt <ps@pks.im>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/osdep/devmapper/getroot.c | 107 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 106 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c
+index 2bf4264..cc3f7da 100644
+--- a/grub-core/osdep/devmapper/getroot.c
++++ b/grub-core/osdep/devmapper/getroot.c
+@@ -51,6 +51,8 @@
+ #include <grub/emu/misc.h>
+ #include <grub/emu/hostdisk.h>
+
++#include <grub/cryptodisk.h>
++
+ static int
+ grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
+ struct dm_tree_node **node)
+@@ -186,7 +188,6 @@ grub_util_pull_devmapper (const char *os_dev)
+ && lastsubdev)
+ {
+ char *grdev = grub_util_get_grub_dev (lastsubdev);
+- dm_tree_free (tree);
+ if (grdev)
+ {
+ grub_err_t err;
+@@ -194,7 +195,111 @@ grub_util_pull_devmapper (const char *os_dev)
+ if (err)
+ grub_util_error (_("can't mount encrypted volume `%s': %s"),
+ lastsubdev, grub_errmsg);
++ if (strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
++ {
++ /*
++ * Set LUKS2 cipher from dm parameters, since it is not
++ * possible to determine the correct one without
++ * unlocking, as there might be multiple segments.
++ */
++ grub_disk_t source;
++ grub_cryptodisk_t cryptodisk;
++ grub_uint64_t start, length;
++ char *target_type;
++ char *params;
++ const char *name;
++ char *cipher, *cipher_mode;
++ struct dm_task *dmt;
++ char *seek_head, *c;
++ unsigned int remaining;
++
++ source = grub_disk_open (grdev);
++ if (! source)
++ grub_util_error (_("cannot open grub disk `%s'"), grdev);
++ cryptodisk = grub_cryptodisk_get_by_source_disk (source);
++ if (! cryptodisk)
++ grub_util_error (_("cannot get cryptodisk from source disk `%s'"), grdev);
++ grub_disk_close (source);
++
++ /*
++ * The following function always returns a non-NULL pointer,
++ * but the string may be empty if the relevant info is not present.
++ */
++ name = dm_tree_node_get_name (node);
++ if (*name == '\0')
++ grub_util_error (_("cannot get dm node name for grub dev `%s'"), grdev);
++
++ grub_util_info ("populating parameters of cryptomount `%s' from DM device `%s'",
++ uuid, name);
++
++ dmt = dm_task_create (DM_DEVICE_TABLE);
++ if (dmt == NULL)
++ grub_util_error (_("can't create dm task DM_DEVICE_TABLE"));
++ if (dm_task_set_name (dmt, name) == 0)
++ grub_util_error (_("can't set dm task name to `%s'"), name);
++ if (dm_task_run (dmt) == 0)
++ grub_util_error (_("can't run dm task for `%s'"), name);
++ /*
++ * dm_get_next_target() doesn't have any error modes, everything has
++ * been handled by dm_task_run().
++ */
++ dm_get_next_target (dmt, NULL, &start, &length,
++ &target_type, &params);
++ if (strncmp (target_type, "crypt", sizeof ("crypt")) != 0)
++ grub_util_error (_("dm target of type `%s' is not `crypt'"), target_type);
++
++ /*
++ * The dm target parameters for dm-crypt are
++ * <cipher> <key> <iv_offset> <device path> <offset> [<#opt_params> <opt_param1> ...]
++ */
++ c = params;
++ remaining = grub_strlen (c);
++
++ /* First, get the cipher name from the cipher. */
++ seek_head = grub_memchr (c, '-', remaining);
++ if (seek_head == NULL)
++ grub_util_error (_("can't get cipher from dm-crypt parameters `%s'"),
++ params);
++ cipher = grub_strndup (c, seek_head - c);
++ if (cipher == NULL)
++ grub_util_error (_("could not strndup cipher of length `%lu'"), (unsigned long)(seek_head - c));
++ remaining -= seek_head - c + 1;
++ c = seek_head + 1;
++
++ /* Now, the cipher mode. */
++ seek_head = grub_memchr (c, ' ', remaining);
++ if (seek_head == NULL)
++ grub_util_error (_("can't get cipher mode from dm-crypt parameters `%s'"),
++ params);
++ cipher_mode = grub_strndup (c, seek_head - c);
++ if (cipher_mode == NULL)
++ grub_util_error (_("could not strndup cipher_mode of length `%lu'"), (unsigned long)(seek_head - c));
++
++ remaining -= seek_head - c + 1;
++ c = seek_head + 1;
++
++ err = grub_cryptodisk_setcipher (cryptodisk, cipher, cipher_mode);
++ if (err)
++ grub_util_error (_("can't set cipher of cryptodisk `%s' to `%s' with mode `%s'"),
++ uuid, cipher, cipher_mode);
++
++ grub_free (cipher);
++ grub_free (cipher_mode);
++
++ /*
++ * This is the only hash usable by PBKDF2, and we don't
++ * have Argon2 support yet, so set it by default,
++ * otherwise grub-probe would miss the required
++ * abstraction.
++ */
++ cryptodisk->hash = grub_crypto_lookup_md_by_name ("sha256");
++ if (cryptodisk->hash == NULL)
++ grub_util_error (_("can't lookup hash sha256 by name"));
++
++ dm_task_destroy (dmt);
++ }
+ }
++ dm_tree_free (tree);
+ grub_free (grdev);
+ }
+ else
+--
+cgit v1.1
+
diff --git a/debian/patches/pc-verifiers-module.patch b/debian/patches/pc-verifiers-module.patch
new file mode 100644
index 0000000..a3c1303
--- /dev/null
+++ b/debian/patches/pc-verifiers-module.patch
@@ -0,0 +1,167 @@
+From 4a6abe501f39c4c8afe4ed7405ff99aff8559a13 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 18 Mar 2021 19:30:26 +0800
+Subject: i386-pc: build verifiers API as module
+
+Given no core functions on i386-pc would require verifiers to work and
+the only consumer of the verifier API is the pgp module, it looks good
+to me that we can move the verifiers out of the kernel image and let
+moddep.lst to auto-load it when pgp is loaded on i386-pc platform.
+
+This helps to reduce the size of core image and thus can relax the
+tension of exploding on some i386-pc system with very short MBR gap
+size. See also a very comprehensive summary from Colin [1] about the
+details.
+
+[1] https://lists.gnu.org/archive/html/grub-devel/2021-03/msg00240.html
+
+V2:
+Drop COND_NOT_i386_pc and use !COND_i386_pc.
+Add comment in kern/verifiers.c to help understanding what's going on
+without digging into the commit history.
+
+Reported-by: Colin Watson <cjwatson@debian.org>
+Reviewed-by: Colin Watson <cjwatson@debian.org>
+Signed-off-by: Michael Chang <mchang@suse.com>
+
+Origin: other, https://lists.gnu.org/archive/html/grub-devel/2021-03/msg00251.html
+Bug-Debian: https://bugs.debian.org/984488
+Bug-Debian: https://bugs.debian.org/985374
+Last-Update: 2021-09-24
+
+Patch-Name: pc-verifiers-module.patch
+---
+ grub-core/Makefile.am | 2 ++
+ grub-core/Makefile.core.def | 8 +++++++-
+ grub-core/kern/main.c | 4 ++++
+ grub-core/kern/verifiers.c | 17 +++++++++++++++++
+ include/grub/verify.h | 9 +++++++++
+ 5 files changed, 39 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index ee88e44e9..b6872d20f 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -93,7 +93,9 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
++if !COND_i386_pc
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/verify.h
++endif
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 2ff266806..da3269899 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -141,7 +141,7 @@ kernel = {
+ common = kern/rescue_parser.c;
+ common = kern/rescue_reader.c;
+ common = kern/term.c;
+- common = kern/verifiers.c;
++ nopc = kern/verifiers.c;
+
+ noemu = kern/compiler-rt.c;
+ noemu = kern/mm.c;
+@@ -946,6 +946,12 @@ module = {
+ cppflags = '-I$(srcdir)/lib/posix_wrap';
+ };
+
++module = {
++ name = verifiers;
++ common = kern/verifiers.c;
++ enable = i386_pc;
++};
++
+ module = {
+ name = hdparm;
+ common = commands/hdparm.c;
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index 2879d644a..c6fb66853 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -29,7 +29,9 @@
+ #include <grub/command.h>
+ #include <grub/reader.h>
+ #include <grub/parser.h>
++#ifndef GRUB_MACHINE_PCBIOS
+ #include <grub/verify.h>
++#endif
+
+ #ifdef GRUB_MACHINE_PCBIOS
+ #include <grub/machine/memory.h>
+@@ -285,8 +287,10 @@ grub_main (void)
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ #endif
+
++#ifndef GRUB_MACHINE_PCBIOS
+ /* Init verifiers API. */
+ grub_verifiers_init ();
++#endif
+
+ grub_load_config ();
+
+diff --git a/grub-core/kern/verifiers.c b/grub-core/kern/verifiers.c
+index 75d7994cf..1245d0d9e 100644
+--- a/grub-core/kern/verifiers.c
++++ b/grub-core/kern/verifiers.c
+@@ -221,8 +221,25 @@ grub_verify_string (char *str, enum grub_verify_string_type type)
+ return GRUB_ERR_NONE;
+ }
+
++/*
++ * It is intended to build verifiers as module on i386-pc platform to minimize
++ * the impact of growing core image size could blow up the 63 sectors limit of
++ * some MBR gap one day. It is also adequate to do so, given no core function
++ * on i386-pc would require the verifiers API to work.
++ */
++#ifdef GRUB_MACHINE_PCBIOS
++GRUB_MOD_INIT(verifiers)
++#else
+ void
+ grub_verifiers_init (void)
++#endif
+ {
+ grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open);
+ }
++
++#ifdef GRUB_MACHINE_PCBIOS
++GRUB_MOD_FINI(verifiers)
++{
++ grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY);
++}
++#endif
+diff --git a/include/grub/verify.h b/include/grub/verify.h
+index cd129c398..6fde244fc 100644
+--- a/include/grub/verify.h
++++ b/include/grub/verify.h
+@@ -64,10 +64,14 @@ struct grub_file_verifier
+ grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type);
+ };
+
++#ifdef GRUB_MACHINE_PCBIOS
++extern struct grub_file_verifier *grub_file_verifiers;
++#else
+ extern struct grub_file_verifier *EXPORT_VAR (grub_file_verifiers);
+
+ extern void
+ grub_verifiers_init (void);
++#endif
+
+ static inline void
+ grub_verifier_register (struct grub_file_verifier *ver)
+@@ -81,7 +85,12 @@ grub_verifier_unregister (struct grub_file_verifier *ver)
+ grub_list_remove (GRUB_AS_LIST (ver));
+ }
+
++#ifdef GRUB_MACHINE_PCBIOS
++grub_err_t
++grub_verify_string (char *str, enum grub_verify_string_type type);
++#else
+ extern grub_err_t
+ EXPORT_FUNC (grub_verify_string) (char *str, enum grub_verify_string_type type);
++#endif
+
+ #endif /* ! GRUB_VERIFY_HEADER */
diff --git a/debian/patches/ppc64el-disable-vsx.patch b/debian/patches/ppc64el-disable-vsx.patch
new file mode 100644
index 0000000..bd29ae8
--- /dev/null
+++ b/debian/patches/ppc64el-disable-vsx.patch
@@ -0,0 +1,52 @@
+From c1c72eb757d40208128fb1da02199b0210a206ab Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com>
+Date: Thu, 25 Sep 2014 19:33:39 -0300
+Subject: Disable VSX instruction
+
+VSX bit is enabled by default for Power7 and Power8 CPU models,
+so we need to disable them in order to avoid instruction exceptions.
+Kernel will activate it when necessary.
+
+* grub-core/kern/powerpc/ieee1275/startup.S: Disable VSX.
+
+Also-By: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
+Also-By: Colin Watson <cjwatson@debian.org>
+
+Origin: other, https://lists.gnu.org/archive/html/grub-devel/2014-09/msg00078.html
+Last-Update: 2015-01-27
+
+Patch-Name: ppc64el-disable-vsx.patch
+---
+ grub-core/kern/powerpc/ieee1275/startup.S | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/grub-core/kern/powerpc/ieee1275/startup.S b/grub-core/kern/powerpc/ieee1275/startup.S
+index 21c884b43..de9a9601a 100644
+--- a/grub-core/kern/powerpc/ieee1275/startup.S
++++ b/grub-core/kern/powerpc/ieee1275/startup.S
+@@ -20,6 +20,8 @@
+ #include <grub/symbol.h>
+ #include <grub/offsets.h>
+
++#define MSR_VSX 0x80
++
+ .extern __bss_start
+ .extern _end
+
+@@ -28,6 +30,16 @@
+ .globl start, _start
+ start:
+ _start:
++ _start:
++
++ /* Disable VSX instruction */
++ mfmsr 0
++ oris 0,0,MSR_VSX
++ /* The "VSX Available" bit is in the lower half of the MSR, so we
++ don't need mtmsrd, which in any case won't work in 32-bit mode. */
++ mtmsr 0
++ isync
++
+ li 2, 0
+ li 13, 0
+
diff --git a/debian/patches/probe-fusionio.patch b/debian/patches/probe-fusionio.patch
new file mode 100644
index 0000000..d0d5efa
--- /dev/null
+++ b/debian/patches/probe-fusionio.patch
@@ -0,0 +1,76 @@
+From 611974f8c3231d87ca572feda72eb6d1a5a6b309 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:31 +0000
+Subject: Probe FusionIO devices
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1237519
+Forwarded: no
+Last-Update: 2016-09-18
+
+Patch-Name: probe-fusionio.patch
+---
+ grub-core/osdep/linux/getroot.c | 13 +++++++++++++
+ util/deviceiter.c | 19 +++++++++++++++++++
+ 2 files changed, 32 insertions(+)
+
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 001b818fe..c506f4cb5 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -963,6 +963,19 @@ grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ *pp = '\0';
+ return path;
+ }
++
++ /* If this is a FusionIO disk. */
++ if ((strncmp ("fio", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
++ {
++ char *pp = p + 3;
++ while (*pp >= 'a' && *pp <= 'z')
++ pp++;
++ if (*pp)
++ *is_part = 1;
++ /* /dev/fio[a-z]+[0-9]* */
++ *pp = '\0';
++ return path;
++ }
+ }
+
+ return path;
+diff --git a/util/deviceiter.c b/util/deviceiter.c
+index b5b9ac6ab..3a8f2770e 100644
+--- a/util/deviceiter.c
++++ b/util/deviceiter.c
+@@ -384,6 +384,12 @@ get_nvme_disk_name (char *name, int controller, int namespace)
+ {
+ sprintf (name, "/dev/nvme%dn%d", controller, namespace);
+ }
++
++static void
++get_fio_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/fio%c", unit + 'a');
++}
+ #endif
+
+ static struct seen_device
+@@ -929,6 +935,19 @@ grub_util_iterate_devices (int (*hook) (const char *, int, void *), void *hook_d
+ }
+ }
+
++ /* FusionIO. */
++ for (i = 0; i < 26; i++)
++ {
++ char name[16];
++
++ get_fio_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
+ # ifdef HAVE_DEVICE_MAPPER
+ # define dmraid_check(cond, ...) \
+ if (! (cond)) \
diff --git a/debian/patches/quick-boot-lvm.patch b/debian/patches/quick-boot-lvm.patch
new file mode 100644
index 0000000..6f3ac2d
--- /dev/null
+++ b/debian/patches/quick-boot-lvm.patch
@@ -0,0 +1,77 @@
+From 4f5e080c61055b04db3cdf8067cf180f193cf89f Mon Sep 17 00:00:00 2001
+From: Steve Langasek <steve.langasek@ubuntu.com>
+Date: Tue, 30 Oct 2018 15:04:16 -0700
+Subject: If we don't have writable grubenv and we're on EFI, always show the
+ menu
+
+If we don't have writable grubenv, recordfail doesn't work, which means our
+quickboot behavior - with a timeout of 0 - leaves the user without a
+reliable way to access the boot menu if they're on UEFI, because unlike
+BIOS, UEFI does not support checking the state of modifier keys (i.e.
+holding down shift at boot is not detectable).
+
+Handle this corner case by always using a non-zero timeout on EFI when
+save_env doesn't work.
+
+Reuse GRUB_RECORDFAIL_TIMEOUT to avoid introducing another variable.
+
+Signed-off-by: Steve Langasek <steve.langasek@canonical.com>
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1800722
+Last-Update: 2019-06-24
+
+Patch-Name: quick-boot-lvm.patch
+---
+ util/grub.d/00_header.in | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index 674a76140..b7135b655 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -115,7 +115,7 @@ EOF
+ cat <<EOF
+ # GRUB lacks write support for $abstraction, so recordfail support is disabled.
+ EOF
+- return
++ return 1
+ ;;
+ esac
+ done
+@@ -126,7 +126,7 @@ EOF
+ cat <<EOF
+ # GRUB lacks write support for $FS, so recordfail support is disabled.
+ EOF
+- return
++ return 1
+ ;;
+ esac
+
+@@ -135,7 +135,9 @@ EOF
+ EOF
+ }
+
+- check_writable
++ if ! check_writable; then
++ recordfail_broken=1
++ fi
+
+ cat <<EOF
+ }
+@@ -379,6 +381,16 @@ EOF
+ fi
+ fi
+ EOF
++if [ "$recordfail_broken" = 1 ]; then
++ cat << EOF
++if [ \$grub_platform = efi ]; then
++ set timeout=${GRUB_RECORDFAIL_TIMEOUT:-30}
++ if [ x\$feature_timeout_style = xy ] ; then
++ set timeout_style=menu
++ fi
++fi
++EOF
++fi
+ }
+
+ if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then
diff --git a/debian/patches/quick-boot.patch b/debian/patches/quick-boot.patch
new file mode 100644
index 0000000..73860af
--- /dev/null
+++ b/debian/patches/quick-boot.patch
@@ -0,0 +1,358 @@
+From e760841d961fc46c5f7a82830d2e0eb6d4b53e8d Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:28 +0000
+Subject: Add configure option to bypass boot menu if possible
+
+If other operating systems are installed, then automatically unhide the
+menu. Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus if
+available to check whether Shift is pressed. If it is, show the menu,
+otherwise boot immediately. If keystatus is not available, then fall
+back to a short delay interruptible with Escape.
+
+This may or may not remain Ubuntu-specific, although it's not obviously
+wanted upstream. It implements a requirement of
+https://wiki.ubuntu.com/DesktopExperienceTeam/KarmicBootExperienceDesignSpec#Bootloader.
+
+If the previous boot failed (defined as failing to get to the end of one
+of the normal runlevels), then show the boot menu regardless.
+
+Author: Richard Laager <rlaager@wiktel.com>
+Author: Robie Basak <robie.basak@ubuntu.com>
+Forwarded: no
+Last-Update: 2015-09-04
+
+Patch-Name: quick-boot.patch
+---
+ configure.ac | 11 ++++++
+ docs/grub.texi | 14 +++++++
+ grub-core/normal/menu.c | 24 ++++++++++++
+ util/grub-mkconfig.in | 3 +-
+ util/grub.d/00_header.in | 77 +++++++++++++++++++++++++++++++------
+ util/grub.d/10_linux.in | 4 ++
+ util/grub.d/30_os-prober.in | 21 ++++++++++
+ 7 files changed, 141 insertions(+), 13 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 256fc44ef..c42e4c784 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1926,6 +1926,17 @@ else
+ fi
+ AC_SUBST([QUIET_BOOT])
+
++AC_ARG_ENABLE([quick-boot],
++ [AS_HELP_STRING([--enable-quick-boot],
++ [bypass boot menu if possible (default=no)])],
++ [], [enable_quick_boot=no])
++if test x"$enable_quick_boot" = xyes ; then
++ QUICK_BOOT=1
++else
++ QUICK_BOOT=0
++fi
++AC_SUBST([QUICK_BOOT])
++
+ LIBS=""
+
+ AC_SUBST([FONT_SOURCE])
+diff --git a/docs/grub.texi b/docs/grub.texi
+index f8b4b3b21..0b58dafb2 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -1563,6 +1563,20 @@ This option may be set to a list of GRUB module names separated by spaces.
+ Each module will be loaded as early as possible, at the start of
+ @file{grub.cfg}.
+
++@item GRUB_RECORDFAIL_TIMEOUT
++If this option is set, it overrides the default recordfail setting. A
++setting of -1 causes GRUB to wait for user input indefinitely. However, a
++false positive in the recordfail mechanism may occur if power is lost during
++boot before boot success is recorded in userspace. The default setting is
++30, which causes GRUB to wait for user input for thirty seconds before
++continuing. This default allows interactive users the opportunity to switch
++to a different, working kernel, while avoiding a false positive causing the
++boot to block indefinitely on headless and appliance systems where access to
++a console is restricted or limited.
++
++This option is only effective when GRUB was configured with the
++@option{--enable-quick-boot} option.
++
+ @end table
+
+ The following options are still accepted for compatibility with existing
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index e9d8444b5..0440340b8 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -603,6 +603,30 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
+ static struct grub_term_coordinate *pos;
+ int entry = -1;
+
++ if (timeout == 0)
++ {
++ /* If modifier key statuses can't be detected without a delay,
++ then a hidden timeout of zero cannot be interrupted in any way,
++ which is not very helpful. Bump it to three seconds in this
++ case to give the user a fighting chance. */
++ grub_term_input_t term;
++ int nterms = 0;
++ int mods_detectable = 1;
++
++ FOR_ACTIVE_TERM_INPUTS(term)
++ {
++ if (!term->getkeystatus)
++ {
++ mods_detectable = 0;
++ break;
++ }
++ else
++ nterms++;
++ }
++ if (!mods_detectable || !nterms)
++ timeout = 3;
++ }
++
+ if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
+ {
+ pos = grub_term_save_pos ();
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 0265a5a66..fa9c53a92 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -256,7 +256,8 @@ export GRUB_DEFAULT \
+ GRUB_ENABLE_CRYPTODISK \
+ GRUB_BADRAM \
+ GRUB_OS_PROBER_SKIP_LIST \
+- GRUB_DISABLE_SUBMENU
++ GRUB_DISABLE_SUBMENU \
++ GRUB_RECORDFAIL_TIMEOUT
+
+ if test "x${grub_cfg}" != "x"; then
+ rm -f "${grub_cfg}.new"
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index 93a90233e..674a76140 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -21,6 +21,8 @@ prefix="@prefix@"
+ exec_prefix="@exec_prefix@"
+ datarootdir="@datarootdir@"
+ grub_lang=`echo $LANG | cut -d . -f 1`
++grubdir="`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`"
++quick_boot="@QUICK_BOOT@"
+
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+@@ -44,6 +46,7 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT
+
+ cat << EOF
+ if [ -s \$prefix/grubenv ]; then
++ set have_grubenv=true
+ load_env
+ fi
+ EOF
+@@ -96,7 +99,50 @@ function savedefault {
+ save_env saved_entry
+ fi
+ }
++EOF
++
++if [ "$quick_boot" = 1 ]; then
++ cat <<EOF
++function recordfail {
++ set recordfail=1
++EOF
++
++ check_writable () {
++ abstractions="$(grub-probe --target=abstraction "${grubdir}")"
++ for abstraction in $abstractions; do
++ case "$abstraction" in
++ diskfilter | lvm)
++ cat <<EOF
++ # GRUB lacks write support for $abstraction, so recordfail support is disabled.
++EOF
++ return
++ ;;
++ esac
++ done
++
++ FS="$(grub-probe --target=fs "${grubdir}")"
++ case "$FS" in
++ btrfs | cpiofs | newc | odc | romfs | squash4 | tarfs | zfs)
++ cat <<EOF
++ # GRUB lacks write support for $FS, so recordfail support is disabled.
++EOF
++ return
++ ;;
++ esac
++
++ cat <<EOF
++ if [ -n "\${have_grubenv}" ]; then if [ -z "\${boot_once}" ]; then save_env recordfail; fi; fi
++EOF
++ }
++
++ check_writable
+
++ cat <<EOF
++}
++EOF
++fi
++
++cat <<EOF
+ function load_video {
+ EOF
+ if [ -n "${GRUB_VIDEO_BACKEND}" ]; then
+@@ -282,10 +328,16 @@ fi
+
+ make_timeout ()
+ {
++ cat << EOF
++if [ "\${recordfail}" = 1 ] ; then
++ set timeout=${GRUB_RECORDFAIL_TIMEOUT:-30}
++else
++EOF
+ if [ "x${3}" != "x" ] ; then
+ timeout="${2}"
+ style="${3}"
+- elif [ "x${1}" != "x" ] && [ "x${1}" != "x0" ] ; then
++ elif [ "x${1}" != "x" ] && \
++ ([ "$quick_boot" = 1 ] || [ "x${1}" != "x0" ]) ; then
+ # Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme.
+ timeout="${1}"
+ if [ "x${2}" != "x0" ] ; then
+@@ -304,26 +356,27 @@ make_timeout ()
+ style="menu"
+ fi
+ cat << EOF
+-if [ x\$feature_timeout_style = xy ] ; then
+- set timeout_style=${style}
+- set timeout=${timeout}
++ if [ x\$feature_timeout_style = xy ] ; then
++ set timeout_style=${style}
++ set timeout=${timeout}
+ EOF
+ if [ "x${style}" = "xmenu" ] ; then
+ cat << EOF
+-# Fallback normal timeout code in case the timeout_style feature is
+-# unavailable.
+-else
+- set timeout=${timeout}
++ # Fallback normal timeout code in case the timeout_style feature is
++ # unavailable.
++ else
++ set timeout=${timeout}
+ EOF
+ else
+ cat << EOF
+-# Fallback hidden-timeout code in case the timeout_style feature is
+-# unavailable.
+-elif sleep${verbose} --interruptible ${timeout} ; then
+- set timeout=0
++ # Fallback hidden-timeout code in case the timeout_style feature is
++ # unavailable.
++ elif sleep${verbose} --interruptible ${timeout} ; then
++ set timeout=0
+ EOF
+ fi
+ cat << EOF
++ fi
+ fi
+ EOF
+ }
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 869a7eec5..80315a31b 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -22,6 +22,7 @@ exec_prefix="@exec_prefix@"
+ datarootdir="@datarootdir@"
+ ubuntu_recovery="@UBUNTU_RECOVERY@"
+ quiet_boot="@QUIET_BOOT@"
++quick_boot="@QUICK_BOOT@"
+
+ . "$pkgdatadir/grub-mkconfig_lib"
+
+@@ -129,6 +130,9 @@ linux_entry ()
+ else
+ echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+ fi
++ if [ "$quick_boot" = 1 ]; then
++ echo " recordfail" | sed "s/^/$submenu_indentation/"
++ fi
+ if [ x$type != xrecovery ] ; then
+ save_default_entry | grub_add_tab
+ fi
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 98aee403e..225a3baf7 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -20,12 +20,26 @@ set -e
+ prefix="@prefix@"
+ exec_prefix="@exec_prefix@"
+ datarootdir="@datarootdir@"
++quick_boot="@QUICK_BOOT@"
+
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+
+ . "$pkgdatadir/grub-mkconfig_lib"
+
++found_other_os=
++
++adjust_timeout () {
++ if [ "$quick_boot" = 1 ] && [ "x${found_other_os}" != "x" ]; then
++ cat << EOF
++set timeout_style=menu
++if [ "\${timeout}" = 0 ]; then
++ set timeout=10
++fi
++EOF
++ fi
++}
++
+ if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then
+ grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")"
+ exit 0
+@@ -45,6 +59,7 @@ if [ -z "${OSPROBED}" ] ; then
+ fi
+
+ osx_entry() {
++ found_other_os=1
+ if [ x$2 = x32 ]; then
+ # TRANSLATORS: it refers to kernel architecture (32-bit)
+ bitstr="$(gettext "(32-bit)")"
+@@ -168,6 +183,7 @@ for OS in ${OSPROBED} ; do
+ ;;
+ esac
+
++ found_other_os=1
+ onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+ cat << EOF
+ menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
+@@ -198,6 +214,7 @@ EOF
+ ;;
+ efi)
+
++ found_other_os=1
+ EFIPATH=${DEVICE#*@}
+ DEVICE=${DEVICE%@*}
+ onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+@@ -246,6 +263,7 @@ EOF
+ [ "${prepare_boot_cache}" ] || continue
+ fi
+
++ found_other_os=1
+ onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+ recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true
+ counter=1
+@@ -322,6 +340,7 @@ EOF
+ fi
+ ;;
+ 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}")' {
+@@ -364,3 +383,5 @@ EOF
+ ;;
+ esac
+ done
++
++adjust_timeout
diff --git a/debian/patches/restore-mkdevicemap.patch b/debian/patches/restore-mkdevicemap.patch
new file mode 100644
index 0000000..3822430
--- /dev/null
+++ b/debian/patches/restore-mkdevicemap.patch
@@ -0,0 +1,1326 @@
+From a7b960126fbc0d4541babe5553546e5f9530ac48 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Mon, 13 Jan 2014 12:13:01 +0000
+Subject: Restore grub-mkdevicemap
+
+This is kind of a mess, requiring lots of OS-specific code to iterate
+over all possible devices. However, we use it in a number of scripts to
+discover devices and reimplementing those in terms of something else
+would be very complicated.
+
+Author: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+Forwarded: no
+Last-Update: 2021-09-24
+
+Patch-Name: restore-mkdevicemap.patch
+---
+ Makefile.util.def | 17 +
+ docs/man/grub-mkdevicemap.h2m | 4 +
+ include/grub/util/deviceiter.h | 14 +
+ util/deviceiter.c | 1027 ++++++++++++++++++++++++++++++++
+ util/devicemap.c | 13 +
+ util/grub-mkdevicemap.c | 181 ++++++
+ 6 files changed, 1256 insertions(+)
+ create mode 100644 docs/man/grub-mkdevicemap.h2m
+ create mode 100644 include/grub/util/deviceiter.h
+ create mode 100644 util/deviceiter.c
+ create mode 100644 util/devicemap.c
+ create mode 100644 util/grub-mkdevicemap.c
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index f8b356cc1..27f948291 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -336,6 +336,23 @@ program = {
+ condition = COND_GRUB_MKFONT;
+ };
+
++program = {
++ name = grub-mkdevicemap;
++ installdir = sbin;
++ mansection = 8;
++
++ common = util/grub-mkdevicemap.c;
++ common = util/deviceiter.c;
++ common = util/devicemap.c;
++ common = grub-core/osdep/init.c;
++
++ ldadd = libgrubmods.a;
++ ldadd = libgrubgcry.a;
++ ldadd = libgrubkern.a;
++ ldadd = grub-core/lib/gnulib/libgnu.a;
++ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
++};
++
+ program = {
+ name = grub-probe;
+ installdir = sbin;
+diff --git a/docs/man/grub-mkdevicemap.h2m b/docs/man/grub-mkdevicemap.h2m
+new file mode 100644
+index 000000000..96cd6ee72
+--- /dev/null
++++ b/docs/man/grub-mkdevicemap.h2m
+@@ -0,0 +1,4 @@
++[NAME]
++grub-mkdevicemap \- make a device map file automatically
++[SEE ALSO]
++.BR grub-probe (8)
+diff --git a/include/grub/util/deviceiter.h b/include/grub/util/deviceiter.h
+new file mode 100644
+index 000000000..85374978c
+--- /dev/null
++++ b/include/grub/util/deviceiter.h
+@@ -0,0 +1,14 @@
++#ifndef GRUB_DEVICEITER_MACHINE_UTIL_HEADER
++#define GRUB_DEVICEITER_MACHINE_UTIL_HEADER 1
++
++#include <config.h>
++
++typedef int (*grub_util_iterate_devices_hook_t) (const char *name,
++ int is_floppy, void *data);
++
++void grub_util_iterate_devices (grub_util_iterate_devices_hook_t hook,
++ void *hook_data, int floppy_disks);
++void grub_util_emit_devicemap_entry (FILE *fp, char *name, int is_floppy,
++ int *num_fd, int *num_hd);
++
++#endif /* ! GRUB_DEVICEITER_MACHINE_UTIL_HEADER */
+diff --git a/util/deviceiter.c b/util/deviceiter.c
+new file mode 100644
+index 000000000..b5b9ac6ab
+--- /dev/null
++++ b/util/deviceiter.c
+@@ -0,0 +1,1027 @@
++/* deviceiter.c - iterate over system devices */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2011 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <limits.h>
++#include <dirent.h>
++
++#include <grub/util/misc.h>
++#include <grub/util/deviceiter.h>
++#include <grub/list.h>
++#include <grub/misc.h>
++#include <grub/emu/misc.h>
++#include <grub/safemath.h>
++
++#ifdef __linux__
++# if !defined(__GLIBC__) || \
++ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
++/* Maybe libc doesn't have large file support. */
++# include <linux/unistd.h> /* _llseek */
++# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
++# include <sys/ioctl.h> /* ioctl */
++# ifndef HDIO_GETGEO
++# define HDIO_GETGEO 0x0301 /* get device geometry */
++/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
++ defined. */
++struct hd_geometry
++{
++ unsigned char heads;
++ unsigned char sectors;
++ unsigned short cylinders;
++ unsigned long start;
++};
++# endif /* ! HDIO_GETGEO */
++# ifndef FLOPPY_MAJOR
++# define FLOPPY_MAJOR 2 /* the major number for floppy */
++# endif /* ! FLOPPY_MAJOR */
++# ifndef MAJOR
++# define MAJOR(dev) \
++ ({ \
++ unsigned long long __dev = (dev); \
++ (unsigned) ((__dev >> 8) & 0xfff) \
++ | ((unsigned int) (__dev >> 32) & ~0xfff); \
++ })
++# endif /* ! MAJOR */
++# ifndef MINOR
++# define MINOR(dev) \
++ ({ \
++ unsigned long long __dev = (dev); \
++ (unsigned) (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff); \
++ })
++# endif /* ! MINOR */
++# ifndef CDROM_GET_CAPABILITY
++# define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
++# endif /* ! CDROM_GET_CAPABILITY */
++# ifndef BLKGETSIZE
++# define BLKGETSIZE _IO(0x12,96) /* return device size */
++# endif /* ! BLKGETSIZE */
++
++#ifdef HAVE_DEVICE_MAPPER
++# include <libdevmapper.h>
++# pragma GCC diagnostic ignored "-Wcast-align"
++#endif
++#endif /* __linux__ */
++
++/* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
++ kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
++#if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
++# define __FreeBSD_kernel__
++#endif
++#ifdef __FreeBSD_kernel__
++ /* Obtain version of kFreeBSD headers */
++# include <osreldate.h>
++# ifndef __FreeBSD_kernel_version
++# define __FreeBSD_kernel_version __FreeBSD_version
++# endif
++
++ /* Runtime detection of kernel */
++# include <sys/utsname.h>
++static int
++get_kfreebsd_version (void)
++{
++ struct utsname uts;
++ int major;
++ int minor;
++ int v[2];
++
++ uname (&uts);
++ sscanf (uts.release, "%d.%d", &major, &minor);
++
++ if (major >= 9)
++ major = 9;
++ if (major >= 5)
++ {
++ v[0] = minor/10; v[1] = minor%10;
++ }
++ else
++ {
++ v[0] = minor%10; v[1] = minor/10;
++ }
++ return major*100000+v[0]*10000+v[1]*1000;
++}
++#endif /* __FreeBSD_kernel__ */
++
++#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
++# include <sys/ioctl.h> /* ioctl */
++# include <sys/disklabel.h>
++# include <sys/cdio.h> /* CDIOCCLRDEBUG */
++# if defined(__FreeBSD_kernel__)
++# include <sys/param.h>
++# if __FreeBSD_kernel_version >= 500040
++# include <sys/disk.h>
++# endif
++# endif /* __FreeBSD_kernel__ */
++#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
++
++#ifdef HAVE_OPENDISK
++# include <util.h>
++#endif /* HAVE_OPENDISK */
++
++#ifdef __linux__
++/* Check if we have devfs support. */
++static int
++have_devfs (void)
++{
++ struct stat st;
++ return stat ("/dev/.devfsd", &st) == 0;
++}
++#endif /* __linux__ */
++
++/* These three functions are quite different among OSes. */
++static void
++get_floppy_disk_name (char *name, int unit)
++{
++#if defined(__linux__)
++ /* GNU/Linux */
++ if (have_devfs ())
++ sprintf (name, "/dev/floppy/%d", unit);
++ else
++ sprintf (name, "/dev/fd%d", unit);
++#elif defined(__GNU__)
++ /* GNU/Hurd */
++ sprintf (name, "/dev/fd%d", unit);
++#elif defined(__FreeBSD_kernel__)
++ /* kFreeBSD */
++ if (get_kfreebsd_version () >= 400000)
++ sprintf (name, "/dev/fd%d", unit);
++ else
++ sprintf (name, "/dev/rfd%d", unit);
++#elif defined(__NetBSD__)
++ /* NetBSD */
++ /* opendisk() doesn't work for floppies. */
++ sprintf (name, "/dev/rfd%da", unit);
++#elif defined(__OpenBSD__)
++ /* OpenBSD */
++ sprintf (name, "/dev/rfd%dc", unit);
++#elif defined(__QNXNTO__)
++ /* QNX RTP */
++ sprintf (name, "/dev/fd%d", unit);
++#elif defined(__CYGWIN__)
++ /* Cygwin */
++ sprintf (name, "/dev/fd%d", unit);
++#elif defined(__MINGW32__)
++ (void) unit;
++ *name = 0;
++#else
++# warning "BIOS floppy drives cannot be guessed in your operating system."
++ /* Set NAME to a bogus string. */
++ *name = 0;
++#endif
++}
++
++static void
++get_ide_disk_name (char *name, int unit)
++{
++#if defined(__linux__)
++ /* GNU/Linux */
++ sprintf (name, "/dev/hd%c", unit + 'a');
++#elif defined(__GNU__)
++ /* GNU/Hurd */
++ sprintf (name, "/dev/hd%d", unit);
++#elif defined(__FreeBSD_kernel__)
++ /* kFreeBSD */
++ if (get_kfreebsd_version () >= 400000)
++ sprintf (name, "/dev/ad%d", unit);
++ else
++ sprintf (name, "/dev/rwd%d", unit);
++#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
++ /* NetBSD */
++ char shortname[16];
++ int fd;
++
++ sprintf (shortname, "wd%d", unit);
++ fd = opendisk (shortname, O_RDONLY, name,
++ 16, /* length of NAME */
++ 0 /* char device */
++ );
++ close (fd);
++#elif defined(__OpenBSD__)
++ /* OpenBSD */
++ sprintf (name, "/dev/rwd%dc", unit);
++#elif defined(__QNXNTO__)
++ /* QNX RTP */
++ /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
++ contain SCSI disks. */
++ sprintf (name, "/dev/hd%d", unit);
++#elif defined(__CYGWIN__)
++ /* Cygwin emulates all disks as /dev/sdX. */
++ (void) unit;
++ *name = 0;
++#elif defined(__MINGW32__)
++ sprintf (name, "//./PHYSICALDRIVE%d", unit);
++#else
++# warning "BIOS IDE drives cannot be guessed in your operating system."
++ /* Set NAME to a bogus string. */
++ *name = 0;
++#endif
++}
++
++static void
++get_scsi_disk_name (char *name, int unit)
++{
++#if defined(__linux__)
++ /* GNU/Linux */
++ sprintf (name, "/dev/sd%c", unit + 'a');
++#elif defined(__GNU__)
++ /* GNU/Hurd */
++ sprintf (name, "/dev/sd%d", unit);
++#elif defined(__FreeBSD_kernel__)
++ /* kFreeBSD */
++ if (get_kfreebsd_version () >= 400000)
++ sprintf (name, "/dev/da%d", unit);
++ else
++ sprintf (name, "/dev/rda%d", unit);
++#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
++ /* NetBSD */
++ char shortname[16];
++ int fd;
++
++ sprintf (shortname, "sd%d", unit);
++ fd = opendisk (shortname, O_RDONLY, name,
++ 16, /* length of NAME */
++ 0 /* char device */
++ );
++ close (fd);
++#elif defined(__OpenBSD__)
++ /* OpenBSD */
++ sprintf (name, "/dev/rsd%dc", unit);
++#elif defined(__QNXNTO__)
++ /* QNX RTP */
++ /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
++ disable the detection of SCSI disks here. */
++ *name = 0;
++#elif defined(__CYGWIN__)
++ /* Cygwin emulates all disks as /dev/sdX. */
++ sprintf (name, "/dev/sd%c", unit + 'a');
++#elif defined(__MINGW32__)
++ (void) unit;
++ *name = 0;
++#else
++# warning "BIOS SCSI drives cannot be guessed in your operating system."
++ /* Set NAME to a bogus string. */
++ *name = 0;
++#endif
++}
++
++#ifdef __FreeBSD_kernel__
++static void
++get_ada_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/ada%d", unit);
++}
++
++static void
++get_ataraid_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/ar%d", unit);
++}
++
++static void
++get_mfi_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/mfid%d", unit);
++}
++
++static void
++get_virtio_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/vtbd%d", unit);
++}
++
++static void
++get_xvd_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/xbd%d", unit);
++}
++#endif
++
++#ifdef __linux__
++static void
++get_virtio_disk_name (char *name, int unit)
++{
++#ifdef __sparc__
++ sprintf (name, "/dev/vdisk%c", unit + 'a');
++#else
++ sprintf (name, "/dev/vd%c", unit + 'a');
++#endif
++}
++
++static void
++get_dac960_disk_name (char *name, int controller, int drive)
++{
++ sprintf (name, "/dev/rd/c%dd%d", controller, drive);
++}
++
++static void
++get_acceleraid_disk_name (char *name, int controller, int drive)
++{
++ sprintf (name, "/dev/rs/c%dd%d", controller, drive);
++}
++
++static void
++get_ataraid_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/ataraid/d%c", unit + '0');
++}
++
++static void
++get_i2o_disk_name (char *name, char unit)
++{
++ sprintf (name, "/dev/i2o/hd%c", unit);
++}
++
++static void
++get_cciss_disk_name (char *name, int controller, int drive)
++{
++ sprintf (name, "/dev/cciss/c%dd%d", controller, drive);
++}
++
++static void
++get_ida_disk_name (char *name, int controller, int drive)
++{
++ sprintf (name, "/dev/ida/c%dd%d", controller, drive);
++}
++
++static void
++get_mmc_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/mmcblk%d", unit);
++}
++
++static void
++get_xvd_disk_name (char *name, int unit)
++{
++ sprintf (name, "/dev/xvd%c", unit + 'a');
++}
++
++static void
++get_nvme_disk_name (char *name, int controller, int namespace)
++{
++ sprintf (name, "/dev/nvme%dn%d", controller, namespace);
++}
++#endif
++
++static struct seen_device
++{
++ struct seen_device *next;
++ struct seen_device **prev;
++ const char *name;
++} *seen;
++
++/* Check if DEVICE can be read. Skip any DEVICE that we have already seen.
++ If an error occurs, return zero, otherwise return non-zero. */
++static int
++check_device_readable_unique (const char *device)
++{
++ char *real_device;
++ char buf[512];
++ FILE *fp;
++ struct seen_device *seen_elt;
++
++ /* If DEVICE is empty, just return error. */
++ if (*device == 0)
++ return 0;
++
++ /* Have we seen this device already? */
++ real_device = canonicalize_file_name (device);
++ if (! real_device)
++ return 0;
++ if (grub_named_list_find (GRUB_AS_NAMED_LIST (seen), real_device))
++ {
++ grub_dprintf ("deviceiter", "Already seen %s (%s)\n",
++ device, real_device);
++ goto fail;
++ }
++
++ fp = fopen (device, "r");
++ if (! fp)
++ {
++ switch (errno)
++ {
++#ifdef ENOMEDIUM
++ case ENOMEDIUM:
++# if 0
++ /* At the moment, this finds only CDROMs, which can't be
++ read anyway, so leave it out. Code should be
++ reactivated if `removable disks' and CDROMs are
++ supported. */
++ /* Accept it, it may be inserted. */
++ return 1;
++# endif
++ break;
++#endif /* ENOMEDIUM */
++ default:
++ /* Break case and leave. */
++ break;
++ }
++ /* Error opening the device. */
++ goto fail;
++ }
++
++ /* Make sure CD-ROMs don't get assigned a BIOS disk number
++ before SCSI disks! */
++#ifdef __linux__
++# ifdef CDROM_GET_CAPABILITY
++ if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
++ goto fail;
++# else /* ! CDROM_GET_CAPABILITY */
++ /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
++ {
++ struct hd_geometry hdg;
++ struct stat st;
++
++ if (fstat (fileno (fp), &st))
++ goto fail;
++
++ /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
++ succeeds. */
++ if (S_ISBLK (st.st_mode)
++ && MAJOR (st.st_rdev) != FLOPPY_MAJOR
++ && ioctl (fileno (fp), HDIO_GETGEO, &hdg))
++ goto fail;
++ }
++# endif /* ! CDROM_GET_CAPABILITY */
++#endif /* __linux__ */
++
++#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
++# ifdef CDIOCCLRDEBUG
++ if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
++ goto fail;
++# endif /* CDIOCCLRDEBUG */
++#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
++
++ /* Attempt to read the first sector. */
++ if (fread (buf, 1, 512, fp) != 512)
++ {
++ fclose (fp);
++ goto fail;
++ }
++
++ /* Remember that we've seen this device. */
++ seen_elt = xmalloc (sizeof (*seen_elt));
++ seen_elt->name = real_device; /* steal memory */
++ grub_list_push (GRUB_AS_LIST_P (&seen), GRUB_AS_LIST (seen_elt));
++
++ fclose (fp);
++ return 1;
++
++fail:
++ free (real_device);
++ return 0;
++}
++
++static void
++clear_seen_devices (void)
++{
++ while (seen)
++ {
++ struct seen_device *seen_elt = seen;
++ seen = seen->next;
++ free (seen_elt);
++ }
++ seen = NULL;
++}
++
++#ifdef __linux__
++struct device
++{
++ char *stable;
++ char *kernel;
++};
++
++/* Sort by the kernel name for preference since that most closely matches
++ older device.map files, but sort by stable by-id names as a fallback.
++ This is because /dev/disk/by-id/ usually has a few alternative
++ identifications of devices (e.g. ATA vs. SATA).
++ check_device_readable_unique will ensure that we only get one for any
++ given disk, but sort the list so that the choice of which one we get is
++ stable. */
++static int
++compare_devices (const void *a, const void *b)
++{
++ const struct device *left = (const struct device *) a;
++ const struct device *right = (const struct device *) b;
++
++ if (left->kernel && right->kernel)
++ {
++ int ret = strcmp (left->kernel, right->kernel);
++ if (ret)
++ return ret;
++ }
++
++ return strcmp (left->stable, right->stable);
++}
++#endif /* __linux__ */
++
++void
++grub_util_iterate_devices (int (*hook) (const char *, int, void *), void *hook_data,
++ int floppy_disks)
++{
++ int i;
++
++ clear_seen_devices ();
++
++ /* Floppies. */
++ for (i = 0; i < floppy_disks; i++)
++ {
++ char name[32];
++ struct stat st;
++
++ get_floppy_disk_name (name, i);
++ if (stat (name, &st) < 0)
++ break;
++ /* In floppies, write the map, whether check_device_readable_unique
++ succeeds or not, because the user just may not insert floppies. */
++ if (hook (name, 1, hook_data))
++ goto out;
++ }
++
++#ifdef __linux__
++ {
++ DIR *dir = opendir ("/dev/disk/by-id");
++
++ if (dir)
++ {
++ struct dirent *entry;
++ struct device *devs;
++ size_t devs_len = 0, devs_max = 1024, dev;
++
++ devs = xcalloc (devs_max, sizeof (*devs));
++
++ /* Dump all the directory entries into names, resizing if
++ necessary. */
++ for (entry = readdir (dir); entry; entry = readdir (dir))
++ {
++ /* Skip current and parent directory entries. */
++ if (strcmp (entry->d_name, ".") == 0 ||
++ strcmp (entry->d_name, "..") == 0)
++ continue;
++ /* Skip partition entries. */
++ if (strstr (entry->d_name, "-part"))
++ continue;
++ /* Skip device-mapper entries; we'll handle the ones we want
++ later. */
++ if (strncmp (entry->d_name, "dm-", sizeof ("dm-") - 1) == 0)
++ continue;
++ /* Skip RAID entries; they are handled by upper layers. */
++ if (strncmp (entry->d_name, "md-", sizeof ("md-") - 1) == 0)
++ continue;
++ if (devs_len >= devs_max)
++ {
++ size_t sz;
++
++ devs_max *= 2;
++ sz = devs_max;
++ if (grub_mul (sz, sizeof (*devs), &sz))
++ grub_util_error ("%s", _("overflow is detected"));
++ devs = xrealloc (devs, sz);
++ }
++ devs[devs_len].stable =
++ xasprintf ("/dev/disk/by-id/%s", entry->d_name);
++ devs[devs_len].kernel =
++ canonicalize_file_name (devs[devs_len].stable);
++ devs_len++;
++ }
++
++ qsort (devs, devs_len, sizeof (*devs), &compare_devices);
++
++ closedir (dir);
++
++ /* Now add all the devices in sorted order. */
++ for (dev = 0; dev < devs_len; ++dev)
++ {
++ if (check_device_readable_unique (devs[dev].stable))
++ {
++ if (hook (devs[dev].stable, 0, hook_data))
++ goto out;
++ }
++ free (devs[dev].stable);
++ free (devs[dev].kernel);
++ }
++ free (devs);
++ }
++ }
++
++ if (have_devfs ())
++ {
++ i = 0;
++ while (1)
++ {
++ char discn[32];
++ char name[PATH_MAX];
++ struct stat st;
++
++ /* Linux creates symlinks "/dev/discs/discN" for convenience.
++ The way to number disks is the same as GRUB's. */
++ sprintf (discn, "/dev/discs/disc%d", i++);
++ if (stat (discn, &st) < 0)
++ break;
++
++ if (realpath (discn, name))
++ {
++ strcat (name, "/disc");
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++ goto out;
++ }
++#endif /* __linux__ */
++
++ /* IDE disks. */
++ for (i = 0; i < 96; i++)
++ {
++ char name[16];
++
++ get_ide_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++#ifdef __FreeBSD_kernel__
++ /* IDE disks using ATA Direct Access driver. */
++ if (get_kfreebsd_version () >= 800000)
++ for (i = 0; i < 96; i++)
++ {
++ char name[16];
++
++ get_ada_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++ /* ATARAID disks. */
++ for (i = 0; i < 8; i++)
++ {
++ char name[20];
++
++ get_ataraid_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++ /* LSI MegaRAID SAS. */
++ for (i = 0; i < 32; i++)
++ {
++ char name[20];
++
++ get_mfi_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++ /* Virtio disks. */
++ for (i = 0; i < 96; i++)
++ {
++ char name[16];
++
++ get_virtio_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++ /* Xen virtual block devices. */
++ for (i = 0; i < 96; i++)
++ {
++ char name[16];
++
++ get_xvd_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++#endif
++
++#ifdef __linux__
++ /* Virtio disks. */
++ for (i = 0; i < 26; i++)
++ {
++ char name[16];
++
++ get_virtio_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++ /* ATARAID disks. */
++ for (i = 0; i < 8; i++)
++ {
++ char name[20];
++
++ get_ataraid_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++ /* Xen virtual block devices. */
++ for (i = 0; i < 26; i++)
++ {
++ char name[16];
++
++ get_xvd_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++#endif /* __linux__ */
++
++ /* The rest is SCSI disks. */
++ for (i = 0; i < 48; i++)
++ {
++ char name[16];
++
++ get_scsi_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++#ifdef __linux__
++ /* This is for DAC960 - we have
++ /dev/rd/c<controller>d<logical drive>p<partition>.
++
++ DAC960 driver currently supports up to 8 controllers, 32 logical
++ drives, and 7 partitions. */
++ {
++ int controller, drive;
++
++ for (controller = 0; controller < 8; controller++)
++ {
++ for (drive = 0; drive < 15; drive++)
++ {
++ char name[24];
++
++ get_dac960_disk_name (name, controller, drive);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++ }
++ }
++
++ /* This is for Mylex Acceleraid - we have
++ /dev/rd/c<controller>d<logical drive>p<partition>. */
++ {
++ int controller, drive;
++
++ for (controller = 0; controller < 8; controller++)
++ {
++ for (drive = 0; drive < 15; drive++)
++ {
++ char name[24];
++
++ get_acceleraid_disk_name (name, controller, drive);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++ }
++ }
++
++ /* This is for CCISS - we have
++ /dev/cciss/c<controller>d<logical drive>p<partition>. */
++ {
++ int controller, drive;
++
++ for (controller = 0; controller < 3; controller++)
++ {
++ for (drive = 0; drive < 16; drive++)
++ {
++ char name[24];
++
++ get_cciss_disk_name (name, controller, drive);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++ }
++ }
++
++ /* This is for Compaq Intelligent Drive Array - we have
++ /dev/ida/c<controller>d<logical drive>p<partition>. */
++ {
++ int controller, drive;
++
++ for (controller = 0; controller < 3; controller++)
++ {
++ for (drive = 0; drive < 16; drive++)
++ {
++ char name[24];
++
++ get_ida_disk_name (name, controller, drive);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++ }
++ }
++
++ /* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */
++ {
++ char unit;
++
++ for (unit = 'a'; unit < 'f'; unit++)
++ {
++ char name[24];
++
++ get_i2o_disk_name (name, unit);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++ }
++
++ /* MultiMediaCard (MMC). */
++ for (i = 0; i < 10; i++)
++ {
++ char name[16];
++
++ get_mmc_disk_name (name, i);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++
++ /* This is for standard NVMe controllers
++ /dev/nvme<controller>n<namespace>p<partition>. No idea about
++ actual limits of how many controllers a system can have and/or
++ how many namespace that would be, 10 for now. */
++ {
++ int controller, namespace;
++
++ for (controller = 0; controller < 10; controller++)
++ {
++ for (namespace = 0; namespace < 10; namespace++)
++ {
++ char name[16];
++
++ get_nvme_disk_name (name, controller, namespace);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ goto out;
++ }
++ }
++ }
++ }
++
++# ifdef HAVE_DEVICE_MAPPER
++# define dmraid_check(cond, ...) \
++ if (! (cond)) \
++ { \
++ grub_dprintf ("deviceiter", __VA_ARGS__); \
++ goto dmraid_end; \
++ }
++
++ /* DM-RAID. */
++ if (grub_device_mapper_supported ())
++ {
++ struct dm_tree *tree = NULL;
++ struct dm_task *task = NULL;
++ struct dm_names *names = NULL;
++ unsigned int next = 0;
++ void *top_handle, *second_handle;
++ struct dm_tree_node *root, *top, *second;
++
++ /* Build DM tree for all devices. */
++ tree = dm_tree_create ();
++ dmraid_check (tree, "dm_tree_create failed\n");
++ task = dm_task_create (DM_DEVICE_LIST);
++ dmraid_check (task, "dm_task_create failed\n");
++ dmraid_check (dm_task_run (task), "dm_task_run failed\n");
++ names = dm_task_get_names (task);
++ dmraid_check (names, "dm_task_get_names failed\n");
++ dmraid_check (names->dev, "No DM devices found\n");
++ do
++ {
++ names = (struct dm_names *) ((char *) names + next);
++ dmraid_check (dm_tree_add_dev (tree, MAJOR (names->dev),
++ MINOR (names->dev)),
++ "dm_tree_add_dev (%s) failed\n", names->name);
++ next = names->next;
++ }
++ while (next);
++
++ /* Walk the second-level children of the inverted tree; that is, devices
++ which are directly composed of non-DM devices such as hard disks.
++ This class includes all DM-RAID disks and excludes all DM-RAID
++ partitions. */
++ root = dm_tree_find_node (tree, 0, 0);
++ top_handle = NULL;
++ top = dm_tree_next_child (&top_handle, root, 1);
++ while (top)
++ {
++ second_handle = NULL;
++ second = dm_tree_next_child (&second_handle, top, 1);
++ while (second)
++ {
++ const char *node_name, *node_uuid;
++ char *name;
++
++ node_name = dm_tree_node_get_name (second);
++ dmraid_check (node_name, "dm_tree_node_get_name failed\n");
++ node_uuid = dm_tree_node_get_uuid (second);
++ dmraid_check (node_uuid, "dm_tree_node_get_uuid failed\n");
++ if (strstr (node_uuid, "DMRAID-") == 0)
++ {
++ grub_dprintf ("deviceiter", "%s is not DM-RAID\n", node_name);
++ goto dmraid_next_child;
++ }
++
++ name = xasprintf ("/dev/mapper/%s", node_name);
++ if (check_device_readable_unique (name))
++ {
++ if (hook (name, 0, hook_data))
++ {
++ free (name);
++ if (task)
++ dm_task_destroy (task);
++ if (tree)
++ dm_tree_free (tree);
++ goto out;
++ }
++ }
++ free (name);
++
++dmraid_next_child:
++ second = dm_tree_next_child (&second_handle, top, 1);
++ }
++ top = dm_tree_next_child (&top_handle, root, 1);
++ }
++
++dmraid_end:
++ if (task)
++ dm_task_destroy (task);
++ if (tree)
++ dm_tree_free (tree);
++ }
++# endif /* HAVE_DEVICE_MAPPER */
++#endif /* __linux__ */
++
++out:
++ clear_seen_devices ();
++}
+diff --git a/util/devicemap.c b/util/devicemap.c
+new file mode 100644
+index 000000000..c61864420
+--- /dev/null
++++ b/util/devicemap.c
+@@ -0,0 +1,13 @@
++#include <stdio.h>
++
++#include <grub/util/deviceiter.h>
++
++void
++grub_util_emit_devicemap_entry (FILE *fp, char *name, int is_floppy,
++ int *num_fd, int *num_hd)
++{
++ if (is_floppy)
++ fprintf (fp, "(fd%d)\t%s\n", (*num_fd)++, name);
++ else
++ fprintf (fp, "(hd%d)\t%s\n", (*num_hd)++, name);
++}
+diff --git a/util/grub-mkdevicemap.c b/util/grub-mkdevicemap.c
+new file mode 100644
+index 000000000..c4bbdbf69
+--- /dev/null
++++ b/util/grub-mkdevicemap.c
+@@ -0,0 +1,181 @@
++/* grub-mkdevicemap.c - make a device map file automatically */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,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 <http://www.gnu.org/licenses/>.
++ */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <limits.h>
++
++#include <grub/emu/misc.h>
++#include <grub/emu/hostdisk.h>
++#include <grub/util/misc.h>
++#include <grub/util/deviceiter.h>
++#include <grub/env.h>
++#include <grub/i18n.h>
++
++#define _GNU_SOURCE 1
++#include <getopt.h>
++
++#include "progname.h"
++
++/* Context for make_device_map. */
++struct make_device_map_ctx
++{
++ FILE *fp;
++ int num_fd;
++ int num_hd;
++};
++
++/* Helper for make_device_map. */
++static int
++process_device (const char *name, int is_floppy, void *data)
++{
++ struct make_device_map_ctx *ctx = data;
++
++ grub_util_emit_devicemap_entry (ctx->fp, (char *) name,
++ is_floppy, &ctx->num_fd, &ctx->num_hd);
++ return 0;
++}
++
++static void
++make_device_map (const char *device_map, int floppy_disks)
++{
++ struct make_device_map_ctx ctx = {
++ .num_fd = 0,
++ .num_hd = 0
++ };
++
++ if (strcmp (device_map, "-") == 0)
++ ctx.fp = stdout;
++ else
++ ctx.fp = fopen (device_map, "w");
++
++ if (! ctx.fp)
++ grub_util_error (_("cannot open %s"), device_map);
++
++ grub_util_iterate_devices (process_device, &ctx, floppy_disks);
++
++ if (ctx.fp != stdout)
++ fclose (ctx.fp);
++}
++
++static struct option options[] =
++ {
++ {"device-map", required_argument, 0, 'm'},
++ {"probe-second-floppy", no_argument, 0, 's'},
++ {"no-floppy", no_argument, 0, 'n'},
++ {"help", no_argument, 0, 'h'},
++ {"version", no_argument, 0, 'V'},
++ {"verbose", no_argument, 0, 'v'},
++ {0, 0, 0, 0}
++ };
++
++static void
++usage (int status)
++{
++ if (status)
++ fprintf (stderr,
++ _("Try `%s --help' for more information.\n"), program_name);
++ else
++ printf (_("\
++Usage: %s [OPTION]...\n\
++\n\
++Generate a device map file automatically.\n\
++\n\
++ -n, --no-floppy do not probe any floppy drive\n\
++ -s, --probe-second-floppy probe the second floppy drive\n\
++ -m, --device-map=FILE use FILE as the device map [default=%s]\n\
++ -h, --help display this message and exit\n\
++ -V, --version print version information and exit\n\
++ -v, --verbose print verbose messages\n\
++\n\
++Report bugs to <%s>.\n\
++"), program_name,
++ DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT);
++
++ exit (status);
++}
++
++int
++main (int argc, char *argv[])
++{
++ char *dev_map = 0;
++ int floppy_disks = 1;
++
++ grub_util_host_init (&argc, &argv);
++
++ /* Check for options. */
++ while (1)
++ {
++ int c = getopt_long (argc, argv, "snm:r:hVv", options, 0);
++
++ if (c == -1)
++ break;
++ else
++ switch (c)
++ {
++ case 'm':
++ if (dev_map)
++ free (dev_map);
++
++ dev_map = xstrdup (optarg);
++ break;
++
++ case 'n':
++ floppy_disks = 0;
++ break;
++
++ case 's':
++ floppy_disks = 2;
++ break;
++
++ case 'h':
++ usage (0);
++ break;
++
++ case 'V':
++ printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
++ return 0;
++
++ case 'v':
++ verbosity++;
++ break;
++
++ default:
++ usage (1);
++ break;
++ }
++ }
++
++ if (verbosity > 1)
++ grub_env_set ("debug", "all");
++
++ make_device_map (dev_map ? : DEFAULT_DEVICE_MAP, floppy_disks);
++
++ free (dev_map);
++
++ return 0;
++}
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..714292a
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,129 @@
+olpc-prefix-hack.patch
+core-in-fs.patch
+dpkg-version-comparison.patch
+grub-legacy-0-based-partitions.patch
+disable-floppies.patch
+grub.cfg-400.patch
+gfxpayload-keep-default.patch
+install-stage2-confusion.patch
+mkrescue-efi-modules.patch
+mkconfig-loopback.patch
+restore-mkdevicemap.patch
+gettext-quiet.patch
+install-efi-fallback.patch
+mkconfig-ubuntu-recovery.patch
+install-locale-langpack.patch
+mkconfig-nonexistent-loopback.patch
+default-grub-d.patch
+blacklist-1440x900x32.patch
+mkconfig-ubuntu-distributor.patch
+linuxefi.patch
+mkconfig-signed-kernel.patch
+install-signed.patch
+wubi-no-windows.patch
+maybe-quiet.patch
+install-efi-adjust-distributor.patch
+quick-boot.patch
+quick-boot-lvm.patch
+gfxpayload-dynamic.patch
+vt-handoff.patch
+probe-fusionio.patch
+ignore-grub_func_test-failures.patch
+mkconfig-recovery-title.patch
+install-powerpc-machtypes.patch
+ieee1275-clear-reset.patch
+ppc64el-disable-vsx.patch
+grub-install-pvxen-paths.patch
+insmod-xzio-and-lzopio-on-xen.patch
+grub-install-extra-removable.patch
+mkconfig-other-inits.patch
+zpool-full-device-name.patch
+net-read-bracketed-ipv6-addr.patch
+bootp-new-net_bootp6-command.patch
+efinet-uefi-ipv6-pxe-support.patch
+bootp-process-dhcpack-http-boot.patch
+efinet-set-network-from-uefi-devpath.patch
+efinet-set-dns-from-uefi-proto.patch
+fix-lockdown.patch
+skip-grub_cmd_set_date.patch
+bash-completion-drop-have-checks.patch
+at_keyboard-module-init.patch
+uefi-secure-boot-cryptomount.patch
+efi-variable-storage-minimise-writes.patch
+grub-install-removable-shim.patch
+dejavu-font-path.patch
+xen-no-xsm-policy-in-non-xsm-options.patch
+pc-verifiers-module.patch
+debug_verifiers.patch
+mkimage-fix-section-sizes.patch
+tpm-unknown-error-non-fatal.patch
+xfs-fix-v4-superblock.patch
+tests-ahci-update-qemu-device-name.patch
+minilzo-2.10.patch
+0063-loader-efi-chainloader-Simplify-the-loader-state.patch
+0064-commands-boot-Add-API-to-pass-context-to-loader.patch
+0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch
+0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
+0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
+0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
+0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch
+0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
+0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
+0072-video-readers-png-Sanity-check-some-huffman-codes.patch
+0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
+0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
+0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
+0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
+0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
+0078-net-netbuff-Block-overly-large-netbuff-allocs.patch
+0079-net-ip-Do-IP-fragment-maths-safely.patch
+0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
+0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
+0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
+0083-net-tftp-Avoid-a-trivial-UAF.patch
+0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
+0085-net-http-Fix-OOB-write-for-split-http-headers.patch
+0086-net-http-Error-out-on-headers-with-LF-without-CR.patch
+0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
+0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
+0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
+0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
+0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
+0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
+fs-tester-time-fail.patch
+cve_2022_2601/0001-video-readers-Add-artificial-limit-to-image-dimensio.patch
+cve_2022_2601/0002-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
+cve_2022_2601/0003-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
+cve_2022_2601/0004-font-Fix-several-integer-overflows-in-grub_font_cons.patch
+cve_2022_2601/0005-font-Remove-grub_font_dup_glyph.patch
+cve_2022_2601/0006-font-Fix-integer-overflow-in-ensure_comb_space.patch
+cve_2022_2601/0007-font-Fix-integer-overflow-in-BMP-index.patch
+cve_2022_2601/0008-font-Fix-integer-underflow-in-binary-search-of-char-.patch
+cve_2022_2601/0009-kern-efi-sb-Enforce-verification-of-font-files.patch
+cve_2022_2601/0010-fbutil-Fix-integer-overflow.patch
+cve_2022_2601/0011-font-Fix-an-integer-underflow-in-blit_comb.patch
+cve_2022_2601/0012-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
+cve_2022_2601/0013-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
+cve_2022_2601/0014-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
+font-Try-opening-fonts-from-the-bundled-memdisk.patch
+kern-file-Fix-error-handling-in-grub_file_open.patch
+gcc12_build_dangling_pointer.patch
+gcc12_build_array_bounds.patch
+gcc12_build_array_bounds2.patch
+arm64_remove_magic_number_check.patch
+grub_mkconfig_restore_umask.patch
+ignore_checksum_seed_incompat_feature.patch
+ignore_the_large_dir_incompat_feature.patch
+987008-lvrename-boot-fail.patch
+disk-cryptodisk-when-cheatmounting-use-the-sector-info-of-the-cheat-device.patch
+osdep-devmapper-getroot-have-devmapper-recognize-luks2.patch
+osdep-devmapper-getroot-set-up-cheated-luks2-cryptodisk-mount-from-dm-parameters.patch
+arm64-handover-to-kernel-if-sb-enabled.patch
+grub_os-prober.patch
+os-prober-Allow-initrd-to-contain-spaces.patch
+ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_LIST-.patch
+ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-reside.patch
+ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entries-fr.patch
+ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-index-at.patch
+ntfs-cve-fixes/fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch
+ntfs-cve-fixes/fs-ntfs-Make-code-more-readable.patch
diff --git a/debian/patches/skip-grub_cmd_set_date.patch b/debian/patches/skip-grub_cmd_set_date.patch
new file mode 100644
index 0000000..830b887
--- /dev/null
+++ b/debian/patches/skip-grub_cmd_set_date.patch
@@ -0,0 +1,27 @@
+From dc8f60ab6ca24cb871fe17955385138d43712727 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Sun, 28 Oct 2018 19:45:56 +0000
+Subject: Skip flaky grub_cmd_set_date test
+
+Bug-Debian: https://bugs.debian.org/906470
+Last-Update: 2018-10-28
+
+Patch-Name: skip-grub_cmd_set_date.patch
+---
+ tests/grub_cmd_set_date.in | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tests/grub_cmd_set_date.in b/tests/grub_cmd_set_date.in
+index aac120a6c..1bb5be4ca 100644
+--- a/tests/grub_cmd_set_date.in
++++ b/tests/grub_cmd_set_date.in
+@@ -1,6 +1,9 @@
+ #! @BUILD_SHEBANG@
+ set -e
+
++echo "Skipping flaky test."
++exit 77
++
+ . "@builddir@/grub-core/modinfo.sh"
+
+ case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in
diff --git a/debian/patches/tests-ahci-update-qemu-device-name.patch b/debian/patches/tests-ahci-update-qemu-device-name.patch
new file mode 100644
index 0000000..f10fc08
--- /dev/null
+++ b/debian/patches/tests-ahci-update-qemu-device-name.patch
@@ -0,0 +1,34 @@
+From 1a1c93cd19a9ec67d6237d5a537976ff9297ab78 Mon Sep 17 00:00:00 2001
+From: Marius Bakke <marius@gnu.org>
+Date: Sun, 13 Jun 2021 15:11:51 +0200
+Subject: tests/ahci: Change "ide-drive" deprecated QEMU device name to
+ "ide-hd"
+
+The "ide-drive" device was removed in QEMU 6.0. The "ide-hd" has been
+available for more than 10 years now in QEMU. Thus there shouldn't be
+any need for backwards compatible names.
+
+Signed-off-by: Marius Bakke <marius@gnu.org>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+Origin: upstream, https://git.savannah.gnu.org/cgit/grub.git/commit/?id=aaea244a6ddd1e35aed60a5c7a08ddc41f51805b
+Last-Update: 2021-09-24
+
+Patch-Name: tests-ahci-update-qemu-device-name.patch
+---
+ tests/ahci_test.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tests/ahci_test.in b/tests/ahci_test.in
+index 7df560462..d844fe680 100644
+--- a/tests/ahci_test.in
++++ b/tests/ahci_test.in
+@@ -41,7 +41,7 @@ echo "hello" > "$outfile"
+
+ tar cf "$imgfile" "$outfile"
+
+-if [ "$(echo "nativedisk; source '(ahci0)/$outfile';" | "${grubshell}" --qemu-opts="-drive id=disk,file=$imgfile,if=none -device ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0 " | tail -n 1)" != "Hello World" ]; then
++if [ "$(echo "nativedisk; source '(ahci0)/$outfile';" | "${grubshell}" --qemu-opts="-drive id=disk,file=$imgfile,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 " | tail -n 1)" != "Hello World" ]; then
+ rm "$imgfile"
+ rm "$outfile"
+ exit 1
diff --git a/debian/patches/tpm-unknown-error-non-fatal.patch b/debian/patches/tpm-unknown-error-non-fatal.patch
new file mode 100644
index 0000000..5f3c3ee
--- /dev/null
+++ b/debian/patches/tpm-unknown-error-non-fatal.patch
@@ -0,0 +1,31 @@
+From ba3a0d4b6c0b56f6d7935911b53a02a7d0504da5 Mon Sep 17 00:00:00 2001
+From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
+Date: Sat, 10 Jul 2021 22:32:00 +0100
+Subject: tpm: Pass unknown error as non-fatal, but debug print the error we
+ got
+
+Signed-off-by: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
+
+Bug-Debian: https://bugs.debian.org/940911
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1848892
+Last-Update: 2021-09-24
+
+Patch-Name: tpm-unknown-error-non-fatal.patch
+---
+ grub-core/commands/efi/tpm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
+index a97d85368..e73bd5561 100644
+--- a/grub-core/commands/efi/tpm.c
++++ b/grub-core/commands/efi/tpm.c
+@@ -145,7 +145,8 @@ grub_efi_log_event_status (grub_efi_status_t status)
+ case GRUB_EFI_NOT_FOUND:
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
+ default:
+- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
++ grub_dprintf ("tpm", "Unknown TPM error: %" PRIdGRUB_SSIZE, status);
++ return 0;
+ }
+ }
+
diff --git a/debian/patches/uefi-secure-boot-cryptomount.patch b/debian/patches/uefi-secure-boot-cryptomount.patch
new file mode 100644
index 0000000..cbef39c
--- /dev/null
+++ b/debian/patches/uefi-secure-boot-cryptomount.patch
@@ -0,0 +1,48 @@
+From 7fd79864c87c57d586989d12c3d4a7e432b3d73a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Herv=C3=A9=20Werner?= <dud225@hotmail.com>
+Date: Mon, 28 Jan 2019 17:24:23 +0100
+Subject: Fix setup on Secure Boot systems where cryptodisk is in use
+
+On full-encrypted systems, including /boot, the current code omits
+cryptodisk commands needed to open the drives if Secure Boot is enabled.
+This prevents grub2 from reading any further configuration residing on
+the encrypted disk.
+This patch fixes this issue by adding the needed "cryptomount" commands in
+the load.cfg file that is then copied in the EFI partition.
+
+Bug-Debian: https://bugs.debian.org/917117
+Last-Update: 2019-02-10
+
+Patch-Name: uefi-secure-boot-cryptomount.patch
+---
+ util/grub-install.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index b51fe4710..58f1453ba 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1531,6 +1531,23 @@ main (int argc, char *argv[])
+ || uefi_secure_boot)
+ {
+ char *uuid = NULL;
++
++ if (uefi_secure_boot && config.is_cryptodisk_enabled)
++ {
++ if (grub_dev->disk)
++ probe_cryptodisk_uuid (grub_dev->disk);
++
++ for (curdrive = grub_drives + 1; *curdrive; curdrive++)
++ {
++ grub_device_t dev = grub_device_open (*curdrive);
++ if (!dev)
++ continue;
++ if (dev->disk)
++ probe_cryptodisk_uuid (dev->disk);
++ grub_device_close (dev);
++ }
++ }
++
+ /* generic method (used on coreboot and ata mod). */
+ if (!force_file_id
+ && grub_fs->fs_uuid && grub_fs->fs_uuid (grub_dev, &uuid))
diff --git a/debian/patches/vt-handoff.patch b/debian/patches/vt-handoff.patch
new file mode 100644
index 0000000..153c58d
--- /dev/null
+++ b/debian/patches/vt-handoff.patch
@@ -0,0 +1,101 @@
+From 4336395ce7d82827b466a0088e1b08d42ef24ae8 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:30 +0000
+Subject: Add configure option to use vt.handoff=7
+
+This is used for non-recovery Linux entries only; it enables
+flicker-free booting if gfxpayload=keep is in use and a suitable kernel
+is present.
+
+Author: Andy Whitcroft <apw@canonical.com>
+Forwarded: not-needed
+Last-Update: 2013-12-25
+
+Patch-Name: vt-handoff.patch
+---
+ configure.ac | 11 +++++++++++
+ util/grub.d/10_linux.in | 28 +++++++++++++++++++++++++++-
+ 2 files changed, 38 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 947fd529f..e11df6bc5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1948,6 +1948,17 @@ else
+ fi
+ AC_SUBST([GFXPAYLOAD_DYNAMIC])
+
++AC_ARG_ENABLE([vt-handoff],
++ [AS_HELP_STRING([--enable-vt-handoff],
++ [use Linux vt.handoff option for flicker-free booting (default=no)])],
++ [], [enable_vt_handoff=no])
++if test x"$enable_vt_handoff" = xyes ; then
++ VT_HANDOFF=1
++else
++ VT_HANDOFF=0
++fi
++AC_SUBST([VT_HANDOFF])
++
+ LIBS=""
+
+ AC_SUBST([FONT_SOURCE])
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index d46d7852b..64204c216 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -24,6 +24,7 @@ ubuntu_recovery="@UBUNTU_RECOVERY@"
+ quiet_boot="@QUIET_BOOT@"
+ quick_boot="@QUICK_BOOT@"
+ gfxpayload_dynamic="@GFXPAYLOAD_DYNAMIC@"
++vt_handoff="@VT_HANDOFF@"
+
+ . "$pkgdatadir/grub-mkconfig_lib"
+
+@@ -104,6 +105,14 @@ if [ "$ubuntu_recovery" = 1 ]; then
+ GRUB_CMDLINE_LINUX_RECOVERY="$GRUB_CMDLINE_LINUX_RECOVERY nomodeset"
+ fi
+
++if [ "$vt_handoff" = 1 ]; then
++ for word in $GRUB_CMDLINE_LINUX_DEFAULT; do
++ if [ "$word" = splash ]; then
++ GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT \$vt_handoff"
++ fi
++ done
++fi
++
+ linux_entry ()
+ {
+ os="$1"
+@@ -149,7 +158,7 @@ linux_entry ()
+ fi
+ if ([ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]) && \
+ ([ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 1 ]); then
+- echo " set gfxpayload=\$linux_gfx_mode" | sed "s/^/$submenu_indentation/"
++ echo " gfxmode \$linux_gfx_mode" | sed "s/^/$submenu_indentation/"
+ fi
+
+ echo " insmod gzio" | sed "s/^/$submenu_indentation/"
+@@ -228,6 +237,23 @@ prepare_root_cache=
+ boot_device_id=
+ title_correction_code=
+
++cat << 'EOF'
++function gfxmode {
++ set gfxpayload="${1}"
++EOF
++if [ "$vt_handoff" = 1 ]; then
++ cat << 'EOF'
++ if [ "${1}" = "keep" ]; then
++ set vt_handoff=vt.handoff=7
++ else
++ set vt_handoff=
++ fi
++EOF
++fi
++cat << EOF
++}
++EOF
++
+ # Use ELILO's generic "efifb" when it's known to be available.
+ # FIXME: We need an interface to select vesafb in case efifb can't be used.
+ if [ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 0 ]; then
diff --git a/debian/patches/wubi-no-windows.patch b/debian/patches/wubi-no-windows.patch
new file mode 100644
index 0000000..407d391
--- /dev/null
+++ b/debian/patches/wubi-no-windows.patch
@@ -0,0 +1,57 @@
+From f36695098443076b8eb12399c286136ac8ed50d3 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:24 +0000
+Subject: Skip Windows os-prober entries on Wubi systems
+
+Since we're already being booted from the Windows boot loader, including
+entries that take us back to it mostly just causes confusion, and stops
+us from being able to hide the menu if there are no other OSes
+installed.
+
+https://blueprints.launchpad.net/ubuntu/+spec/foundations-o-wubi
+
+Forwarded: not-needed
+Last-Update: 2013-11-26
+
+Patch-Name: wubi-no-windows.patch
+---
+ util/grub.d/30_os-prober.in | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index e2ec80eb9..98aee403e 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -113,6 +113,8 @@ EOF
+
+ used_osprober_linux_ids=
+
++wubi=
++
+ for OS in ${OSPROBED} ; do
+ DEVICE="`echo ${OS} | cut -d ':' -f 1`"
+ LONGNAME="`echo ${OS} | cut -d ':' -f 2 | tr '^' ' '`"
+@@ -149,6 +151,23 @@ for OS in ${OSPROBED} ; do
+ case ${BOOT} in
+ chain)
+
++ case ${LONGNAME} in
++ Windows*)
++ if [ -z "$wubi" ]; then
++ if [ -x /usr/share/lupin-support/grub-mkimage ] && \
++ /usr/share/lupin-support/grub-mkimage --test; then
++ wubi=yes
++ else
++ wubi=no
++ fi
++ fi
++ if [ "$wubi" = yes ]; then
++ echo "Skipping ${LONGNAME} on Wubi system" >&2
++ continue
++ fi
++ ;;
++ esac
++
+ onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+ cat << EOF
+ menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
diff --git a/debian/patches/xen-no-xsm-policy-in-non-xsm-options.patch b/debian/patches/xen-no-xsm-policy-in-non-xsm-options.patch
new file mode 100644
index 0000000..315bdab
--- /dev/null
+++ b/debian/patches/xen-no-xsm-policy-in-non-xsm-options.patch
@@ -0,0 +1,35 @@
+From 4d208a51f41c6df932805dfd681ad64a02c2c728 Mon Sep 17 00:00:00 2001
+From: Ian Jackson <ian.jackson@eu.citrix.com>
+Date: Wed, 27 May 2020 17:00:45 +0100
+Subject: 20_linux_xen: Do not load XSM policy in non-XSM options
+
+For complicated reasons, even if you have XSM/FLASK disabled (as is
+the default) the Xen build system still builds a policy file and puts
+it in /boot.
+
+Even so, we shouldn't be loading this in the usual non-"XSM enabled"
+entries. It doesn't do any particular harm but it is quite confusing.
+
+Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
+
+Bug-Debian: https://bugs.debian.org/961673
+Last-Update: 2020-05-29
+
+Patch-Name: xen-no-xsm-policy-in-non-xsm-options.patch
+---
+ util/grub.d/20_linux_xen.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index d99751a94..a12780ebe 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -173,7 +173,7 @@ EOF
+ ${module_loader} --nounzip $(echo $initrd_path)
+ EOF
+ fi
+- if test -n "${xenpolicy}" ; then
++ if ${xsm} && test -n "${xenpolicy}" ; then
+ message="$(gettext_printf "Loading XSM policy ...")"
+ sed "s/^/$submenu_indentation/" << EOF
+ echo '$(echo "$message" | grub_quote)'
diff --git a/debian/patches/xfs-fix-v4-superblock.patch b/debian/patches/xfs-fix-v4-superblock.patch
new file mode 100644
index 0000000..7bafc46
--- /dev/null
+++ b/debian/patches/xfs-fix-v4-superblock.patch
@@ -0,0 +1,122 @@
+From bf29fbd997292bbf6be2eec03594ec82f0899f57 Mon Sep 17 00:00:00 2001
+From: Erwan Velu <erwanaliasr1@gmail.com>
+Date: Wed, 25 Aug 2021 15:31:52 +0200
+Subject: 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 <e.velu@criteo.com>
+Tested-by: Carlos Maiolino <cmaiolino@redhat.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+
+Origin: upstream, https://git.savannah.gnu.org/cgit/grub.git/commit/?id=a4b495520e4dc41a896a8b916a64eda9970c50ea
+Last-Update: 2021-09-24
+
+Patch-Name: xfs-fix-v4-superblock.patch
+---
+ grub-core/fs/xfs.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
+index 0f524c3a8..e3816d1ec 100644
+--- a/grub-core/fs/xfs.c
++++ b/grub-core/fs/xfs.c
+@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy
+ grub_uint32_t nanosec;
+ } GRUB_PACKED;
+
++/*
++ * The struct grub_xfs_inode layout was taken from the
++ * struct xfs_dinode_core which is described here:
++ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
++ */
+ struct grub_xfs_inode
+ {
+ grub_uint8_t magic[2];
+@@ -208,14 +213,15 @@ struct grub_xfs_inode
+ grub_uint32_t nextents;
+ grub_uint16_t unused3;
+ grub_uint8_t fork_offset;
+- grub_uint8_t unused4[37];
++ grub_uint8_t unused4[17]; /* Last member of inode v2. */
++ grub_uint8_t unused5[20]; /* First member of inode v3. */
+ grub_uint64_t flags2;
+- grub_uint8_t unused5[48];
++ grub_uint8_t unused6[48]; /* Last member of inode v3. */
+ } GRUB_PACKED;
+
+ #define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode)
+-/* Size of struct grub_xfs_inode until fork_offset (included). */
+-#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92)
++/* Size of struct grub_xfs_inode v2, up to unused4 member included. */
++#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76)
+
+ struct grub_xfs_dirblock_tail
+ {
diff --git a/debian/patches/zpool-full-device-name.patch b/debian/patches/zpool-full-device-name.patch
new file mode 100644
index 0000000..4f6ce65
--- /dev/null
+++ b/debian/patches/zpool-full-device-name.patch
@@ -0,0 +1,33 @@
+From be244ee23f3b12266a5671486af814c57c616a6c Mon Sep 17 00:00:00 2001
+From: Chad MILLER <chad.miller@canonical.com>
+Date: Thu, 27 Oct 2016 17:15:07 -0400
+Subject: Tell zpool to emit full device names
+
+zfs-initramfs currently provides extraneous, undesired symlinks to
+devices directly underneath /dev/ to satisfy zpool's historical output
+of unqualified device names. By including this environment variable to
+signal our intent to zpool, zfs-linux packages can drop the symlink
+behavior when updating to its upstream or backported output behavior.
+
+Bug: https://savannah.gnu.org/bugs/?43653
+Bug-Debian: https://bugs.debian.org/824974
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1527727
+Last-Update: 2016-11-01
+
+Patch-Name: zpool-full-device-name.patch
+---
+ grub-core/osdep/unix/getroot.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c
+index 46d7116c6..da102918d 100644
+--- a/grub-core/osdep/unix/getroot.c
++++ b/grub-core/osdep/unix/getroot.c
+@@ -243,6 +243,7 @@ grub_util_find_root_devices_from_poolname (char *poolname)
+ argv[2] = poolname;
+ argv[3] = NULL;
+
++ setenv ("ZPOOL_VDEV_NAME_PATH", "YES", 1);
+ pid = grub_util_exec_pipe (argv, &fd);
+ if (!pid)
+ return NULL;