Blame SOURCES/0285-malloc-Use-overflow-checking-primitives-where-we-do-.patch

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