# see git-dpm(1) from git-dpm package
-dbcbb3e5b9fac665b92d630eb24de7bd8c43652e
+589500ad3777d1335c8e5cb139f7c0c6089112a8
589500ad3777d1335c8e5cb139f7c0c6089112a8
21f954425ffe2a934b6b26c0c948d340c91a16bb
21f954425ffe2a934b6b26c0c948d340c91a16bb
* Add Julian Andres Klode to uploaders
* Disable building with LTO, as used in Ubuntu and possibly other
downstreams (maybe Debian one day), as that breaks the build.
-
- -- Colin Watson <cjwatson@debian.org> Wed, 01 Dec 2021 13:17:18 +0000
+ * SECURITY UPDATE: Crafted PNG grayscale images may lead to out-of-bounds
+ write in heap.
+ - 0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch:
+ video/readers/png: Drop greyscale support to fix heap out-of-bounds write
+ - CVE-2021-3695
+ * SECURITY UPDATE: Crafted PNG image may lead to out-of-bound write during
+ huffman table handling.
+ - 0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch:
+ video/readers/png: Avoid heap OOB R/W inserting huff table items
+ - CVE-2021-3696
+ * SECURITY UPDATE: Crafted JPEG image can lead to buffer underflow write in
+ the heap.
+ - 0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch:
+ video/readers/jpeg: Block int underflow -> wild pointer write
+ - CVE-2021-3697
+ * SECURITY UPDATE: Integer underflow in grub_net_recv_ip4_packets
+ - 0079-net-ip-Do-IP-fragment-maths-safely.patch: net/ip: Do IP fragment
+ maths safely
+ - CVE-2022-28733
+ * SECURITY UPDATE: Out-of-bounds write when handling split HTTP headers
+ - 0085-net-http-Fix-OOB-write-for-split-http-headers.patch: net/http: Fix
+ OOB write for split http headers
+ - CVE-2022-28734
+ * SECURITY UPDATE: shim_lock verifier allows non-kernel files to be loaded
+ - 0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch:
+ kern/efi/sb: Reject non-kernel files in the shim_lock verifier
+ - CVE-2022-28735
+ - Closes: #1001057
+ * SECURITY UPDATE: use-after-free in grub_cmd_chainloader()
+ - 0063-loader-efi-chainloader-Simplify-the-loader-state.patch:
+ loader/efi/chainloader: simplify the loader state
+ - 0064-commands-boot-Add-API-to-pass-context-to-loader.patch: commands/boot:
+ Add API to pass context to loader
+ - 0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch:
+ loader/efi/chainloader: Use grub_loader_set_ex
+ - 0066-loader-i386-efi-linux-Use-grub_loader_set_ex.patch:
+ loader/i386/efi/linux: Use grub_loader_set_ex
+ * Various fixes as a result of fuzzing and static analysis:
+ - 0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch:
+ kern/file: Do not leak device_name on error in grub_file_open()
+ - 0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch:
+ video/readers/png: Abort sooner if a read operation fails
+ - 0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch:
+ video/readers/png: Refuse to handle multiple image headers
+ - 0072-video-readers-png-Sanity-check-some-huffman-codes.patch:
+ video/readers/png: Sanity check some huffman codes
+ - 0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch:
+ video/readers/jpeg: Abort sooner if a read operation fails
+ - 0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch:
+ video/readers/jpeg: Do not reallocate a given huff table
+ - 0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch:
+ video/readers/jpeg: Refuse to handle multiple start of streams
+ - 0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch:
+ normal/charset: Fix array out-of-bounds formatting unicode for display
+ - 0078-net-netbuff-Block-overly-large-netbuff-allocs.patch:
+ net/netbuff: Block overly large netbuff allocs
+ - 0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch:
+ net/dns: Fix double-free addresses on corrupt DNS response
+ - 0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch:
+ net/dns: Don't read past the end of the string we're checking against
+ - 0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch:
+ net/tftp: Prevent a UAF and double-free from a failed seek
+ - 0083-net-tftp-Avoid-a-trivial-UAF.patch: net/tftp: Avoid a trivial UAF
+ - 0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch:
+ net/http: Do not tear down socket if it's already been torn down
+ - 0086-net-http-Error-out-on-headers-with-LF-without-CR.patch:
+ net/http: Error out on headers with LF without CR
+ - 0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch:
+ fs/f2fs: Do not read past the end of nat journal entries
+ - 0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch:
+ fs/f2fs: Do not read past the end of nat bitmap
+ - 0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch:
+ fs/f2fs: Do not copy file names that are too long
+ - 0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch:
+ fs/btrfs: Fix several fuzz issues with invalid dir item sizing
+ - 0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch:
+ fs/btrfs: Fix more ASAN and SEGV issues found with fuzzing
+ - 0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch:
+ fs/btrfs: Fix more fuzz issues related to chunks
+ * Bump SBAT generation:
+ - update debian/sbat.debian.csv.in
+
+ -- Julian Andres Klode <jak@debian.org> Fri, 10 Jun 2022 10:30:55 +0200
grub2 (2.06-2) unstable; urgency=medium
--- /dev/null
+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;
--- /dev/null
+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);
+
--- /dev/null
+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);
+
--- /dev/null
+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. */
--- /dev/null
+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);
+
--- /dev/null
+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)
--- /dev/null
+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);
+
--- /dev/null
+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. */
--- /dev/null
+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];
+
--- /dev/null
+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]);
--- /dev/null
+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;
+
--- /dev/null
+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;
--- /dev/null
+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)
--- /dev/null
+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)
+ {
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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)
+ {
--- /dev/null
+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"));
+ }
+
--- /dev/null
+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;
--- /dev/null
+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);
--- /dev/null
+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);
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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)
+ {
--- /dev/null
+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;
+
--- /dev/null
+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)
--- /dev/null
+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;
--- /dev/null
+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));
--- /dev/null
+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,
--- /dev/null
+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,
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