a9bbe0
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
a9bbe0
From: Zhang Boyang <zhangboyang.id@gmail.com>
a9bbe0
Date: Tue, 6 Sep 2022 03:03:21 +0800
a9bbe0
Subject: [PATCH] fbutil: Fix integer overflow
a9bbe0
a9bbe0
Expressions like u64 = u32 * u32 are unsafe because their products are
a9bbe0
truncated to u32 even if left hand side is u64. This patch fixes all
a9bbe0
problems like that one in fbutil.
a9bbe0
a9bbe0
To get right result not only left hand side have to be u64 but it's also
a9bbe0
necessary to cast at least one of the operands of all leaf operators of
a9bbe0
right hand side to u64, e.g. u64 = u32 * u32 + u32 * u32 should be
a9bbe0
u64 = (u64)u32 * u32 + (u64)u32 * u32.
a9bbe0
a9bbe0
For 1-bit bitmaps grub_uint64_t have to be used. It's safe because any
a9bbe0
combination of values in (grub_uint64_t)u32 * u32 + u32 expression will
a9bbe0
not overflow grub_uint64_t.
a9bbe0
a9bbe0
Other expressions like ptr + u32 * u32 + u32 * u32 are also vulnerable.
a9bbe0
They should be ptr + (grub_addr_t)u32 * u32 + (grub_addr_t)u32 * u32.
a9bbe0
a9bbe0
This patch also adds a comment to grub_video_fb_get_video_ptr() which
a9bbe0
says it's arguments must be valid and no sanity check is performed
a9bbe0
(like its siblings in grub-core/video/fb/fbutil.c).
a9bbe0
a9bbe0
Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
a9bbe0
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
a9bbe0
(cherry picked from commit 50a11a81bc842c58962244a2dc86bbd31a426e12)
a9bbe0
(cherry picked from commit 8fa75d647362c938c4cc302cf5945b31fb92c078)
a9bbe0
(cherry picked from commit 91005e39b3c8b6ca8dcc84ecb19ac9328966aaea)
a9bbe0
---
a9bbe0
 grub-core/video/fb/fbutil.c |  4 ++--
a9bbe0
 include/grub/fbutil.h       | 13 +++++++++----
a9bbe0
 2 files changed, 11 insertions(+), 6 deletions(-)
a9bbe0
a9bbe0
diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c
a9bbe0
index b98bb51fe8..25ef39f47d 100644
a9bbe0
--- a/grub-core/video/fb/fbutil.c
a9bbe0
+++ b/grub-core/video/fb/fbutil.c
a9bbe0
@@ -67,7 +67,7 @@ get_pixel (struct grub_video_fbblit_info *source,
a9bbe0
     case 1:
a9bbe0
       if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
a9bbe0
         {
a9bbe0
-          int bit_index = y * source->mode_info->width + x;
a9bbe0
+          grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
a9bbe0
           grub_uint8_t *ptr = source->data + bit_index / 8;
a9bbe0
           int bit_pos = 7 - bit_index % 8;
a9bbe0
           color = (*ptr >> bit_pos) & 0x01;
a9bbe0
@@ -138,7 +138,7 @@ set_pixel (struct grub_video_fbblit_info *source,
a9bbe0
     case 1:
a9bbe0
       if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
a9bbe0
         {
a9bbe0
-          int bit_index = y * source->mode_info->width + x;
a9bbe0
+          grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
a9bbe0
           grub_uint8_t *ptr = source->data + bit_index / 8;
a9bbe0
           int bit_pos = 7 - bit_index % 8;
a9bbe0
           *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos);
a9bbe0
diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h
a9bbe0
index 4205eb917f..78a1ab3b45 100644
a9bbe0
--- a/include/grub/fbutil.h
a9bbe0
+++ b/include/grub/fbutil.h
a9bbe0
@@ -31,14 +31,19 @@ struct grub_video_fbblit_info
a9bbe0
   grub_uint8_t *data;
a9bbe0
 };
a9bbe0
 
a9bbe0
-/* Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
a9bbe0
-   and it doesn't make sense, in general, to ask for a pointer
a9bbe0
-   to a particular pixel's data.  */
a9bbe0
+/*
a9bbe0
+ * Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
a9bbe0
+ * and it doesn't make sense, in general, to ask for a pointer
a9bbe0
+ * to a particular pixel's data.
a9bbe0
+ *
a9bbe0
+ * This function assumes that bounds checking has been done in previous phase
a9bbe0
+ * and they are opted out in here.
a9bbe0
+ */
a9bbe0
 static inline void *
a9bbe0
 grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source,
a9bbe0
               unsigned int x, unsigned int y)
a9bbe0
 {
a9bbe0
-  return source->data + y * source->mode_info->pitch + x * source->mode_info->bytes_per_pixel;
a9bbe0
+  return source->data + (grub_addr_t) y * source->mode_info->pitch + (grub_addr_t) x * source->mode_info->bytes_per_pixel;
a9bbe0
 }
a9bbe0
 
a9bbe0
 /* Advance pointer by VAL bytes. If there is no unaligned access available,