]> git.proxmox.com Git - grub2.git/commitdiff
Security updates
authorJulian Andres Klode <julian.klode@canonical.com>
Fri, 10 Jun 2022 08:30:55 +0000 (10:30 +0200)
committerJulian Andres Klode <julian.klode@canonical.com>
Fri, 10 Jun 2022 08:43:34 +0000 (10:43 +0200)
33 files changed:
debian/.git-dpm
debian/changelog
debian/patches/0063-loader-efi-chainloader-Simplify-the-loader-state.patch [new file with mode: 0644]
debian/patches/0064-commands-boot-Add-API-to-pass-context-to-loader.patch [new file with mode: 0644]
debian/patches/0065-loader-efi-chainloader-Use-grub_loader_set_ex.patch [new file with mode: 0644]
debian/patches/0066-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch [new file with mode: 0644]
debian/patches/0067-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch [new file with mode: 0644]
debian/patches/0068-video-readers-png-Abort-sooner-if-a-read-operation-f.patch [new file with mode: 0644]
debian/patches/0069-video-readers-png-Refuse-to-handle-multiple-image-he.patch [new file with mode: 0644]
debian/patches/0070-video-readers-png-Drop-greyscale-support-to-fix-heap.patch [new file with mode: 0644]
debian/patches/0071-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch [new file with mode: 0644]
debian/patches/0072-video-readers-png-Sanity-check-some-huffman-codes.patch [new file with mode: 0644]
debian/patches/0073-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch [new file with mode: 0644]
debian/patches/0074-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch [new file with mode: 0644]
debian/patches/0075-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch [new file with mode: 0644]
debian/patches/0076-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch [new file with mode: 0644]
debian/patches/0077-normal-charset-Fix-array-out-of-bounds-formatting-un.patch [new file with mode: 0644]
debian/patches/0078-net-netbuff-Block-overly-large-netbuff-allocs.patch [new file with mode: 0644]
debian/patches/0079-net-ip-Do-IP-fragment-maths-safely.patch [new file with mode: 0644]
debian/patches/0080-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch [new file with mode: 0644]
debian/patches/0081-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch [new file with mode: 0644]
debian/patches/0082-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch [new file with mode: 0644]
debian/patches/0083-net-tftp-Avoid-a-trivial-UAF.patch [new file with mode: 0644]
debian/patches/0084-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch [new file with mode: 0644]
debian/patches/0085-net-http-Fix-OOB-write-for-split-http-headers.patch [new file with mode: 0644]
debian/patches/0086-net-http-Error-out-on-headers-with-LF-without-CR.patch [new file with mode: 0644]
debian/patches/0087-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch [new file with mode: 0644]
debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch [new file with mode: 0644]
debian/patches/0089-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch [new file with mode: 0644]
debian/patches/0090-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch [new file with mode: 0644]
debian/patches/0091-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch [new file with mode: 0644]
debian/patches/0092-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch [new file with mode: 0644]
debian/patches/series

index 28b6c1eeaeb71bec4647fd79dc453a4ac85f8b62..8f101b7ecc6dbdd6f97a6eef05322a1fc262d2ca 100644 (file)
@@ -1,5 +1,5 @@
 # see git-dpm(1) from git-dpm package
-dbcbb3e5b9fac665b92d630eb24de7bd8c43652e
+589500ad3777d1335c8e5cb139f7c0c6089112a8
 589500ad3777d1335c8e5cb139f7c0c6089112a8
 21f954425ffe2a934b6b26c0c948d340c91a16bb
 21f954425ffe2a934b6b26c0c948d340c91a16bb
index 4b71dbb37abbd2d8964a51bb98df64aa6fd71898..0e421988f1a5cfb3f2282c02d3cd60114fb0ce54 100644 (file)
@@ -20,8 +20,89 @@ grub2 (2.06-3) UNRELEASED; urgency=medium
   * 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
 
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 (file)
index 0000000..51a7b68
--- /dev/null
@@ -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 (file)
index 0000000..47caba2
--- /dev/null
@@ -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 (file)
index 0000000..4a4a0e7
--- /dev/null
@@ -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 (file)
index 0000000..18ecc25
--- /dev/null
@@ -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 (file)
index 0000000..d319507
--- /dev/null
@@ -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 (file)
index 0000000..58e6e50
--- /dev/null
@@ -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 (file)
index 0000000..1c0aba1
--- /dev/null
@@ -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 (file)
index 0000000..08c33f8
--- /dev/null
@@ -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 (file)
index 0000000..7f73935
--- /dev/null
@@ -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 (file)
index 0000000..b355584
--- /dev/null
@@ -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 (file)
index 0000000..1f5b558
--- /dev/null
@@ -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 (file)
index 0000000..c4228f9
--- /dev/null
@@ -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 (file)
index 0000000..07fd802
--- /dev/null
@@ -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 (file)
index 0000000..b292cbc
--- /dev/null
@@ -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 (file)
index 0000000..066775a
--- /dev/null
@@ -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 (file)
index 0000000..150f101
--- /dev/null
@@ -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 (file)
index 0000000..7c5d8dc
--- /dev/null
@@ -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 (file)
index 0000000..0f3cdc7
--- /dev/null
@@ -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 (file)
index 0000000..0fc28a9
--- /dev/null
@@ -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 (file)
index 0000000..bb4cd8c
--- /dev/null
@@ -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 (file)
index 0000000..8e42215
--- /dev/null
@@ -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 (file)
index 0000000..763e46a
--- /dev/null
@@ -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 (file)
index 0000000..3b6ff59
--- /dev/null
@@ -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 (file)
index 0000000..5b7ede1
--- /dev/null
@@ -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 (file)
index 0000000..6561abd
--- /dev/null
@@ -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 (file)
index 0000000..5f06bd4
--- /dev/null
@@ -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 (file)
index 0000000..cf71b38
--- /dev/null
@@ -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 (file)
index 0000000..d02cbe2
--- /dev/null
@@ -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 (file)
index 0000000..4ae22c9
--- /dev/null
@@ -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 (file)
index 0000000..30c2dad
--- /dev/null
@@ -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,
index acc1c680924cc3c5cf958bd67677cbced2276e7d..66a1bd4040e64837eaa0a3ff47a82989300a806e 100644 (file)
@@ -60,3 +60,33 @@ 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