|
@@ -1540,17 +1540,26 @@ out_drop_write:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-STATIC int
|
|
|
-xfs_getbmap_format(void **ap, struct getbmapx *bmv)
|
|
|
+static bool
|
|
|
+xfs_getbmap_format(
|
|
|
+ struct kgetbmap *p,
|
|
|
+ struct getbmapx __user *u,
|
|
|
+ size_t recsize)
|
|
|
{
|
|
|
- struct getbmap __user *base = (struct getbmap __user *)*ap;
|
|
|
-
|
|
|
- /* copy only getbmap portion (not getbmapx) */
|
|
|
- if (copy_to_user(base, bmv, sizeof(struct getbmap)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- *ap += sizeof(struct getbmap);
|
|
|
- return 0;
|
|
|
+ if (put_user(p->bmv_offset, &u->bmv_offset) ||
|
|
|
+ put_user(p->bmv_block, &u->bmv_block) ||
|
|
|
+ put_user(p->bmv_length, &u->bmv_length) ||
|
|
|
+ put_user(0, &u->bmv_count) ||
|
|
|
+ put_user(0, &u->bmv_entries))
|
|
|
+ return false;
|
|
|
+ if (recsize < sizeof(struct getbmapx))
|
|
|
+ return true;
|
|
|
+ if (put_user(0, &u->bmv_iflags) ||
|
|
|
+ put_user(p->bmv_oflags, &u->bmv_oflags) ||
|
|
|
+ put_user(0, &u->bmv_unused1) ||
|
|
|
+ put_user(0, &u->bmv_unused2))
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
STATIC int
|
|
@@ -1560,68 +1569,57 @@ xfs_ioc_getbmap(
|
|
|
void __user *arg)
|
|
|
{
|
|
|
struct getbmapx bmx = { 0 };
|
|
|
- int error;
|
|
|
+ struct kgetbmap *buf;
|
|
|
+ size_t recsize;
|
|
|
+ int error, i;
|
|
|
|
|
|
- /* struct getbmap is a strict subset of struct getbmapx. */
|
|
|
- if (copy_from_user(&bmx, arg, offsetof(struct getbmapx, bmv_iflags)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- if (bmx.bmv_count < 2)
|
|
|
+ switch (cmd) {
|
|
|
+ case XFS_IOC_GETBMAPA:
|
|
|
+ bmx.bmv_iflags = BMV_IF_ATTRFORK;
|
|
|
+ /*FALLTHRU*/
|
|
|
+ case XFS_IOC_GETBMAP:
|
|
|
+ if (file->f_mode & FMODE_NOCMTIME)
|
|
|
+ bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
|
|
|
+ /* struct getbmap is a strict subset of struct getbmapx. */
|
|
|
+ recsize = sizeof(struct getbmap);
|
|
|
+ break;
|
|
|
+ case XFS_IOC_GETBMAPX:
|
|
|
+ recsize = sizeof(struct getbmapx);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
- bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
|
|
|
- if (file->f_mode & FMODE_NOCMTIME)
|
|
|
- bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
|
|
|
-
|
|
|
- error = xfs_getbmap(XFS_I(file_inode(file)), &bmx, xfs_getbmap_format,
|
|
|
- (__force struct getbmap *)arg+1);
|
|
|
- if (error)
|
|
|
- return error;
|
|
|
-
|
|
|
- /* copy back header - only size of getbmap */
|
|
|
- if (copy_to_user(arg, &bmx, sizeof(struct getbmap)))
|
|
|
- return -EFAULT;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-xfs_getbmapx_format(void **ap, struct getbmapx *bmv)
|
|
|
-{
|
|
|
- struct getbmapx __user *base = (struct getbmapx __user *)*ap;
|
|
|
-
|
|
|
- if (copy_to_user(base, bmv, sizeof(struct getbmapx)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- *ap += sizeof(struct getbmapx);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-xfs_ioc_getbmapx(
|
|
|
- struct xfs_inode *ip,
|
|
|
- void __user *arg)
|
|
|
-{
|
|
|
- struct getbmapx bmx;
|
|
|
- int error;
|
|
|
-
|
|
|
- if (copy_from_user(&bmx, arg, sizeof(bmx)))
|
|
|
+ if (copy_from_user(&bmx, arg, recsize))
|
|
|
return -EFAULT;
|
|
|
|
|
|
if (bmx.bmv_count < 2)
|
|
|
return -EINVAL;
|
|
|
+ if (bmx.bmv_count > ULONG_MAX / recsize)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- if (bmx.bmv_iflags & (~BMV_IF_VALID))
|
|
|
- return -EINVAL;
|
|
|
+ buf = kmem_zalloc_large(bmx.bmv_count * sizeof(*buf), 0);
|
|
|
+ if (!buf)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format,
|
|
|
- (__force struct getbmapx *)arg+1);
|
|
|
+ error = xfs_getbmap(XFS_I(file_inode(file)), &bmx, buf);
|
|
|
if (error)
|
|
|
- return error;
|
|
|
+ goto out_free_buf;
|
|
|
|
|
|
- /* copy back header */
|
|
|
- if (copy_to_user(arg, &bmx, sizeof(struct getbmapx)))
|
|
|
- return -EFAULT;
|
|
|
+ error = -EFAULT;
|
|
|
+ if (copy_to_user(arg, &bmx, recsize))
|
|
|
+ goto out_free_buf;
|
|
|
+ arg += recsize;
|
|
|
+
|
|
|
+ for (i = 0; i < bmx.bmv_entries; i++) {
|
|
|
+ if (!xfs_getbmap_format(buf + i, arg, recsize))
|
|
|
+ goto out_free_buf;
|
|
|
+ arg += recsize;
|
|
|
+ }
|
|
|
|
|
|
+ error = 0;
|
|
|
+out_free_buf:
|
|
|
+ kmem_free(buf);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1878,10 +1876,8 @@ xfs_file_ioctl(
|
|
|
|
|
|
case XFS_IOC_GETBMAP:
|
|
|
case XFS_IOC_GETBMAPA:
|
|
|
- return xfs_ioc_getbmap(filp, cmd, arg);
|
|
|
-
|
|
|
case XFS_IOC_GETBMAPX:
|
|
|
- return xfs_ioc_getbmapx(ip, arg);
|
|
|
+ return xfs_ioc_getbmap(filp, cmd, arg);
|
|
|
|
|
|
case FS_IOC_GETFSMAP:
|
|
|
return xfs_ioc_getfsmap(ip, arg);
|