]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
[XFS] Fix xfs_bulkstat_one size checks & error handling
authorsandeen@sandeen.net <sandeen@sandeen.net>
Wed, 26 Nov 2008 03:20:12 +0000 (21:20 -0600)
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>
Tue, 2 Dec 2008 06:16:03 +0000 (17:16 +1100)
The 32-bit xfs_blkstat_one handler was failing because
a size check checked whether the remaining (32-bit)
user buffer was less than the (64-bit) bulkstat buffer,
and failed with ENOMEM if so.  Move this check
into the respective handlers so that they check the
correct sizes.

Also, the formatters were returning negative errors
or positive bytes copied; this was odd in the positive
error value world of xfs, and handled wrong by at least
some of the callers, which treated the bytes returned
as an error value.  Move the bytes-used assignment
into the formatters.

Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
fs/xfs/linux-2.6/xfs_ioctl32.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_itable.h

index a97022f2d9b0014ebd29e04d52e8393f3eb736d7..2d336062831d8e4ebbeb2a2911d01c845d31bf15 100644 (file)
@@ -192,35 +192,43 @@ xfs_bstime_store_compat(
        return 0;
 }
 
+/* Return 0 on success or positive error (to xfs_bulkstat()) */
 STATIC int
 xfs_bulkstat_one_fmt_compat(
        void                    __user *ubuffer,
+       int                     ubsize,
+       int                     *ubused,
        const xfs_bstat_t       *buffer)
 {
        compat_xfs_bstat_t      __user *p32 = ubuffer;
 
-       if (put_user(buffer->bs_ino, &p32->bs_ino) ||
-           put_user(buffer->bs_mode, &p32->bs_mode) ||
-           put_user(buffer->bs_nlink, &p32->bs_nlink) ||
-           put_user(buffer->bs_uid, &p32->bs_uid) ||
-           put_user(buffer->bs_gid, &p32->bs_gid) ||
-           put_user(buffer->bs_rdev, &p32->bs_rdev) ||
-           put_user(buffer->bs_blksize, &p32->bs_blksize) ||
-           put_user(buffer->bs_size, &p32->bs_size) ||
+       if (ubsize < sizeof(*p32))
+               return XFS_ERROR(ENOMEM);
+
+       if (put_user(buffer->bs_ino,      &p32->bs_ino)         ||
+           put_user(buffer->bs_mode,     &p32->bs_mode)        ||
+           put_user(buffer->bs_nlink,    &p32->bs_nlink)       ||
+           put_user(buffer->bs_uid,      &p32->bs_uid)         ||
+           put_user(buffer->bs_gid,      &p32->bs_gid)         ||
+           put_user(buffer->bs_rdev,     &p32->bs_rdev)        ||
+           put_user(buffer->bs_blksize,  &p32->bs_blksize)     ||
+           put_user(buffer->bs_size,     &p32->bs_size)        ||
            xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) ||
            xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) ||
            xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) ||
-           put_user(buffer->bs_blocks, &p32->bs_blocks) ||
-           put_user(buffer->bs_xflags, &p32->bs_xflags) ||
-           put_user(buffer->bs_extsize, &p32->bs_extsize) ||
-           put_user(buffer->bs_extents, &p32->bs_extents) ||
-           put_user(buffer->bs_gen, &p32->bs_gen) ||
-           put_user(buffer->bs_projid, &p32->bs_projid) ||
-           put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) ||
-           put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
+           put_user(buffer->bs_blocks,   &p32->bs_blocks)      ||
+           put_user(buffer->bs_xflags,   &p32->bs_xflags)      ||
+           put_user(buffer->bs_extsize,  &p32->bs_extsize)     ||
+           put_user(buffer->bs_extents,  &p32->bs_extents)     ||
+           put_user(buffer->bs_gen,      &p32->bs_gen)         ||
+           put_user(buffer->bs_projid,   &p32->bs_projid)      ||
+           put_user(buffer->bs_dmevmask, &p32->bs_dmevmask)    ||
+           put_user(buffer->bs_dmstate,  &p32->bs_dmstate)     ||
            put_user(buffer->bs_aextents, &p32->bs_aextents))
-               return -XFS_ERROR(EFAULT);
-       return sizeof(*p32);
+               return XFS_ERROR(EFAULT);
+       if (ubused)
+               *ubused = sizeof(*p32);
+       return 0;
 }
 
 STATIC int
index 7bd49b87160ce0838bba7b1bd0b1ebc383c4efb0..e19d0a8d5618d934408d5c37086e435a11a5bdb5 100644 (file)
@@ -188,14 +188,21 @@ xfs_bulkstat_one_dinode(
        }
 }
 
+/* Return 0 on success or positive error */
 STATIC int
 xfs_bulkstat_one_fmt(
        void                    __user *ubuffer,
+       int                     ubsize,
+       int                     *ubused,
        const xfs_bstat_t       *buffer)
 {
+       if (ubsize < sizeof(*buffer))
+               return XFS_ERROR(ENOMEM);
        if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))
-               return -EFAULT;
-       return sizeof(*buffer);
+               return XFS_ERROR(EFAULT);
+       if (ubused)
+               *ubused = sizeof(*buffer);
+       return 0;
 }
 
 /*
@@ -223,8 +230,6 @@ xfs_bulkstat_one_int(
 
        if (!buffer || xfs_internal_inum(mp, ino))
                return XFS_ERROR(EINVAL);
-       if (ubsize < sizeof(*buf))
-               return XFS_ERROR(ENOMEM);
 
        buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
 
@@ -239,15 +244,11 @@ xfs_bulkstat_one_int(
                xfs_bulkstat_one_dinode(mp, ino, dip, buf);
        }
 
-       error = formatter(buffer, buf);
-       if (error < 0)  {
-               error = EFAULT;
+       error = formatter(buffer, ubsize, ubused, buf);
+       if (error)
                goto out_free;
-       }
 
        *stat = BULKSTAT_RV_DIDONE;
-       if (ubused)
-               *ubused = error;
 
  out_free:
        kmem_free(buf);
index e210a4c065698e197f66b2fdce1dba1469ddba5d..1fb04e7deb61298d13c4a55db385071b92c3b9a5 100644 (file)
@@ -71,6 +71,8 @@ xfs_bulkstat_single(
 
 typedef int (*bulkstat_one_fmt_pf)(  /* used size in bytes or negative error */
        void                    __user *ubuffer, /* buffer to write to */
+       int                     ubsize,          /* remaining user buffer sz */
+       int                     *ubused,         /* bytes used by formatter */
        const xfs_bstat_t       *buffer);        /* buffer to read from */
 
 int