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

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