On Mon, 10 Mar 2025 11:23:59 -0500
Stuart Hayes <stuart.w.ha...@gmail.com> wrote:

> 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);

Two missing space issues. Daniel, perhaps there is a whitespace commit
that you're accumulating that these can be added to. Or perhaps we just
let it go as I'm now noticing that this file has a lot of spacing
issues.

Also, I noticed that this patch is very similar to the patch attached
to https://savannah.gnu.org/bugs/?63846. However, neither is a subset
of the other. It would have been nice to have a Fixes line on this
commit for that bug. I think I'll take a stab at submitting a patch
with the not included changes.

Glenn

> +  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;
>      }
>  

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to