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:
parent
f725fa7cb2
commit
3f05d693d1
23 changed files with 382 additions and 113 deletions
|
@ -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");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue