diff --git a/include/sys/zfs_ioctl_impl.h b/include/sys/zfs_ioctl_impl.h index 0c59441d50..a59cfa1673 100644 --- a/include/sys/zfs_ioctl_impl.h +++ b/include/sys/zfs_ioctl_impl.h @@ -84,7 +84,7 @@ void zfs_ioctl_init_os(void); int zfs_vfs_ref(zfsvfs_t **); -long zfsdev_ioctl_common(uint_t, unsigned long); +long zfsdev_ioctl_common(uint_t, zfs_cmd_t *); int zfsdev_attach(void); void zfsdev_detach(void); int zfs_kmod_init(void); diff --git a/module/os/linux/zfs/zfs_ioctl_os.c b/module/os/linux/zfs/zfs_ioctl_os.c index fa47c30eae..2960832a59 100644 --- a/module/os/linux/zfs/zfs_ioctl_os.c +++ b/module/os/linux/zfs/zfs_ioctl_os.c @@ -168,9 +168,25 @@ static long zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg) { uint_t vecnum; + zfs_cmd_t *zc; + int error, rc; vecnum = cmd - ZFS_IOC_FIRST; - return (zfsdev_ioctl_common(vecnum, arg)); + + zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); + + if (ddi_copyin((void *)(uintptr_t)arg, zc, sizeof (zfs_cmd_t), 0)) { + error = -SET_ERROR(EFAULT); + goto out; + } + error = -zfsdev_ioctl_common(vecnum, zc); + rc = ddi_copyout(zc, (void *)(uintptr_t)arg, sizeof (zfs_cmd_t), 0); + if (error == 0 && rc != 0) + error = -SET_ERROR(EFAULT); +out: + kmem_free(zc, sizeof (zfs_cmd_t)); + return (error); + } int diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 902c0b2b2a..a993d02e13 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -7215,18 +7215,19 @@ zfsdev_minor_alloc(void) } long -zfsdev_ioctl_common(uint_t vecnum, unsigned long arg) +zfsdev_ioctl_common(uint_t vecnum, zfs_cmd_t *zc) { - zfs_cmd_t *zc; - int error, cmd, rc, flag = 0; + int error, cmd, flag = 0; const zfs_ioc_vec_t *vec; char *saved_poolname = NULL; nvlist_t *innvl = NULL; fstrans_cookie_t cookie; cmd = vecnum; + error = 0; if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) - return (-SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL)); + return (SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL)); + vec = &zfs_ioc_vec[vecnum]; /* @@ -7234,16 +7235,7 @@ zfsdev_ioctl_common(uint_t vecnum, unsigned long arg) * a normal or legacy handler are registered. */ if (vec->zvec_func == NULL && vec->zvec_legacy_func == NULL) - return (-SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL)); - - zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); - - error = ddi_copyin((void *)(uintptr_t)arg, zc, sizeof (zfs_cmd_t), - flag); - if (error != 0) { - error = SET_ERROR(EFAULT); - goto out; - } + return (SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL)); zc->zc_iflags = flag & FKIOCTL; if (zc->zc_nvlist_src_size > MAX_NVLIST_SRC_SIZE) { @@ -7406,9 +7398,6 @@ zfsdev_ioctl_common(uint_t vecnum, unsigned long arg) out: nvlist_free(innvl); - rc = ddi_copyout(zc, (void *)(uintptr_t)arg, sizeof (zfs_cmd_t), flag); - if (error == 0 && rc != 0) - error = SET_ERROR(EFAULT); if (error == 0 && vec->zvec_allow_log) { char *s = tsd_get(zfs_allow_log_key); if (s != NULL) @@ -7418,9 +7407,7 @@ out: if (saved_poolname != NULL) kmem_strfree(saved_poolname); } - - kmem_free(zc, sizeof (zfs_cmd_t)); - return (-error); + return (error); } int