Skip to content

Commit

Permalink
[XFS] Fix xfs_bulkstat_one size checks & error handling
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Lachlan McIlroy <[email protected]>
  • Loading branch information
sandeen authored and Lachlan McIlroy committed Dec 2, 2008
1 parent 2ee4fa5 commit 65fbaf2
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 28 deletions.
44 changes: 26 additions & 18 deletions fs/xfs/linux-2.6/xfs_ioctl32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 11 additions & 10 deletions fs/xfs/xfs_itable.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/*
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/xfs_itable.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 65fbaf2

Please sign in to comment.