malloc: Use overflow checking primitives where we do complex allocations

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>
This commit is contained in:
Peter Jones 2020-06-15 12:28:27 -04:00 committed by Daniel Kiper
parent f725fa7cb2
commit 3f05d693d1
23 changed files with 382 additions and 113 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -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;