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