Index: cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c =================================================================== --- cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c (revision 219703) +++ cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c (working copy) @@ -151,16 +151,67 @@ zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, co } static int +zfs_ioctl_compat_read_nvlist_dst(uint64_t nvl, size_t nvsize, int iflag, + nvlist_t **nvp) +{ + char *packed; + int err; + nvlist_t *list = NULL; + + /* + * Read in and unpack the user-supplied nvlist. + */ + if (nvsize == 0) + return (EINVAL); + +#ifdef _KERNEL + packed = kmem_alloc(nvsize, KM_SLEEP); + if ((err = ddi_copyin((void *)(uintptr_t)nvl, packed, nvsize, + iflag)) != 0) { + kmem_free(packed, nvsize); + return (err); + } +#else + packed = (void *)(uintptr_t)nvl; +#endif + + err = nvlist_unpack(packed, nvsize, &list, 0); + +#ifdef _KERNEL + kmem_free(packed, nvsize); +#endif + + if (err != 0) + return (err); + + *nvp = list; + return (0); +} + +static int zfs_ioctl_compat_write_nvlist_dst(zfs_cmd_t *zc, nvlist_t *nvl, size_t nvsize) { - char *packed = (void *)(uintptr_t)zc->zc_nvlist_dst; + char *packed; int err; +#ifdef _KERNEL + packed = kmem_alloc(nvsize, KM_SLEEP); +#else + packed = (void *)(uintptr_t)zc->zc_nvlist_dst; +#endif + err = nvlist_pack(nvl, &packed, &nvsize, NV_ENCODE_NATIVE, 0); if (err == 0) zc->zc_nvlist_dst_size = nvsize; +#ifdef _KERNEL + if (err == 0 && ddi_copyout(packed, + (void *)(uintptr_t)zc->zc_nvlist_dst, nvsize, zc->zc_iflags) != 0) + err = EFAULT; + kmem_free(packed, nvsize); +#endif + return (err); } @@ -213,8 +264,8 @@ zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const in size_t nvsize; char *packed; - if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst, - zc->zc_nvlist_dst_size, &nv, 0) != 0) + if (zfs_ioctl_compat_read_nvlist_dst(zc->zc_nvlist_dst, + zc->zc_nvlist_dst_size, zc->zc_iflags, &nv) != 0) return; if (cflag == 5) { /* ZFS_IOC_POOL_STATS */ @@ -239,8 +290,8 @@ zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc) nvlist_t *nv, *nva = NULL; size_t nvsize; - if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst, - zc->zc_nvlist_dst_size, &nv, 0) != 0) + if (zfs_ioctl_compat_read_nvlist_dst(zc->zc_nvlist_dst, + zc->zc_nvlist_dst_size, zc->zc_iflags, &nv) != 0) return; #ifdef _KERNEL