buildroot/boot/grub2/0006-malloc-Use-overflow-checking-primitives-where-we-do-.patch
Stefan Sørensen 2f7a8021b5 boot/grub2: Backport Boothole securify fixes
Details: https://lists.gnu.org/archive/html/grub-devel/2020-07/msg00034.html

Fixes the following security issues:

 * CVE-2020-10713
   A flaw was found in grub2, prior to version 2.06. An attacker may
   use the GRUB 2 flaw to hijack and tamper the GRUB verification
   process. This flaw also allows the bypass of Secure Boot
   protections. In order to load an untrusted or modified kernel, an
   attacker would first need to establish access to the system such as
   gaining physical access, obtain the ability to alter a pxe-boot
   network, or have remote access to a networked system with root
   access. With this access, an attacker could then craft a string to
   cause a buffer overflow by injecting a malicious payload that leads
   to arbitrary code execution within GRUB. The highest threat from
   this vulnerability is to data confidentiality and integrity as well
   as system availability.

 * CVE-2020-14308
   In grub2 versions before 2.06 the grub memory allocator doesn't
   check for possible arithmetic overflows on the requested allocation
   size. This leads the function to return invalid memory allocations
   which can be further used to cause possible integrity,
   confidentiality and availability impacts during the boot process.

 * CVE-2020-14309
   There's an issue with grub2 in all versions before 2.06 when
   handling squashfs filesystems containing a symbolic link with name
   length of UINT32 bytes in size. The name size leads to an
   arithmetic overflow leading to a zero-size allocation further
   causing a heap-based buffer overflow with attacker controlled data.

 * CVE-2020-14310
   An integer overflow in read_section_from_string may lead to a heap
   based buffer overflow.

 * CVE-2020-14311
   An integer overflow in grub_ext2_read_link may lead to a heap-based
   buffer overflow.

 * CVE-2020-15706
   GRUB2 contains a race condition in grub_script_function_create()
   leading to a use-after-free vulnerability which can be triggered by
   redefining a function whilst the same function is already
   executing, leading to arbitrary code execution and secure boot
   restriction bypass

 * CVE-2020-15707
   Integer overflows were discovered in the functions grub_cmd_initrd
   and grub_initrd_init in the efilinux component of GRUB2, as shipped
   in Debian, Red Hat, and Ubuntu (the functionality is not included
   in GRUB2 upstream), leading to a heap-based buffer overflow. These
   could be triggered by an extremely large number of arguments to the
   initrd command on 32-bit architectures, or a crafted filesystem
   with very large files on any architecture. An attacker could use
   this to execute arbitrary code and bypass UEFI Secure Boot
   restrictions. This issue affects GRUB2 version 2.04 and prior
   versions.

Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
2020-08-03 13:38:49 +02:00

1327 lines
37 KiB
Diff

