|
|
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,
|