Blame SOURCES/0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch

a46852
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
a46852
From: Zhang Boyang <zhangboyang.id@gmail.com>
a46852
Date: Fri, 5 Aug 2022 00:51:20 +0800
a46852
Subject: [PATCH] font: Fix size overflow in grub_font_get_glyph_internal()
a46852
a46852
The length of memory allocation and file read may overflow. This patch
a46852
fixes the problem by using safemath macros.
a46852
a46852
There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe
a46852
if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz().
a46852
It is safe replacement for such code. It has safemath-like prototype.
a46852
a46852
This patch also introduces grub_cast(value, pointer), it casts value to
a46852
typeof(*pointer) then store the value to *pointer. It returns true when
a46852
overflow occurs or false if there is no overflow. The semantics of arguments
a46852
and return value are designed to be consistent with other safemath macros.
a46852
a46852
Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
a46852
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
a46852
(cherry picked from commit 941d10ad6f1dcbd12fb613002249e29ba035f985)
a46852
(cherry picked from commit 6bca9693878bdf61dd62b8c784862a48e75f569a)
a46852
---
a46852
 grub-core/font/font.c   | 17 +++++++++++++----
a46852
 include/grub/bitmap.h   | 18 ++++++++++++++++++
a46852
 include/grub/safemath.h |  2 ++
a46852
 3 files changed, 33 insertions(+), 4 deletions(-)
a46852
a46852
diff --git a/grub-core/font/font.c b/grub-core/font/font.c
a46852
index 2f09a4a55b..6a3fbebbd8 100644
a46852
--- a/grub-core/font/font.c
a46852
+++ b/grub-core/font/font.c
a46852
@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
a46852
       grub_int16_t xoff;
a46852
       grub_int16_t yoff;
a46852
       grub_int16_t dwidth;
a46852
-      int len;
a46852
+      grub_ssize_t len;
a46852
+      grub_size_t sz;
a46852
 
a46852
       if (index_entry->glyph)
a46852
 	/* Return cached glyph.  */
a46852
@@ -768,9 +769,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
a46852
 	  return 0;
a46852
 	}
a46852
 
a46852
-      len = (width * height + 7) / 8;
a46852
-      glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
a46852
-      if (!glyph)
a46852
+      /* Calculate real struct size of current glyph. */
a46852
+      if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) ||
a46852
+	  grub_add (sizeof (struct grub_font_glyph), len, &sz))
a46852
+	{
a46852
+	  remove_font (font);
a46852
+	  return 0;
a46852
+	}
a46852
+
a46852
+      /* Allocate and initialize the glyph struct. */
a46852
+      glyph = grub_malloc (sz);
a46852
+      if (glyph == NULL)
a46852
 	{
a46852
 	  remove_font (font);
a46852
 	  return 0;
a46852
diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h
a46852
index 5728f8ca3a..0d9603f619 100644
a46852
--- a/include/grub/bitmap.h
a46852
+++ b/include/grub/bitmap.h
a46852
@@ -23,6 +23,7 @@
a46852
 #include <grub/symbol.h>
a46852
 #include <grub/types.h>
a46852
 #include <grub/video.h>
a46852
+#include <grub/safemath.h>
a46852
 
a46852
 struct grub_video_bitmap
a46852
 {
a46852
@@ -79,6 +80,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap)
a46852
   return bitmap->mode_info.height;
a46852
 }
a46852
 
a46852
+/*
a46852
+ * Calculate and store the size of data buffer of 1bit bitmap in result.
a46852
+ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs.
a46852
+ * Return true when overflow occurs or false if there is no overflow.
a46852
+ * This function is intentionally implemented as a macro instead of
a46852
+ * an inline function. Although a bit awkward, it preserves data types for
a46852
+ * safemath macros and reduces macro side effects as much as possible.
a46852
+ *
a46852
+ * XXX: Will report false overflow if width * height > UINT64_MAX.
a46852
+ */
a46852
+#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \
a46852
+({ \
a46852
+  grub_uint64_t _bitmap_pixels; \
a46852
+  grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \
a46852
+    grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \
a46852
+})
a46852
+
a46852
 void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap,
a46852
 						    struct grub_video_mode_info *mode_info);
a46852
 
a46852
diff --git a/include/grub/safemath.h b/include/grub/safemath.h
a46852
index c17b89bba1..bb0f826de1 100644
a46852
--- a/include/grub/safemath.h
a46852
+++ b/include/grub/safemath.h
a46852
@@ -30,6 +30,8 @@
a46852
 #define grub_sub(a, b, res)	__builtin_sub_overflow(a, b, res)
a46852
 #define grub_mul(a, b, res)	__builtin_mul_overflow(a, b, res)
a46852
 
a46852
+#define grub_cast(a, res)	grub_add ((a), 0, (res))
a46852
+
a46852
 #else
a46852
 #error gcc 5.1 or newer or clang 3.8 or newer is required
a46852
 #endif