From 4ad7e85adc3803788d65707a9db11fd681aebe4a Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 15 Jun 2020 12:28:27 -0400
Subject: [PATCH] malloc: Use overflow checking primitives where we do
complex allocations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This attempts to fix the places where we do the following where
arithmetic_expr may include unvalidated data:
X = grub_malloc(arithmetic_expr);
It accomplishes this by doing the arithmetic ahead of time using grub_add(),
grub_sub(), grub_mul() and testing for overflow before proceeding.
Among other issues, this fixes:
- allocation of integer overflow in grub_video_bitmap_create()
reported by Chris Coulson,
- allocation of integer overflow in grub_png_decode_image_header()
reported by Chris Coulson,
- allocation of integer overflow in grub_squash_read_symlink()
reported by Chris Coulson,
- allocation of integer overflow in grub_ext2_read_symlink()
reported by Chris Coulson,
- allocation of integer overflow in read_section_as_string()
reported by Chris Coulson.
Fixes: CVE-2020-14309, CVE-2020-14310, CVE-2020-14311
Signed-off-by: Peter Jones <pjones@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
---
grub-core/commands/legacycfg.c | 29 +++++++++++++++----
grub-core/commands/wildcard.c | 36 ++++++++++++++++++++----
grub-core/disk/ldm.c | 32 +++++++++++++++------
grub-core/font/font.c | 7 ++++-
grub-core/fs/btrfs.c | 28 +++++++++++++------
grub-core/fs/ext2.c | 10 ++++++-
grub-core/fs/iso9660.c | 51 ++++++++++++++++++++++++----------
grub-core/fs/sfs.c | 27 ++++++++++++++----
grub-core/fs/squash4.c | 45 ++++++++++++++++++++++--------
grub-core/fs/udf.c | 41 +++++++++++++++++----------
grub-core/fs/xfs.c | 11 +++++---
grub-core/fs/zfs/zfs.c | 22 ++++++++++-----
grub-core/fs/zfs/zfscrypt.c | 7 ++++-
grub-core/lib/arg.c | 20 +++++++++++--
grub-core/loader/i386/bsd.c | 8 +++++-
grub-core/net/dns.c | 9 +++++-
grub-core/normal/charset.c | 10 +++++--
grub-core/normal/cmdline.c | 14 ++++++++--
grub-core/normal/menu_entry.c | 13 +++++++--
grub-core/script/argv.c | 16 +++++++++--
grub-core/script/lexer.c | 21 ++++++++++++--
grub-core/video/bitmap.c | 25 +++++++++++------
grub-core/video/readers/png.c | 13 +++++++--
23 files changed, 382 insertions(+), 113 deletions(-)
diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c
index 5e3ec0d5e..cc5971f4d 100644
--- a/grub-core/commands/legacycfg.c
+++ b/grub-core/commands/legacycfg.c
@@ -32,6 +32,7 @@
#include <grub/auth.h>
#include <grub/disk.h>
#include <grub/partition.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -104,13 +105,22 @@ legacy_file (const char *filename)
if (newsuffix)
{
char *t;
-
+ grub_size_t sz;
+
+ if (grub_add (grub_strlen (suffix), grub_strlen (newsuffix), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ goto fail_0;
+ }
+
t = suffix;
- suffix = grub_realloc (suffix, grub_strlen (suffix)
- + grub_strlen (newsuffix) + 1);
+ suffix = grub_realloc (suffix, sz);
if (!suffix)
{
grub_free (t);
+
+ fail_0:
grub_free (entrysrc);
grub_free (parsed);
grub_free (newsuffix);
@@ -154,13 +164,22 @@ legacy_file (const char *filename)
else
{
char *t;
+ grub_size_t sz;
+
+ if (grub_add (grub_strlen (entrysrc), grub_strlen (parsed), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ goto fail_1;
+ }
t = entrysrc;
- entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc)
- + grub_strlen (parsed) + 1);
+ entrysrc = grub_realloc (entrysrc, sz);
if (!entrysrc)
{
grub_free (t);
+
+ fail_1:
grub_free (parsed);
grub_free (suffix);
return grub_errno;
diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c
index 4a106ca04..cc3290311 100644
--- a/grub-core/commands/wildcard.c
+++ b/grub-core/commands/wildcard.c
@@ -23,6 +23,7 @@
#include <grub/file.h>
#include <grub/device.h>
#include <grub/script_sh.h>
+#include <grub/safemath.h>
#include <regex.h>
@@ -48,6 +49,7 @@ merge (char **dest, char **ps)
int i;
int j;
char **p;
+ grub_size_t sz;
if (! dest)
return ps;
@@ -60,7 +62,12 @@ merge (char **dest, char **ps)
for (j = 0; ps[j]; j++)
;
- p = grub_realloc (dest, sizeof (char*) * (i + j + 1));
+ if (grub_add (i, j, &sz) ||
+ grub_add (sz, 1, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ return dest;
+
+ p = grub_realloc (dest, sz);
if (! p)
{
grub_free (dest);
@@ -115,8 +122,15 @@ make_regex (const char *start, const char *end, regex_t *regexp)
char ch;
int i = 0;
unsigned len = end - start;
- char *buffer = grub_malloc (len * 2 + 2 + 1); /* worst case size. */
+ char *buffer;
+ grub_size_t sz;
+ /* Worst case size is (len * 2 + 2 + 1). */
+ if (grub_mul (len, 2, &sz) ||
+ grub_add (sz, 3, &sz))
+ return 1;
+
+ buffer = grub_malloc (sz);
if (! buffer)
return 1;
@@ -226,6 +240,7 @@ match_devices_iter (const char *name, void *data)
struct match_devices_ctx *ctx = data;
char **t;
char *buffer;
+ grub_size_t sz;
/* skip partitions if asked to. */
if (ctx->noparts && grub_strchr (name, ','))
@@ -239,11 +254,16 @@ match_devices_iter (const char *name, void *data)
if (regexec (ctx->regexp, buffer, 0, 0, 0))
{
grub_dprintf ("expand", "not matched\n");
+ fail:
grub_free (buffer);
return 0;
}
- t = grub_realloc (ctx->devs, sizeof (char*) * (ctx->ndev + 2));
+ if (grub_add (ctx->ndev, 2, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ goto fail;
+
+ t = grub_realloc (ctx->devs, sz);
if (! t)
{
grub_free (buffer);
@@ -300,6 +320,7 @@ match_files_iter (const char *name,
struct match_files_ctx *ctx = data;
char **t;
char *buffer;
+ grub_size_t sz;
/* skip . and .. names */
if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
@@ -315,9 +336,14 @@ match_files_iter (const char *name,
if (! buffer)
return 1;
- t = grub_realloc (ctx->files, sizeof (char*) * (ctx->nfile + 2));
- if (! t)
+ if (grub_add (ctx->nfile, 2, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ goto fail;
+
+ t = grub_realloc (ctx->files, sz);
+ if (!t)
{
+ fail:
grub_free (buffer);
return 1;
}
diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
index e6323701a..58f8a53e1 100644
--- a/grub-core/disk/ldm.c
+++ b/grub-core/disk/ldm.c
@@ -25,6 +25,7 @@
#include <grub/msdos_partition.h>
#include <grub/gpt_partition.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
#ifdef GRUB_UTIL
#include <grub/emu/misc.h>
@@ -289,6 +290,7 @@ make_vg (grub_disk_t disk,
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
+ grub_size_t sz;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
@@ -350,7 +352,13 @@ make_vg (grub_disk_t disk,
grub_free (lv);
goto fail2;
}
- lv->name = grub_malloc (*ptr + 1);
+ if (grub_add (*ptr, 1, &sz))
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv);
+ goto fail2;
+ }
+ lv->name = grub_malloc (sz);
if (!lv->name)
{
grub_free (lv->internal_id);
@@ -599,10 +607,13 @@ make_vg (grub_disk_t disk,
if (lv->segments->node_alloc == lv->segments->node_count)
{
void *t;
- lv->segments->node_alloc *= 2;
- t = grub_realloc (lv->segments->nodes,
- sizeof (*lv->segments->nodes)
- * lv->segments->node_alloc);
+ grub_size_t sz;
+
+ if (grub_mul (lv->segments->node_alloc, 2, &lv->segments->node_alloc) ||
+ grub_mul (lv->segments->node_alloc, sizeof (*lv->segments->nodes), &sz))
+ goto fail2;
+
+ t = grub_realloc (lv->segments->nodes, sz);
if (!t)
goto fail2;
lv->segments->nodes = t;
@@ -723,10 +734,13 @@ make_vg (grub_disk_t disk,
if (comp->segment_alloc == comp->segment_count)
{
void *t;
- comp->segment_alloc *= 2;
- t = grub_realloc (comp->segments,
- comp->segment_alloc
- * sizeof (*comp->segments));
+ grub_size_t sz;
+
+ if (grub_mul (comp->segment_alloc, 2, &comp->segment_alloc) ||
+ grub_mul (comp->segment_alloc, sizeof (*comp->segments), &sz))
+ goto fail2;
+
+ t = grub_realloc (comp->segments, sz);
if (!t)
goto fail2;
comp->segments = t;
diff --git a/grub-core/font/font.c b/grub-core/font/font.c
index 8e118b315..5edb477ac 100644
--- a/grub-core/font/font.c
+++ b/grub-core/font/font.c
@@ -30,6 +30,7 @@
#include <grub/unicode.h>
#include <grub/fontformat.h>
#include <grub/env.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -360,9 +361,13 @@ static char *
read_section_as_string (struct font_file_section *section)
{
char *str;
+ grub_size_t sz;
grub_ssize_t ret;
- str = grub_malloc (section->length + 1);
+ if (grub_add (section->length, 1, &sz))
+ return NULL;
+
+ str = grub_malloc (sz);
if (!str)
return 0;
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 11272efc1..2b65bd56a 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -40,6 +40,7 @@
#include <grub/btrfs.h>
#include <grub/crypto.h>
#include <grub/diskfilter.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -329,9 +330,13 @@ save_ref (struct grub_btrfs_leaf_descriptor *desc,
if (desc->allocated < desc->depth)
{
void *newdata;
- desc->allocated *= 2;
- newdata = grub_realloc (desc->data, sizeof (desc->data[0])
- * desc->allocated);
+ grub_size_t sz;
+
+ if (grub_mul (desc->allocated, 2, &desc->allocated) ||
+ grub_mul (desc->allocated, sizeof (desc->data[0]), &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+
+ newdata = grub_realloc (desc->data, sz);
if (!newdata)
return grub_errno;
desc->data = newdata;
@@ -622,16 +627,21 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t id)
if (data->n_devices_attached > data->n_devices_allocated)
{
void *tmp;
- data->n_devices_allocated = 2 * data->n_devices_attached + 1;
- data->devices_attached
- = grub_realloc (tmp = data->devices_attached,
- data->n_devices_allocated
- * sizeof (data->devices_attached[0]));
+ grub_size_t sz;
+
+ if (grub_mul (data->n_devices_attached, 2, &data->n_devices_allocated) ||
+ grub_add (data->n_devices_allocated, 1, &data->n_devices_allocated) ||
+ grub_mul (data->n_devices_allocated, sizeof (data->devices_attached[0]), &sz))
+ goto fail;
+
+ data->devices_attached = grub_realloc (tmp = data->devices_attached, sz);
if (!data->devices_attached)
{
+ data->devices_attached = tmp;
+
+ fail:
if (ctx.dev_found)
grub_device_close (ctx.dev_found);
- data->devices_attached = tmp;
return NULL;
}
}
diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
index 9b389802a..ac33bcd68 100644
--- a/grub-core/fs/ext2.c
+++ b/grub-core/fs/ext2.c
@@ -46,6 +46,7 @@
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/fshelp.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -703,6 +704,7 @@ grub_ext2_read_symlink (grub_fshelp_node_t node)
{
char *symlink;
struct grub_fshelp_node *diro = node;
+ grub_size_t sz;
if (! diro->inode_read)
{
@@ -717,7 +719,13 @@ grub_ext2_read_symlink (grub_fshelp_node_t node)
}
}
- symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1);
+ if (grub_add (grub_le_to_cpu32 (diro->inode.size), 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+ return NULL;
+ }
+
+ symlink = grub_malloc (sz);
if (! symlink)
return 0;
diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c
index 4f1b52a55..7ba5b300b 100644
--- a/grub-core/fs/iso9660.c
+++ b/grub-core/fs/iso9660.c
@@ -28,6 +28,7 @@
#include <grub/fshelp.h>
#include <grub/charset.h>
#include <grub/datetime.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -531,8 +532,13 @@ add_part (struct iterate_dir_ctx *ctx,
int len2)
{
int size = ctx->symlink ? grub_strlen (ctx->symlink) : 0;
+ grub_size_t sz;
- ctx->symlink = grub_realloc (ctx->symlink, size + len2 + 1);
+ if (grub_add (size, len2, &sz) ||
+ grub_add (sz, 1, &sz))
+ return;
+
+ ctx->symlink = grub_realloc (ctx->symlink, sz);
if (! ctx->symlink)
return;
@@ -560,17 +566,24 @@ susp_iterate_dir (struct grub_iso9660_susp_entry *entry,
{
grub_size_t off = 0, csize = 1;
char *old;
+ grub_size_t sz;
+
csize = entry->len - 5;
old = ctx->filename;
if (ctx->filename_alloc)
{
off = grub_strlen (ctx->filename);
- ctx->filename = grub_realloc (ctx->filename, csize + off + 1);
+ if (grub_add (csize, off, &sz) ||
+ grub_add (sz, 1, &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+ ctx->filename = grub_realloc (ctx->filename, sz);
}
else
{
off = 0;
- ctx->filename = grub_zalloc (csize + 1);
+ if (grub_add (csize, 1, &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+ ctx->filename = grub_zalloc (sz);
}
if (!ctx->filename)
{
@@ -776,14 +789,18 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
if (node->have_dirents >= node->alloc_dirents)
{
struct grub_fshelp_node *new_node;
- node->alloc_dirents *= 2;
- new_node = grub_realloc (node,
- sizeof (struct grub_fshelp_node)
- + ((node->alloc_dirents
- - ARRAY_SIZE (node->dirents))
- * sizeof (node->dirents[0])));
+ grub_size_t sz;
+
+ if (grub_mul (node->alloc_dirents, 2, &node->alloc_dirents) ||
+ grub_sub (node->alloc_dirents, ARRAY_SIZE (node->dirents), &sz) ||
+ grub_mul (sz, sizeof (node->dirents[0]), &sz) ||
+ grub_add (sz, sizeof (struct grub_fshelp_node), &sz))
+ goto fail_0;
+
+ new_node = grub_realloc (node, sz);
if (!new_node)
{
+ fail_0:
if (ctx.filename_alloc)
grub_free (ctx.filename);
grub_free (node);
@@ -799,14 +816,18 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
* sizeof (node->dirents[0]) < grub_strlen (ctx.symlink) + 1)
{
struct grub_fshelp_node *new_node;
- new_node = grub_realloc (node,
- sizeof (struct grub_fshelp_node)
- + ((node->alloc_dirents
- - ARRAY_SIZE (node->dirents))
- * sizeof (node->dirents[0]))
- + grub_strlen (ctx.symlink) + 1);
+ grub_size_t sz;
+
+ if (grub_sub (node->alloc_dirents, ARRAY_SIZE (node->dirents), &sz) ||
+ grub_mul (sz, sizeof (node->dirents[0]), &sz) ||
+ grub_add (sz, sizeof (struct grub_fshelp_node) + 1, &sz) ||
+ grub_add (sz, grub_strlen (ctx.symlink), &sz))
+ goto fail_1;
+
+ new_node = grub_realloc (node, sz);
if (!new_node)
{
+ fail_1:
if (ctx.filename_alloc)
grub_free (ctx.filename);
grub_free (node);
diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c
index 90f7fb379..de2b107a4 100644
--- a/grub-core/fs/sfs.c
+++ b/grub-core/fs/sfs.c
@@ -26,6 +26,7 @@
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/charset.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -307,10 +308,15 @@ grub_sfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
if (node->cache && node->cache_size >= node->cache_allocated)
{
struct cache_entry *e = node->cache;
- e = grub_realloc (node->cache,node->cache_allocated * 2
- * sizeof (e[0]));
+ grub_size_t sz;
+
+ if (grub_mul (node->cache_allocated, 2 * sizeof (e[0]), &sz))
+ goto fail;
+
+ e = grub_realloc (node->cache, sz);
if (!e)
{
+ fail:
grub_errno = 0;
grub_free (node->cache);
node->cache = 0;
@@ -477,10 +483,16 @@ grub_sfs_create_node (struct grub_fshelp_node **node,
grub_size_t len = grub_strlen (name);
grub_uint8_t *name_u8;
int ret;
+ grub_size_t sz;
+
+ if (grub_mul (len, GRUB_MAX_UTF8_PER_LATIN1, &sz) ||
+ grub_add (sz, 1, &sz))
+ return 1;
+
*node = grub_malloc (sizeof (**node));
if (!*node)
return 1;
- name_u8 = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1);
+ name_u8 = grub_malloc (sz);
if (!name_u8)
{
grub_free (*node);
@@ -724,8 +736,13 @@ grub_sfs_label (grub_device_t device, char **label)
data = grub_sfs_mount (disk);
if (data)
{
- grub_size_t len = grub_strlen (data->label);
- *label = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1);
+ grub_size_t sz, len = grub_strlen (data->label);
+
+ if (grub_mul (len, GRUB_MAX_UTF8_PER_LATIN1, &sz) ||
+ grub_add (sz, 1, &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+
+ *label = grub_malloc (sz);
if (*label)
*grub_latin1_to_utf8 ((grub_uint8_t *) *label,
(const grub_uint8_t *) data->label,
diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c
index 95d5c1e1f..785123894 100644
--- a/grub-core/fs/squash4.c
+++ b/grub-core/fs/squash4.c
@@ -26,6 +26,7 @@
#include <grub/types.h>
#include <grub/fshelp.h>
#include <grub/deflate.h>
+#include <grub/safemath.h>
#include <minilzo.h>
#include "xz.h"
@@ -459,7 +460,17 @@ grub_squash_read_symlink (grub_fshelp_node_t node)
{
char *ret;
grub_err_t err;
- ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1);
+ grub_size_t sz;
+
+ if (grub_add (grub_le_to_cpu32 (node->ino.symlink.namelen), 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+ return NULL;
+ }
+
+ ret = grub_malloc (sz);
+ if (!ret)
+ return NULL;
err = read_chunk (node->data, ret,
grub_le_to_cpu32 (node->ino.symlink.namelen),
@@ -506,11 +517,16 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
{
grub_fshelp_node_t node;
- node = grub_malloc (sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
+ grub_size_t sz;
+
+ if (grub_mul (dir->stsize, sizeof (dir->stack[0]), &sz) ||
+ grub_add (sz, sizeof (*node), &sz))
+ return 0;
+
+ node = grub_malloc (sz);
if (!node)
return 0;
- grub_memcpy (node, dir,
- sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
+ grub_memcpy (node, dir, sz);
if (hook (".", GRUB_FSHELP_DIR, node, hook_data))
return 1;
@@ -518,12 +534,15 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
{
grub_err_t err;
- node = grub_malloc (sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
+ if (grub_mul (dir->stsize, sizeof (dir->stack[0]), &sz) ||
+ grub_add (sz, sizeof (*node), &sz))
+ return 0;
+
+ node = grub_malloc (sz);
if (!node)
return 0;
- grub_memcpy (node, dir,
- sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
+ grub_memcpy (node, dir, sz);
node->stsize--;
err = read_chunk (dir->data, &node->ino, sizeof (node->ino),
@@ -557,6 +576,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
enum grub_fshelp_filetype filetype = GRUB_FSHELP_REG;
struct grub_squash_dirent di;
struct grub_squash_inode ino;
+ grub_size_t sz;
err = read_chunk (dir->data, &di, sizeof (di),
grub_le_to_cpu64 (dir->data->sb.diroffset)
@@ -589,13 +609,16 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_SYMLINK)
filetype = GRUB_FSHELP_SYMLINK;
- node = grub_malloc (sizeof (*node)
- + (dir->stsize + 1) * sizeof (dir->stack[0]));
+ if (grub_add (dir->stsize, 1, &sz) ||
+ grub_mul (sz, sizeof (dir->stack[0]), &sz) ||
+ grub_add (sz, sizeof (*node), &sz))
+ return 0;
+
+ node = grub_malloc (sz);
if (! node)
return 0;
- grub_memcpy (node, dir,
- sizeof (*node) + dir->stsize * sizeof (dir->stack[0]));
+ grub_memcpy (node, dir, sz - sizeof(dir->stack[0]));
node->ino = ino;
node->stack[node->stsize].ino_chunk = grub_le_to_cpu32 (dh.ino_chunk);
diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
index a83761674..21ac7f446 100644
--- a/grub-core/fs/udf.c
+++ b/grub-core/fs/udf.c
@@ -28,6 +28,7 @@
#include <grub/charset.h>
#include <grub/datetime.h>
#include <grub/udf.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -890,9 +891,19 @@ read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2];
}
if (!outbuf)
- outbuf = grub_malloc (utf16len * GRUB_MAX_UTF8_PER_UTF16 + 1);
+ {
+ grub_size_t size;
+
+ if (grub_mul (utf16len, GRUB_MAX_UTF8_PER_UTF16, &size) ||
+ grub_add (size, 1, &size))
+ goto fail;
+
+ outbuf = grub_malloc (size);
+ }
if (outbuf)
*grub_utf16_to_utf8 ((grub_uint8_t *) outbuf, utf16, utf16len) = '\0';
+
+ fail:
grub_free (utf16);
return outbuf;
}
@@ -1005,7 +1016,7 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
grub_size_t sz = U64 (node->block.fe.file_size);
grub_uint8_t *raw;
const grub_uint8_t *ptr;
- char *out, *optr;
+ char *out = NULL, *optr;
if (sz < 4)
return NULL;
@@ -1013,14 +1024,16 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
if (!raw)
return NULL;
if (grub_udf_read_file (node, NULL, NULL, 0, sz, (char *) raw) < 0)
- {
- grub_free (raw);
- return NULL;
- }
+ goto fail_1;
- out = grub_malloc (sz * 2 + 1);
+ if (grub_mul (sz, 2, &sz) ||
+ grub_add (sz, 1, &sz))
+ goto fail_0;
+
+ out = grub_malloc (sz);
if (!out)
{
+ fail_0:
grub_free (raw);
return NULL;
}
@@ -1031,17 +1044,17 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
{
grub_size_t s;
if ((grub_size_t) (ptr - raw + 4) > sz)
- goto fail;
+ goto fail_1;
if (!(ptr[2] == 0 && ptr[3] == 0))
- goto fail;
+ goto fail_1;
s = 4 + ptr[1];
if ((grub_size_t) (ptr - raw + s) > sz)
- goto fail;
+ goto fail_1;
switch (*ptr)
{
case 1:
if (ptr[1])
- goto fail;
+ goto fail_1;
/* Fallthrough. */
case 2:
/* in 4 bytes. out: 1 byte. */
@@ -1066,11 +1079,11 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
if (optr != out)
*optr++ = '/';
if (!read_string (ptr + 4, s - 4, optr))
- goto fail;
+ goto fail_1;
optr += grub_strlen (optr);
break;
default:
- goto fail;
+ goto fail_1;
}
ptr += s;
}
@@ -1078,7 +1091,7 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
grub_free (raw);
return out;
- fail:
+ fail_1:
grub_free (raw);
grub_free (out);
grub_error (GRUB_ERR_BAD_FS, "invalid symlink");
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 96ffecbfc..ea6590290 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -25,6 +25,7 @@
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/fshelp.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -899,6 +900,7 @@ static struct grub_xfs_data *
grub_xfs_mount (grub_disk_t disk)
{
struct grub_xfs_data *data = 0;
+ grub_size_t sz;
data = grub_zalloc (sizeof (struct grub_xfs_data));
if (!data)
@@ -913,10 +915,11 @@ grub_xfs_mount (grub_disk_t disk)
if (!grub_xfs_sb_valid(data))
goto fail;
- data = grub_realloc (data,
- sizeof (struct grub_xfs_data)
- - sizeof (struct grub_xfs_inode)
- + grub_xfs_inode_size(data) + 1);
+ if (grub_add (grub_xfs_inode_size (data),
+ sizeof (struct grub_xfs_data) - sizeof (struct grub_xfs_inode) + 1, &sz))
+ goto fail;
+
+ data = grub_realloc (data, sz);
if (! data)
goto fail;
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index 381dde556..36d0373a6 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -55,6 +55,7 @@
#include <grub/deflate.h>
#include <grub/crypto.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -773,11 +774,14 @@ fill_vdev_info (struct grub_zfs_data *data,
if (data->n_devices_attached > data->n_devices_allocated)
{
void *tmp;
- data->n_devices_allocated = 2 * data->n_devices_attached + 1;
- data->devices_attached
- = grub_realloc (tmp = data->devices_attached,
- data->n_devices_allocated
- * sizeof (data->devices_attached[0]));
+ grub_size_t sz;
+
+ if (grub_mul (data->n_devices_attached, 2, &data->n_devices_allocated) ||
+ grub_add (data->n_devices_allocated, 1, &data->n_devices_allocated) ||
+ grub_mul (data->n_devices_allocated, sizeof (data->devices_attached[0]), &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+
+ data->devices_attached = grub_realloc (tmp = data->devices_attached, sz);
if (!data->devices_attached)
{
data->devices_attached = tmp;
@@ -3468,14 +3472,18 @@ grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name)
{
char *nvpair;
char *ret;
- grub_size_t size;
+ grub_size_t size, sz;
int found;
found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair,
&size, 0);
if (!found)
return 0;
- ret = grub_zalloc (size + 3 * sizeof (grub_uint32_t));
+
+ if (grub_add (size, 3 * sizeof (grub_uint32_t), &sz))
+ return 0;
+
+ ret = grub_zalloc (sz);
if (!ret)
return 0;
grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c
index 1402e0bc2..de3b015f5 100644
--- a/grub-core/fs/zfs/zfscrypt.c
+++ b/grub-core/fs/zfs/zfscrypt.c
@@ -22,6 +22,7 @@
#include <grub/misc.h>
#include <grub/disk.h>
#include <grub/partition.h>
+#include <grub/safemath.h>
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/zfs/zfs.h>
@@ -82,9 +83,13 @@ grub_zfs_add_key (grub_uint8_t *key_in,
int passphrase)
{
struct grub_zfs_wrap_key *key;
+ grub_size_t sz;
+
if (!passphrase && keylen > 32)
keylen = 32;
- key = grub_malloc (sizeof (*key) + keylen);
+ if (grub_add (sizeof (*key), keylen, &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+ key = grub_malloc (sz);
if (!key)
return grub_errno;
key->is_passphrase = passphrase;
diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c
index fd7744a6f..3288609a5 100644
--- a/grub-core/lib/arg.c
+++ b/grub-core/lib/arg.c
@@ -23,6 +23,7 @@
#include <grub/term.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
/* Built-in parser for default options. */
static const struct grub_arg_option help_options[] =
@@ -216,7 +217,13 @@ static inline grub_err_t
add_arg (char ***argl, int *num, char *s)
{
char **p = *argl;
- *argl = grub_realloc (*argl, (++(*num) + 1) * sizeof (char *));
+ grub_size_t sz;
+
+ if (grub_add (++(*num), 1, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+
+ *argl = grub_realloc (*argl, sz);
if (! *argl)
{
grub_free (p);
@@ -431,6 +438,7 @@ grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
grub_size_t argcnt;
struct grub_arg_list *list;
const struct grub_arg_option *options;
+ grub_size_t sz0, sz1;
options = extcmd->options;
if (! options)
@@ -443,7 +451,15 @@ grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
argcnt += ((grub_size_t) argc + 1) / 2 + 1; /* max possible for any option */
}
- list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt);
+ if (grub_mul (sizeof (*list), i, &sz0) ||
+ grub_mul (sizeof (char *), argcnt, &sz1) ||
+ grub_add (sz0, sz1, &sz0))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+ return 0;
+ }
+
+ list = grub_zalloc (sz0);
if (! list)
return 0;
diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
index 3730ed382..b92cbe98d 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -35,6 +35,7 @@
#include <grub/ns8250.h>
#include <grub/bsdlabel.h>
#include <grub/crypto.h>
+#include <grub/safemath.h>
#include <grub/verify.h>
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/int.h>
@@ -1012,11 +1013,16 @@ grub_netbsd_add_modules (void)
struct grub_netbsd_btinfo_modules *mods;
unsigned i;
grub_err_t err;
+ grub_size_t sz;
for (mod = netbsd_mods; mod; mod = mod->next)
modcnt++;
- mods = grub_malloc (sizeof (*mods) + sizeof (mods->mods[0]) * modcnt);
+ if (grub_mul (modcnt, sizeof (mods->mods[0]), &sz) ||
+ grub_add (sz, sizeof (*mods), &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+
+ mods = grub_malloc (sz);
if (!mods)
return grub_errno;
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index e332d5eb4..906ec7d67 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -22,6 +22,7 @@
#include <grub/i18n.h>
#include <grub/err.h>
#include <grub/time.h>
+#include <grub/safemath.h>
struct dns_cache_element
{
@@ -51,9 +52,15 @@ grub_net_add_dns_server (const struct grub_net_network_level_address *s)
{
int na = dns_servers_alloc * 2;
struct grub_net_network_level_address *ns;
+ grub_size_t sz;
+
if (na < 8)
na = 8;
- ns = grub_realloc (dns_servers, na * sizeof (ns[0]));
+
+ if (grub_mul (na, sizeof (ns[0]), &sz))
+ return GRUB_ERR_OUT_OF_RANGE;
+
+ ns = grub_realloc (dns_servers, sz);
if (!ns)
return grub_errno;
dns_servers_alloc = na;
diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
index d57fb72fa..4dfcc3107 100644
--- a/grub-core/normal/charset.c
+++ b/grub-core/normal/charset.c
@@ -48,6 +48,7 @@
#include <grub/unicode.h>
#include <grub/term.h>
#include <grub/normal.h>
+#include <grub/safemath.h>
#if HAVE_FONT_SOURCE
#include "widthspec.h"
@@ -464,6 +465,7 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
{
struct grub_unicode_combining *n;
unsigned j;
+ grub_size_t sz;
if (!haveout)
continue;
@@ -477,10 +479,14 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
n = out->combining_inline;
else if (out->ncomb > (int) ARRAY_SIZE (out->combining_inline))
{
- n = grub_realloc (out->combining_ptr,
- sizeof (n[0]) * (out->ncomb + 1));
+ if (grub_add (out->ncomb, 1, &sz) ||
+ grub_mul (sz, sizeof (n[0]), &sz))
+ goto fail;
+
+ n = grub_realloc (out->combining_ptr, sz);
if (!n)
{
+ fail:
grub_errno = GRUB_ERR_NONE;
continue;
}
diff --git a/grub-core/normal/cmdline.c b/grub-core/normal/cmdline.c
index c57242e2e..de03fe63b 100644
--- a/grub-core/normal/cmdline.c
+++ b/grub-core/normal/cmdline.c
@@ -28,6 +28,7 @@
#include <grub/env.h>
#include <grub/i18n.h>
#include <grub/charset.h>
+#include <grub/safemath.h>
static grub_uint32_t *kill_buf;
@@ -307,12 +308,21 @@ cl_insert (struct cmdline_term *cl_terms, unsigned nterms,
if (len + (*llen) >= (*max_len))
{
grub_uint32_t *nbuf;
- (*max_len) *= 2;
- nbuf = grub_realloc ((*buf), sizeof (grub_uint32_t) * (*max_len));
+ grub_size_t sz;
+
+ if (grub_mul (*max_len, 2, max_len) ||
+ grub_mul (*max_len, sizeof (grub_uint32_t), &sz))
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ goto fail;
+ }
+
+ nbuf = grub_realloc ((*buf), sz);
if (nbuf)
(*buf) = nbuf;
else
{
+ fail:
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
(*max_len) /= 2;
diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
index 1993995be..50eef918c 100644
--- a/grub-core/normal/menu_entry.c
+++ b/grub-core/normal/menu_entry.c
@@ -27,6 +27,7 @@
#include <grub/auth.h>
#include <grub/i18n.h>
#include <grub/charset.h>
+#include <grub/safemath.h>
enum update_mode
{
@@ -113,10 +114,18 @@ ensure_space (struct line *linep, int extra)
{
if (linep->max_len < linep->len + extra)
{
- linep->max_len = 2 * (linep->len + extra);
- linep->buf = grub_realloc (linep->buf, (linep->max_len + 1) * sizeof (linep->buf[0]));
+ grub_size_t sz0, sz1;
+
+ if (grub_add (linep->len, extra, &sz0) ||
+ grub_mul (sz0, 2, &sz0) ||
+ grub_add (sz0, 1, &sz1) ||
+ grub_mul (sz1, sizeof (linep->buf[0]), &sz1))
+ return 0;
+
+ linep->buf = grub_realloc (linep->buf, sz1);
if (! linep->buf)
return 0;
+ linep->max_len = sz0;
}
return 1;
diff --git a/grub-core/script/argv.c b/grub-core/script/argv.c
index 217ec5d1e..5751fdd57 100644
--- a/grub-core/script/argv.c
+++ b/grub-core/script/argv.c
@@ -20,6 +20,7 @@
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/script_sh.h>
+#include <grub/safemath.h>
/* Return nearest power of two that is >= v. */
static unsigned
@@ -81,11 +82,16 @@ int
grub_script_argv_next (struct grub_script_argv *argv)
{
char **p = argv->args;
+ grub_size_t sz;
if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0)
return 0;
- p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *)));
+ if (grub_add (argv->argc, 2, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ return 1;
+
+ p = grub_realloc (p, round_up_exp (sz));
if (! p)
return 1;
@@ -105,13 +111,19 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s,
{
grub_size_t a;
char *p = argv->args[argv->argc - 1];
+ grub_size_t sz;
if (! s)
return 0;
a = p ? grub_strlen (p) : 0;
- p = grub_realloc (p, round_up_exp ((a + slen + 1) * sizeof (char)));
+ if (grub_add (a, slen, &sz) ||
+ grub_add (sz, 1, &sz) ||
+ grub_mul (sz, sizeof (char), &sz))
+ return 1;
+
+ p = grub_realloc (p, round_up_exp (sz));
if (! p)
return 1;
diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c
index c6bd3172f..5fb0cbd0b 100644
--- a/grub-core/script/lexer.c
+++ b/grub-core/script/lexer.c
@@ -24,6 +24,7 @@
#include <grub/mm.h>
#include <grub/script_sh.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
#define yytext_ptr char *
#include "grub_script.tab.h"
@@ -110,10 +111,14 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str)
old = lexer->recording;
if (lexer->recordlen < len)
lexer->recordlen = len;
- lexer->recordlen *= 2;
+
+ if (grub_mul (lexer->recordlen, 2, &lexer->recordlen))
+ goto fail;
+
lexer->recording = grub_realloc (lexer->recording, lexer->recordlen);
if (!lexer->recording)
{
+ fail:
grub_free (old);
lexer->recordpos = 0;
lexer->recordlen = 0;
@@ -130,7 +135,7 @@ int
grub_script_lexer_yywrap (struct grub_parser_param *parserstate,
const char *input)
{
- grub_size_t len = 0;
+ grub_size_t len = 0, sz;
char *p = 0;
char *line = 0;
YY_BUFFER_STATE buffer;
@@ -168,12 +173,22 @@ grub_script_lexer_yywrap (struct grub_parser_param *parserstate,
}
else if (len && line[len - 1] != '\n')
{
- p = grub_realloc (line, len + 2);
+ if (grub_add (len, 2, &sz))
+ {
+ grub_free (line);
+ grub_script_yyerror (parserstate, N_("overflow is detected"));
+ return 1;
+ }
+
+ p = grub_realloc (line, sz);
if (p)
{
p[len++] = '\n';
p[len] = '\0';
}
+ else
+ grub_free (line);
+
line = p;
}
diff --git a/grub-core/video/bitmap.c b/grub-core/video/bitmap.c
index b2e031566..6256e209a 100644
--- a/grub-core/video/bitmap.c
+++ b/grub-core/video/bitmap.c
@@ -23,6 +23,7 @@
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -58,7 +59,7 @@ grub_video_bitmap_create (struct grub_video_bitmap **bitmap,
enum grub_video_blit_format blit_format)
{
struct grub_video_mode_info *mode_info;
- unsigned int size;
+ grub_size_t size;
if (!bitmap)
return grub_error (GRUB_ERR_BUG, "invalid argument");
@@ -137,19 +138,25 @@ grub_video_bitmap_create (struct grub_video_bitmap **bitmap,
mode_info->pitch = width * mode_info->bytes_per_pixel;
- /* Calculate size needed for the data. */
- size = (width * mode_info->bytes_per_pixel) * height;
+ /* Calculate size needed for the data. */
+ if (grub_mul (width, mode_info->bytes_per_pixel, &size) ||
+ grub_mul (size, height, &size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+ goto fail;
+ }
(*bitmap)->data = grub_zalloc (size);
if (! (*bitmap)->data)
- {
- grub_free (*bitmap);
- *bitmap = 0;
-
- return grub_errno;
- }
+ goto fail;
return GRUB_ERR_NONE;
+
+ fail:
+ grub_free (*bitmap);
+ *bitmap = NULL;
+
+ return grub_errno;
}
/* Frees all resources allocated by bitmap. */
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index 61bd64537..0157ff742 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -23,6 +23,7 @@
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/bufio.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -301,9 +302,17 @@ grub_png_decode_image_header (struct grub_png_data *data)
data->bpp <<= 1;
data->color_bits = color_bits;
- data->row_bytes = data->image_width * data->bpp;
+
+ if (grub_mul (data->image_width, data->bpp, &data->row_bytes))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+
if (data->color_bits <= 4)
- data->row_bytes = (data->image_width * data->color_bits + 7) / 8;
+ {
+ if (grub_mul (data->image_width, data->color_bits + 7, &data->row_bytes))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+
+ data->row_bytes >>= 3;
+ }
#ifndef GRUB_CPU_WORDS_BIGENDIAN
if (data->is_16bit || data->is_gray || data->is_palette)
--
2.26.2