1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
From: Lidong Chen <lidong.chen@oracle.com>
Date: Wed, 22 Jan 2025 07:17:02 +0000
Subject: fs/zfs: 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: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/zfs/zfs.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 44 insertions(+), 6 deletions(-)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index a497b18..2f303d6 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -2387,6 +2387,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
zap_dnode->endian) << DNODE_SHIFT);
grub_err_t err;
grub_zfs_endian_t endian;
+ grub_size_t sz;
if (zap_verify (zap, zap_dnode->endian))
return 0;
@@ -2448,8 +2449,14 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
if (le->le_type != ZAP_CHUNK_ENTRY)
continue;
- buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
- * name_elem_length + 1);
+ if (grub_mul (grub_zfs_to_cpu16 (le->le_name_length, endian), name_elem_length, &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow"));
+ grub_free (l);
+ return grub_errno;
+ }
+ buf = grub_malloc (sz);
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk,
endian),
@@ -2872,6 +2879,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
&& ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa)
{
char *sym_value;
+ grub_size_t sz;
grub_size_t sym_sz;
int free_symval = 0;
char *oldpath = path, *oldpathbuf = path_buf;
@@ -2923,7 +2931,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
break;
free_symval = 1;
}
- path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
+
+ if (grub_add (sym_sz, grub_strlen (oldpath), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow"));
+ grub_free (oldpathbuf);
+ if (free_symval)
+ grub_free (sym_value);
+ err = grub_errno;
+ break;
+ }
+ path = path_buf = grub_malloc (sz);
if (!path_buf)
{
grub_free (oldpathbuf);
@@ -2960,6 +2979,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
{
void *sahdrp;
int hdrsize;
+ grub_size_t sz;
if (dnode_path->dn.dn.dn_bonuslen != 0)
{
@@ -2993,7 +3013,15 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
+ SA_SIZE_OFFSET),
dnode_path->dn.endian);
char *oldpath = path, *oldpathbuf = path_buf;
- path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
+ if (grub_add (sym_sz, grub_strlen (oldpath), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow"));
+ grub_free (oldpathbuf);
+ err = grub_errno;
+ break;
+ }
+ path = path_buf = grub_malloc (sz);
if (!path_buf)
{
grub_free (oldpathbuf);
@@ -3568,6 +3596,7 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
unsigned i;
grub_size_t nelm;
int elemsize = 0;
+ int sz;
found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
&size, &nelm);
@@ -3602,7 +3631,12 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name,
return 0;
}
- ret = grub_zalloc (elemsize + sizeof (grub_uint32_t));
+ if (grub_add (elemsize, sizeof (grub_uint32_t), &sz))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("elemsize overflow"));
+ return 0;
+ }
+ ret = grub_zalloc (sz);
if (!ret)
return 0;
grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
@@ -4193,6 +4227,7 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
struct grub_dirhook_info info;
char *name2;
int ret;
+ grub_size_t sz;
dnode_end_t mdn;
@@ -4213,7 +4248,10 @@ iterate_zap_snap (const char *name, grub_uint64_t val,
return 0;
}
- name2 = grub_malloc (grub_strlen (name) + 2);
+ if (grub_add (grub_strlen (name), 2, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow"));
+
+ name2 = grub_malloc (sz);
name2[0] = '@';
grub_memcpy (name2 + 1, name, grub_strlen (name) + 1);
ret = ctx->hook (name2, &info, ctx->hook_data);
|