Skip to content

Commit

Permalink
[XFS] Move copy_from_user calls out of ioctl helpers into ioctl switch.
Browse files Browse the repository at this point in the history
Moving the copy_from_user out of some of the ioctl helpers will
make it easier for the compat ioctl switch to copy in the right
struct, then just pass to the underlying helper.

Also, move common access checks into the helpers themselves,
and out of the native ioctl switch code, to reduce code
duplication between native & compat ioctl callers.

Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
  • Loading branch information
sandeen@sandeen.net authored and Lachlan McIlroy committed Dec 2, 2008
1 parent 0e44667 commit 743bb46
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 64 deletions.
109 changes: 53 additions & 56 deletions fs/xfs/linux-2.6/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,19 @@
STATIC int
xfs_find_handle(
unsigned int cmd,
void __user *arg)
xfs_fsop_handlereq_t *hreq)
{
int hsize;
xfs_handle_t handle;
xfs_fsop_handlereq_t hreq;
struct inode *inode;

if (copy_from_user(&hreq, arg, sizeof(hreq)))
return -XFS_ERROR(EFAULT);

memset((char *)&handle, 0, sizeof(handle));

switch (cmd) {
case XFS_IOC_PATH_TO_FSHANDLE:
case XFS_IOC_PATH_TO_HANDLE: {
struct path path;
int error = user_lpath((const char __user *)hreq.path, &path);
int error = user_lpath((const char __user *)hreq->path, &path);
if (error)
return error;

Expand All @@ -101,7 +97,7 @@ xfs_find_handle(
case XFS_IOC_FD_TO_HANDLE: {
struct file *file;

file = fget(hreq.fd);
file = fget(hreq->fd);
if (!file)
return -EBADF;

Expand Down Expand Up @@ -158,8 +154,8 @@ xfs_find_handle(
}

/* now copy our handle into the user buffer & write out the size */
if (copy_to_user(hreq.ohandle, &handle, hsize) ||
copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) {
if (copy_to_user(hreq->ohandle, &handle, hsize) ||
copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) {
iput(inode);
return -XFS_ERROR(EFAULT);
}
Expand Down Expand Up @@ -252,7 +248,7 @@ xfs_vget_fsop_handlereq(
STATIC int
xfs_open_by_handle(
xfs_mount_t *mp,
void __user *arg,
xfs_fsop_handlereq_t *hreq,
struct file *parfilp,
struct inode *parinode)
{
Expand All @@ -262,14 +258,11 @@ xfs_open_by_handle(
struct file *filp;
struct inode *inode;
struct dentry *dentry;
xfs_fsop_handlereq_t hreq;

if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);

error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode);
error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode);
if (error)
return -error;

Expand All @@ -280,10 +273,10 @@ xfs_open_by_handle(
}

#if BITS_PER_LONG != 32
hreq.oflags |= O_LARGEFILE;
hreq->oflags |= O_LARGEFILE;
#endif
/* Put open permission in namei format. */
permflag = hreq.oflags;
permflag = hreq->oflags;
if ((permflag+1) & O_ACCMODE)
permflag++;
if (permflag & O_TRUNC)
Expand Down Expand Up @@ -321,7 +314,7 @@ xfs_open_by_handle(
mntget(parfilp->f_path.mnt);

/* Create file pointer. */
filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags);
filp = dentry_open(dentry, parfilp->f_path.mnt, hreq->oflags);
if (IS_ERR(filp)) {
put_unused_fd(new_fd);
return -XFS_ERROR(-PTR_ERR(filp));
Expand Down Expand Up @@ -365,21 +358,18 @@ do_readlink(
STATIC int
xfs_readlink_by_handle(
xfs_mount_t *mp,
void __user *arg,
xfs_fsop_handlereq_t *hreq,
struct inode *parinode)
{
struct inode *inode;
xfs_fsop_handlereq_t hreq;
__u32 olen;
void *link;
int error;

if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);

error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode);
error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode);
if (error)
return -error;

Expand All @@ -389,7 +379,7 @@ xfs_readlink_by_handle(
goto out_iput;
}

if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) {
error = -XFS_ERROR(EFAULT);
goto out_iput;
}
Expand All @@ -401,7 +391,7 @@ xfs_readlink_by_handle(
error = -xfs_readlink(XFS_I(inode), link);
if (error)
goto out_kfree;
error = do_readlink(hreq.ohandle, olen, link);
error = do_readlink(hreq->ohandle, olen, link);
if (error)
goto out_kfree;

Expand Down Expand Up @@ -668,12 +658,19 @@ xfs_ioc_space(
struct file *filp,
int ioflags,
unsigned int cmd,
void __user *arg)
xfs_flock64_t *bf)
{
xfs_flock64_t bf;
int attr_flags = 0;
int error;

/*
* Only allow the sys admin to reserve space unless
* unwritten extents are enabled.
*/
if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) &&
!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);

if (inode->i_flags & (S_IMMUTABLE|S_APPEND))
return -XFS_ERROR(EPERM);

Expand All @@ -683,15 +680,12 @@ xfs_ioc_space(
if (!S_ISREG(inode->i_mode))
return -XFS_ERROR(EINVAL);

if (copy_from_user(&bf, arg, sizeof(bf)))
return -XFS_ERROR(EFAULT);

if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
attr_flags |= XFS_ATTR_NONBLOCK;
if (ioflags & IO_INVIS)
attr_flags |= XFS_ATTR_DMI;

error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, attr_flags);
error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags);
return -error;
}

Expand Down Expand Up @@ -1356,17 +1350,13 @@ xfs_ioctl(
case XFS_IOC_ALLOCSP64:
case XFS_IOC_FREESP64:
case XFS_IOC_RESVSP64:
case XFS_IOC_UNRESVSP64:
/*
* Only allow the sys admin to reserve space unless
* unwritten extents are enabled.
*/
if (!xfs_sb_version_hasextflgbit(&mp->m_sb) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;

return xfs_ioc_space(ip, inode, filp, ioflags, cmd, arg);
case XFS_IOC_UNRESVSP64: {
xfs_flock64_t bf;

if (copy_from_user(&bf, arg, sizeof(bf)))
return -XFS_ERROR(EFAULT);
return xfs_ioc_space(ip, inode, filp, ioflags, cmd, &bf);
}
case XFS_IOC_DIOINFO: {
struct dioattr da;
xfs_buftarg_t *target =
Expand Down Expand Up @@ -1426,26 +1416,42 @@ xfs_ioctl(

case XFS_IOC_FD_TO_HANDLE:
case XFS_IOC_PATH_TO_HANDLE:
case XFS_IOC_PATH_TO_FSHANDLE:
return xfs_find_handle(cmd, arg);
case XFS_IOC_PATH_TO_FSHANDLE: {
xfs_fsop_handlereq_t hreq;

case XFS_IOC_OPEN_BY_HANDLE:
return xfs_open_by_handle(mp, arg, filp, inode);
if (copy_from_user(&hreq, arg, sizeof(hreq)))
return -XFS_ERROR(EFAULT);
return xfs_find_handle(cmd, &hreq);
}
case XFS_IOC_OPEN_BY_HANDLE: {
xfs_fsop_handlereq_t hreq;

if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);
return xfs_open_by_handle(mp, &hreq, filp, inode);
}
case XFS_IOC_FSSETDM_BY_HANDLE:
return xfs_fssetdm_by_handle(mp, arg, inode);

case XFS_IOC_READLINK_BY_HANDLE:
return xfs_readlink_by_handle(mp, arg, inode);
case XFS_IOC_READLINK_BY_HANDLE: {
xfs_fsop_handlereq_t hreq;

if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);
return xfs_readlink_by_handle(mp, &hreq, inode);
}
case XFS_IOC_ATTRLIST_BY_HANDLE:
return xfs_attrlist_by_handle(mp, arg, inode);

case XFS_IOC_ATTRMULTI_BY_HANDLE:
return xfs_attrmulti_by_handle(mp, arg, filp, inode);

case XFS_IOC_SWAPEXT: {
error = xfs_swapext((struct xfs_swapext __user *)arg);
struct xfs_swapext sxp;

if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t)))
return -XFS_ERROR(EFAULT);
error = xfs_swapext(&sxp);
return -error;
}

Expand Down Expand Up @@ -1501,9 +1507,6 @@ xfs_ioctl(
case XFS_IOC_FSGROWFSDATA: {
xfs_growfs_data_t in;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);

Expand All @@ -1514,9 +1517,6 @@ xfs_ioctl(
case XFS_IOC_FSGROWFSLOG: {
xfs_growfs_log_t in;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);

Expand All @@ -1527,9 +1527,6 @@ xfs_ioctl(
case XFS_IOC_FSGROWFSRT: {
xfs_growfs_rt_t in;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);

Expand Down
8 changes: 1 addition & 7 deletions fs/xfs/xfs_dfrag.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,8 @@
*/
int
xfs_swapext(
xfs_swapext_t __user *sxu)
xfs_swapext_t *sxp)
{
xfs_swapext_t *sxp;
xfs_inode_t *ip, *tip;
struct file *file, *target_file;
int error = 0;
Expand All @@ -62,11 +61,6 @@ xfs_swapext(
goto out;
}

if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) {
error = XFS_ERROR(EFAULT);
goto out_free_sxp;
}

/* Pull information for the target fd */
file = fget((int)sxp->sx_fdtarget);
if (!file) {
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_dfrag.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ typedef struct xfs_swapext
/*
* Syscall interface for xfs_swapext
*/
int xfs_swapext(struct xfs_swapext __user *sx);
int xfs_swapext(struct xfs_swapext *sx);

int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
struct xfs_swapext *sxp);
Expand Down
6 changes: 6 additions & 0 deletions fs/xfs/xfs_fsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,9 @@ xfs_growfs_data(
xfs_growfs_data_t *in)
{
int error;

if (!capable(CAP_SYS_ADMIN))
return XFS_ERROR(EPERM);
if (!mutex_trylock(&mp->m_growlock))
return XFS_ERROR(EWOULDBLOCK);
error = xfs_growfs_data_private(mp, in);
Expand All @@ -448,6 +451,9 @@ xfs_growfs_log(
xfs_growfs_log_t *in)
{
int error;

if (!capable(CAP_SYS_ADMIN))
return XFS_ERROR(EPERM);
if (!mutex_trylock(&mp->m_growlock))
return XFS_ERROR(EWOULDBLOCK);
error = xfs_growfs_log_private(mp, in);
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/xfs_rtalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1876,6 +1876,8 @@ xfs_growfs_rt(
/*
* Initial error checking.
*/
if (!capable(CAP_SYS_ADMIN))
return XFS_ERROR(EPERM);
if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL ||
(nrblocks = in->newblocks) <= sbp->sb_rblocks ||
(sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
Expand Down

0 comments on commit 743bb46

Please sign in to comment.