Fix handling of nvlist array

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-12-05 18:13:32 +01:00
parent 069142f4c2
commit e5c63d9d41
2 changed files with 32 additions and 18 deletions

View file

@ -1812,13 +1812,28 @@ grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist, char *name)
grub_size_t nelm, size; grub_size_t nelm, size;
int found; int found;
found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair, found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
&size, &nelm); &size, &nelm);
if (! found) if (! found)
return -1; return -1;
return nelm; return nelm;
} }
static int
get_nvlist_size (char *beg, char *limit)
{
char *ptr;
grub_uint32_t encode_size;
ptr = beg + 8;
while (ptr < limit
&& (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) ptr)))
ptr += encode_size; /* goto the next nvpair */
ptr += 8;
return (ptr > limit) ? -1 : (ptr - beg);
}
char * char *
grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name, grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name,
grub_size_t index) grub_size_t index)
@ -1829,8 +1844,9 @@ grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name,
grub_size_t size; grub_size_t size;
unsigned i; unsigned i;
grub_size_t nelm; grub_size_t nelm;
int elemsize = 0;
found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair, found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair,
&size, &nelm); &size, &nelm);
if (!found) if (!found)
return 0; return 0;
@ -1844,33 +1860,31 @@ grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name,
for (i = 0; i < index; i++) for (i = 0; i < index; i++)
{ {
grub_uint32_t encode_size; int r;
r = get_nvlist_size (nvpairptr, nvpair + size);
/* skip the header, nvl_version, and nvl_nvflag */ if (r < 0)
nvpairptr = nvpairptr + 4 * 2; {
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
while (nvpairptr < nvpair + size return NULL;
&& (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) nvpairptr))) }
nvlist += encode_size; /* goto the next nvpair */ nvpairptr += r;
nvlist = nvlist + 4 * 2; /* skip the ending 2 zeros - 8 bytes */
} }
if (nvpairptr >= nvpair + size elemsize = get_nvlist_size (nvpairptr, nvpair + size);
|| nvpairptr + grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2))
>= nvpair + size) if (elemsize < 0)
{ {
grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array");
return 0; return 0;
} }
ret = grub_zalloc (grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2)) ret = grub_zalloc (elemsize + sizeof (grub_uint32_t));
+ 3 * sizeof (grub_uint32_t));
if (!ret) if (!ret)
return 0; return 0;
grub_memcpy (ret, nvlist, sizeof (grub_uint32_t)); grub_memcpy (ret, nvlist, sizeof (grub_uint32_t));
grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, size); grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize);
return ret; return ret;
} }

View file

@ -139,7 +139,6 @@ print_vdev_info (char *nvlist, int tab)
} }
grub_printf ("Mirror VDEV with %d children\n", nelm); grub_printf ("Mirror VDEV with %d children\n", nelm);
print_state (nvlist, tab); print_state (nvlist, tab);
for (i = 0; i < nelm; i++) for (i = 0; i < nelm; i++)
{ {
char *child; char *child;
@ -159,6 +158,7 @@ print_vdev_info (char *nvlist, int tab)
grub_free (child); grub_free (child);
} }
return GRUB_ERR_NONE;
} }
print_tabs (tab); print_tabs (tab);