From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alec Brown Date: Wed, 22 Jan 2025 02:55:09 +0000 Subject: [PATCH] disk: Use safe math macros to prevent overflows Replace direct arithmetic operations with macros from include/grub/safemath.h to prevent potential overflow issues when calculating the memory sizes. Signed-off-by: Alec Brown Reviewed-by: Daniel Kiper --- grub-core/disk/cryptodisk.c | 36 ++++++++++++++++++------ grub-core/disk/diskfilter.c | 9 ++++-- grub-core/disk/ieee1275/ofdisk.c | 60 ++++++++++++++++++++++++++++++++++------ grub-core/disk/ldm.c | 37 +++++++++++++++++++++---- grub-core/disk/memdisk.c | 7 ++++- 5 files changed, 123 insertions(+), 26 deletions(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 78a902515..871640685 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef GRUB_UTIL #include @@ -1039,7 +1040,7 @@ static char * luks_script_get (grub_size_t *sz) { grub_cryptodisk_t i; - grub_size_t size = 0; + grub_size_t size = 0, mul; char *ptr, *ret; *sz = 0; @@ -1047,16 +1048,33 @@ luks_script_get (grub_size_t *sz) for (i = cryptodisk_list; i != NULL; i = i->next) if (grub_strcmp (i->modname, "luks") == 0) { - size += sizeof ("luks_mount "); - size += grub_strlen (i->uuid); - size += grub_strlen (i->cipher->cipher->name); - size += 54; - if (i->essiv_hash) - size += grub_strlen (i->essiv_hash->name); - size += i->keysize * 2; + if (grub_add (size, grub_strlen (i->modname), &size) || + grub_add (size, sizeof ("_mount") + 60, &size) || + grub_add (size, grub_strlen (i->uuid), &size) || + grub_add (size, grub_strlen (i->cipher->cipher->name), &size) || + grub_mul (i->keysize, 2, &mul) || + grub_add (size, mul, &size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); + return 0; + } + if (i->essiv_hash) + { + if (grub_add (size, grub_strlen (i->essiv_hash->name), &size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); + return 0; + } + } } - ret = grub_malloc (size + 1); + if (grub_add (size, 1, &size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); + return 0; + } + + ret = grub_malloc (size); if (!ret) return 0; diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index 2be019269..a881aa2c9 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef GRUB_UTIL #include #include @@ -1013,7 +1014,7 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, { struct grub_diskfilter_vg *array; int i; - grub_size_t j; + grub_size_t j, sz; grub_uint64_t totsize; struct grub_diskfilter_pv *pv; grub_err_t err; @@ -1107,7 +1108,11 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, } array->lvs->vg = array; - array->lvs->idname = grub_malloc (sizeof ("mduuid/") + 2 * uuidlen); + if (grub_mul (uuidlen, 2, &sz) || + grub_add (sz, sizeof ("mduuid/"), &sz)) + goto fail; + + array->lvs->idname = grub_malloc (sz); if (!array->lvs->idname) goto fail; diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index 98325ca98..c1b07d087 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -24,6 +24,7 @@ #include #include #include +#include static char *last_devpath; static grub_ieee1275_ihandle_t last_ihandle; @@ -80,6 +81,7 @@ ofdisk_hash_add_real (char *devpath) struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)]; const char *iptr; char *optr; + grub_size_t sz; p = grub_zalloc (sizeof (*p)); if (!p) @@ -87,8 +89,14 @@ ofdisk_hash_add_real (char *devpath) p->devpath = devpath; - p->grub_devpath = grub_malloc (sizeof ("ieee1275/") - + 2 * grub_strlen (p->devpath)); + if (grub_mul (grub_strlen (p->devpath), 2, &sz) || + grub_add (sz, sizeof ("ieee1275/"), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path")); + return NULL; + } + + p->grub_devpath = grub_malloc (sz); if (!p->grub_devpath) { @@ -98,7 +106,13 @@ ofdisk_hash_add_real (char *devpath) if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0)) { - p->open_path = grub_malloc (grub_strlen (p->devpath) + 3); + if (grub_add (grub_strlen (p->devpath), 3, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path")); + return NULL; + } + + p->open_path = grub_malloc (sz); if (!p->open_path) { grub_free (p->grub_devpath); @@ -224,7 +238,7 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) args; char *buf, *bufptr; unsigned i; - + grub_size_t sz; RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle) if (! ihandle) @@ -245,7 +259,14 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) return; } - buf = grub_malloc (grub_strlen (alias->path) + 32); + if (grub_add (grub_strlen (alias->path), 32, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for vscsi"); + grub_ieee1275_close (ihandle); + return; + } + + buf = grub_malloc (sz); if (!buf) return; bufptr = grub_stpcpy (buf, alias->path); @@ -289,9 +310,15 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) grub_uint64_t *table; grub_uint16_t table_size; grub_ieee1275_ihandle_t ihandle; + grub_size_t sz; - buf = grub_malloc (grub_strlen (alias->path) + - sizeof ("/disk@7766554433221100")); + if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for sas_ioa"); + return; + } + + buf = grub_malloc (sz); if (!buf) return; bufptr = grub_stpcpy (buf, alias->path); @@ -431,9 +458,17 @@ grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, static char * compute_dev_path (const char *name) { - char *devpath = grub_malloc (grub_strlen (name) + 3); + char *devpath; char *p, c; + grub_size_t sz; + if (grub_add (grub_strlen (name), 3, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path")); + return NULL; + } + + devpath = grub_malloc (sz); if (!devpath) return NULL; @@ -660,6 +695,7 @@ insert_bootpath (void) char *bootpath; grub_ssize_t bootpath_size; char *type; + grub_size_t sz; if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", &bootpath_size) @@ -670,7 +706,13 @@ insert_bootpath (void) return; } - bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); + if (grub_add (bootpath_size, 64, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining bootpath size")); + return; + } + + bootpath = (char *) grub_malloc (sz); if (! bootpath) { grub_print_error (); diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c index e82e9899f..973fbfdcb 100644 --- a/grub-core/disk/ldm.c +++ b/grub-core/disk/ldm.c @@ -220,6 +220,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) @@ -251,7 +252,13 @@ make_vg (grub_disk_t disk, grub_free (pv); goto fail2; } - pv->internal_id = grub_malloc (ptr[0] + 2); + if (grub_add (ptr[0], 2, &sz)) + { + grub_free (pv); + goto fail2; + } + + pv->internal_id = grub_malloc (sz); if (!pv->internal_id) { grub_free (pv); @@ -276,7 +283,15 @@ make_vg (grub_disk_t disk, goto fail2; } pv->id.uuidlen = *ptr; - pv->id.uuid = grub_malloc (pv->id.uuidlen + 1); + + if (grub_add (pv->id.uuidlen, 1, &sz)) + { + grub_free (pv->internal_id); + grub_free (pv); + goto fail2; + } + + pv->id.uuid = grub_malloc (sz); grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen); pv->id.uuid[pv->id.uuidlen] = 0; @@ -343,7 +358,13 @@ make_vg (grub_disk_t disk, grub_free (lv); goto fail2; } - lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); + if (grub_add (ptr[0], 2, &sz)) + { + grub_free (lv->segments); + grub_free (lv); + goto fail2; + } + lv->internal_id = grub_malloc (sz); if (!lv->internal_id) { grub_free (lv); @@ -455,6 +476,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) @@ -489,7 +511,13 @@ make_vg (grub_disk_t disk, { goto fail2; } - comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); + if (grub_add (ptr[0], 2, &sz)) + { + grub_free (comp); + goto fail2; + } + comp->internal_id = grub_malloc (sz); + if (!comp->internal_id) { grub_free (comp); @@ -639,7 +667,6 @@ make_vg (grub_disk_t disk, if (lv->segments->node_alloc == lv->segments->node_count) { void *t; - 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)) diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c index e5ffc01bf..18863305e 100644 --- a/grub-core/disk/memdisk.c +++ b/grub-core/disk/memdisk.c @@ -23,6 +23,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -96,7 +97,11 @@ GRUB_MOD_INIT(memdisk) grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr); - memdisk_size = header->size - sizeof (struct grub_module_header); + if (grub_sub (header->size, sizeof (struct grub_module_header), &memdisk_size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while obtaining memdisk size"); + return; + } memdisk_addr = grub_malloc (memdisk_size); grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n");