Without this fix, grub failed to boot linux with "out of memory" after trying to run a "search --fs-uuid..." on a system that has 7 ZFS pools across about 80 drives.
Signed-off-by: Stuart Hayes <stuart.w.ha...@gmail.com> --- grub-core/fs/zfs/zfs.c | 43 +++++++++++++++++++++++++++++++++----- grub-core/fs/zfs/zfsinfo.c | 5 ++++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c index 376042631..bff9d0208 100644 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -1057,8 +1057,10 @@ check_pool_label (struct grub_zfs_data *data, ZIO_SET_CHECKSUM(&emptycksum, diskdesc->vdev_phys_sector << 9, 0, 0, 0); err = zio_checksum_verify (emptycksum, ZIO_CHECKSUM_LABEL, endian, nvlist, VDEV_PHYS_SIZE); - if (err) + if (err) { + grub_free (nvlist); return err; + } grub_dprintf ("zfs", "check 2 passed\n"); @@ -1144,8 +1146,10 @@ check_pool_label (struct grub_zfs_data *data, if (original) data->guid = poolguid; - if (data->guid != poolguid) + if (data->guid != poolguid) { + grub_free (nvlist); return grub_error (GRUB_ERR_BAD_FS, "another zpool"); + } { char *nv; @@ -1186,9 +1190,12 @@ check_pool_label (struct grub_zfs_data *data, { grub_dprintf("zfs","feature missing in check_pool_label:%s\n",name); err= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET," check_pool_label missing feature '%s' for read",name); + grub_free(features); + grub_free(nvlist); return err; } } + grub_free(features); } grub_dprintf ("zfs", "check 12 passed (feature flags)\n"); grub_free (nvlist); @@ -2601,6 +2608,7 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val, return err; } + grub_free (zapbuf); return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); } @@ -2671,6 +2679,7 @@ zap_iterate_u64 (dnode_end_t * zap_dnode, grub_free (zapbuf); return ret; } + grub_free (zapbuf); grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); return 0; } @@ -2701,6 +2710,7 @@ zap_iterate (dnode_end_t * zap_dnode, if (block_type == ZBT_MICRO) { grub_error (GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected"); + grub_free (zapbuf); return 0; } if (block_type == ZBT_HEADER) @@ -2712,6 +2722,7 @@ zap_iterate (dnode_end_t * zap_dnode, grub_free (zapbuf); return ret; } + grub_free (zapbuf); grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); return 0; } @@ -2785,6 +2796,9 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, } grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE); + if (data->dnode_buf == 0) + /* dnbuf not used anymore if data->dnode_mdn malloc failed */ + grub_free (dnbuf); buf->endian = endian; if (type && buf->dn.dn_type != type) return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); @@ -3436,6 +3450,8 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, if (err) { grub_dprintf ("zfs", "failed here\n"); + grub_free (fsname); + grub_free (snapname); return err; } @@ -3472,8 +3488,11 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, if (!err) err = dnode_get (&(data->mos), headobj, 0, &subvol->mdn, data); - if (!err && subvol->mdn.dn.dn_type != DMU_OT_DSL_DATASET && subvol->mdn.dn.dn_bonustype != DMU_OT_DSL_DATASET) + if (!err && subvol->mdn.dn.dn_type != DMU_OT_DSL_DATASET && subvol->mdn.dn.dn_bonustype != DMU_OT_DSL_DATASET) { + grub_free (fsname); + grub_free (snapname); return grub_error(GRUB_ERR_BAD_FS, "incorrect dataset dnode type"); + } if (err) { @@ -3952,6 +3971,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename) { void *sahdrp; int hdrsize; + bool free_sahdrp = false; if (data->dnode.dn.dn_bonuslen != 0) { @@ -3964,6 +3984,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename) err = zio_read (bp, data->dnode.endian, &sahdrp, NULL, data); if (err) return err; + free_sahdrp = true; } else { @@ -3972,6 +3993,8 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename) hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); file->size = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian); + if (free_sahdrp) + grub_free(sahdrp); } else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE) { @@ -4157,6 +4180,7 @@ fill_fs_info (struct grub_dirhook_info *info, { void *sahdrp; int hdrsize; + bool free_sahdrp = false; if (dn.dn.dn_bonuslen != 0) { @@ -4169,6 +4193,7 @@ fill_fs_info (struct grub_dirhook_info *info, err = zio_read (bp, dn.endian, &sahdrp, NULL, data); if (err) return err; + free_sahdrp = true; } else { @@ -4179,6 +4204,8 @@ fill_fs_info (struct grub_dirhook_info *info, hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); info->mtimeset = 1; info->mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); + if (free_sahdrp) + grub_free (sahdrp); } if (dn.dn.dn_bonustype == DMU_OT_ZNODE) @@ -4210,6 +4237,7 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx) { void *sahdrp; int hdrsize; + bool free_sahdrp = false; if (dn.dn.dn_bonuslen != 0) { @@ -4225,6 +4253,7 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx) grub_print_error (); return 0; } + free_sahdrp = true; } else { @@ -4237,6 +4266,8 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx) info.mtimeset = 1; info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); info.case_insensitive = ctx->data->subvol.case_insensitive; + if (free_sahdrp) + grub_free (sahdrp); } if (dn.dn.dn_bonustype == DMU_OT_ZNODE) @@ -4448,7 +4479,7 @@ check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct gru dnode_end_t dn,mosmdn; mzap_phys_t* mzp; grub_zfs_endian_t endianzap; - int size; + int size, ret; grub_memmove(&(mosmdn.dn),mosmdn_phys,sizeof(dnode_phys_t)); mosmdn.endian=endian; errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT, @@ -4474,7 +4505,9 @@ check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct gru return errnum; size = grub_zfs_to_cpu16 (dn.dn.dn_datablkszsec, dn.endian) << SPA_MINBLOCKSHIFT; - return mzap_iterate (mzp,endianzap, size, check_feature,NULL); + ret = mzap_iterate (mzp,endianzap, size, check_feature,NULL); + grub_free(mzp); + return ret; } diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c index c8a28acf5..31d767bbd 100644 --- a/grub-core/fs/zfs/zfsinfo.c +++ b/grub-core/fs/zfs/zfsinfo.c @@ -379,14 +379,17 @@ grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc, grub_device_close (dev); - if (err) + if (err) { + grub_free (nvlist); return err; + } poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME); if (!poolname) { if (!grub_errno) grub_error (GRUB_ERR_BAD_FS, "No poolname found"); + grub_free (nvlist); return grub_errno; } -- 2.39.3 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel