blob: efa00a3c6caf9ac0cdfd81f1bf61d7aa48542b51 [file] [log] [blame]
Andrew Geissler517393d2023-01-13 08:55:19 -06001From 1f511ae054fe42dce7aedfbfe0f234fa1e0a7a3e Mon Sep 17 00:00:00 2001
2From: Zhang Boyang <zhangboyang.id@gmail.com>
3Date: Fri, 5 Aug 2022 00:51:20 +0800
4Subject: [PATCH] font: Fix size overflow in grub_font_get_glyph_internal()
5
6The length of memory allocation and file read may overflow. This patch
7fixes the problem by using safemath macros.
8
9There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe
10if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz().
11It is safe replacement for such code. It has safemath-like prototype.
12
13This patch also introduces grub_cast(value, pointer), it casts value to
14typeof(*pointer) then store the value to *pointer. It returns true when
15overflow occurs or false if there is no overflow. The semantics of arguments
16and return value are designed to be consistent with other safemath macros.
17
18Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
19Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
20
21Upstream-Status: Backport from
22[https://git.savannah.gnu.org/cgit/grub.git/commit/?id=9c76ec09ae08155df27cd237eaea150b4f02f532]
23
24Signed-off-by: Xiangyu Chen <xiangyu.chen@windriver.com>
25
26---
27 grub-core/font/font.c | 17 +++++++++++++----
28 include/grub/bitmap.h | 18 ++++++++++++++++++
29 include/grub/safemath.h | 2 ++
30 3 files changed, 33 insertions(+), 4 deletions(-)
31
32diff --git a/grub-core/font/font.c b/grub-core/font/font.c
33index d09bb38..876b5b6 100644
34--- a/grub-core/font/font.c
35+++ b/grub-core/font/font.c
36@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
37 grub_int16_t xoff;
38 grub_int16_t yoff;
39 grub_int16_t dwidth;
40- int len;
41+ grub_ssize_t len;
42+ grub_size_t sz;
43
44 if (index_entry->glyph)
45 /* Return cached glyph. */
46@@ -766,9 +767,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
47 return 0;
48 }
49
50- len = (width * height + 7) / 8;
51- glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
52- if (!glyph)
53+ /* Calculate real struct size of current glyph. */
54+ if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) ||
55+ grub_add (sizeof (struct grub_font_glyph), len, &sz))
56+ {
57+ remove_font (font);
58+ return 0;
59+ }
60+
61+ /* Allocate and initialize the glyph struct. */
62+ glyph = grub_malloc (sz);
63+ if (glyph == NULL)
64 {
65 remove_font (font);
66 return 0;
67diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h
68index 5728f8c..0d9603f 100644
69--- a/include/grub/bitmap.h
70+++ b/include/grub/bitmap.h
71@@ -23,6 +23,7 @@
72 #include <grub/symbol.h>
73 #include <grub/types.h>
74 #include <grub/video.h>
75+#include <grub/safemath.h>
76
77 struct grub_video_bitmap
78 {
79@@ -79,6 +80,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap)
80 return bitmap->mode_info.height;
81 }
82
83+/*
84+ * Calculate and store the size of data buffer of 1bit bitmap in result.
85+ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs.
86+ * Return true when overflow occurs or false if there is no overflow.
87+ * This function is intentionally implemented as a macro instead of
88+ * an inline function. Although a bit awkward, it preserves data types for
89+ * safemath macros and reduces macro side effects as much as possible.
90+ *
91+ * XXX: Will report false overflow if width * height > UINT64_MAX.
92+ */
93+#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \
94+({ \
95+ grub_uint64_t _bitmap_pixels; \
96+ grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \
97+ grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \
98+})
99+
100 void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap,
101 struct grub_video_mode_info *mode_info);
102
103diff --git a/include/grub/safemath.h b/include/grub/safemath.h
104index c17b89b..bb0f826 100644
105--- a/include/grub/safemath.h
106+++ b/include/grub/safemath.h
107@@ -30,6 +30,8 @@
108 #define grub_sub(a, b, res) __builtin_sub_overflow(a, b, res)
109 #define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res)
110
111+#define grub_cast(a, res) grub_add ((a), 0, (res))
112+
113 #else
114 #error gcc 5.1 or newer or clang 3.8 or newer is required
115 #endif