2018-06-05 19:42:14 -07:00
// SPDX-License-Identifier: GPL-2.0
2005-04-16 15:20:36 -07:00
/*
2005-11-02 14:58:39 +11:00
* Copyright ( c ) 2004 - 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-16 15:20:36 -07:00
*/
2009-01-19 02:03:03 +01:00
# include <linux/mount.h>
2017-03-28 14:56:37 -07:00
# include <linux/fsmap.h>
2005-04-16 15:20:36 -07:00
# include "xfs.h"
# include "xfs_fs.h"
2019-06-28 19:25:35 -07:00
# include "xfs_shared.h"
2013-10-23 10:51:50 +11:00
# include "xfs_format.h"
2013-10-23 10:50:10 +11:00
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2007-07-11 11:10:19 +10:00
# include "xfs_mount.h"
# include "xfs_inode.h"
# include "xfs_itable.h"
2008-11-25 21:20:08 -06:00
# include "xfs_fsops.h"
2008-11-25 21:20:10 -06:00
# include "xfs_rtalloc.h"
2008-11-25 21:20:14 -06:00
# include "xfs_attr.h"
2008-11-25 21:20:08 -06:00
# include "xfs_ioctl.h"
2007-11-23 16:28:09 +11:00
# include "xfs_ioctl32.h"
2009-12-14 23:14:59 +00:00
# include "xfs_trace.h"
2018-01-08 10:51:27 -08:00
# include "xfs_sb.h"
2005-04-16 15:20:36 -07:00
2005-09-05 08:25:06 +10:00
# define _NATIVE_IOC(cmd, type) \
_IOC ( _IOC_DIR ( cmd ) , _IOC_TYPE ( cmd ) , _IOC_NR ( cmd ) , sizeof ( type ) )
2008-11-25 21:20:07 -06:00
# ifdef BROKEN_X86_ALIGNMENT
2008-11-25 21:20:08 -06:00
STATIC int
xfs_compat_flock64_copyin (
xfs_flock64_t * bf ,
compat_xfs_flock64_t __user * arg32 )
2005-09-05 08:25:06 +10:00
{
2008-11-25 21:20:08 -06:00
if ( get_user ( bf - > l_type , & arg32 - > l_type ) | |
get_user ( bf - > l_whence , & arg32 - > l_whence ) | |
get_user ( bf - > l_start , & arg32 - > l_start ) | |
get_user ( bf - > l_len , & arg32 - > l_len ) | |
get_user ( bf - > l_sysid , & arg32 - > l_sysid ) | |
get_user ( bf - > l_pid , & arg32 - > l_pid ) | |
copy_from_user ( bf - > l_pad , & arg32 - > l_pad , 4 * sizeof ( u32 ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:08 -06:00
return 0 ;
2005-09-05 08:25:06 +10:00
}
2008-11-25 21:20:08 -06:00
STATIC int
xfs_compat_ioc_fsgeometry_v1 (
struct xfs_mount * mp ,
compat_xfs_fsop_geom_v1_t __user * arg32 )
2007-07-11 11:09:57 +10:00
{
2019-04-12 07:41:16 -07:00
struct xfs_fsop_geom fsgeo ;
2007-07-11 11:09:57 +10:00
2019-05-01 20:26:30 -07:00
xfs_fs_geometry ( & mp - > m_sb , & fsgeo , 3 ) ;
2008-11-25 21:20:08 -06:00
/* The 32-bit variant simply has some padding at the end */
if ( copy_to_user ( arg32 , & fsgeo , sizeof ( struct compat_xfs_fsop_geom_v1 ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:08 -06:00
return 0 ;
2007-07-11 11:09:57 +10:00
}
2008-11-25 21:20:10 -06:00
STATIC int
xfs_compat_growfs_data_copyin (
struct xfs_growfs_data * in ,
compat_xfs_growfs_data_t __user * arg32 )
{
if ( get_user ( in - > newblocks , & arg32 - > newblocks ) | |
get_user ( in - > imaxpct , & arg32 - > imaxpct ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:10 -06:00
return 0 ;
}
STATIC int
xfs_compat_growfs_rt_copyin (
struct xfs_growfs_rt * in ,
compat_xfs_growfs_rt_t __user * arg32 )
{
if ( get_user ( in - > newblocks , & arg32 - > newblocks ) | |
get_user ( in - > extsize , & arg32 - > extsize ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:10 -06:00
return 0 ;
}
2008-11-25 21:20:08 -06:00
STATIC int
xfs_inumbers_fmt_compat (
void __user * ubuffer ,
2014-07-24 12:11:47 +10:00
const struct xfs_inogrp * buffer ,
2008-11-25 21:20:08 -06:00
long count ,
long * written )
2007-07-11 11:10:19 +10:00
{
2008-11-25 21:20:08 -06:00
compat_xfs_inogrp_t __user * p32 = ubuffer ;
long i ;
2007-07-11 11:10:19 +10:00
for ( i = 0 ; i < count ; i + + ) {
if ( put_user ( buffer [ i ] . xi_startino , & p32 [ i ] . xi_startino ) | |
put_user ( buffer [ i ] . xi_alloccount , & p32 [ i ] . xi_alloccount ) | |
put_user ( buffer [ i ] . xi_allocmask , & p32 [ i ] . xi_allocmask ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
}
* written = count * sizeof ( * p32 ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
# else
2007-07-11 11:10:19 +10:00
# define xfs_inumbers_fmt_compat xfs_inumbers_fmt
2008-11-25 21:20:17 -06:00
# endif /* BROKEN_X86_ALIGNMENT */
2007-07-11 11:10:19 +10:00
2008-11-25 21:20:09 -06:00
STATIC int
xfs_ioctl32_bstime_copyin (
xfs_bstime_t * bstime ,
compat_xfs_bstime_t __user * bstime32 )
{
compat_time_t sec32 ; /* tv_sec differs on 64 vs. 32 */
if ( get_user ( sec32 , & bstime32 - > tv_sec ) | |
get_user ( bstime - > tv_nsec , & bstime32 - > tv_nsec ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:09 -06:00
bstime - > tv_sec = sec32 ;
return 0 ;
}
/* xfs_bstat_t has differing alignment on intel, & bstime_t sizes everywhere */
STATIC int
xfs_ioctl32_bstat_copyin (
xfs_bstat_t * bstat ,
compat_xfs_bstat_t __user * bstat32 )
{
if ( get_user ( bstat - > bs_ino , & bstat32 - > bs_ino ) | |
get_user ( bstat - > bs_mode , & bstat32 - > bs_mode ) | |
get_user ( bstat - > bs_nlink , & bstat32 - > bs_nlink ) | |
get_user ( bstat - > bs_uid , & bstat32 - > bs_uid ) | |
get_user ( bstat - > bs_gid , & bstat32 - > bs_gid ) | |
get_user ( bstat - > bs_rdev , & bstat32 - > bs_rdev ) | |
get_user ( bstat - > bs_blksize , & bstat32 - > bs_blksize ) | |
get_user ( bstat - > bs_size , & bstat32 - > bs_size ) | |
xfs_ioctl32_bstime_copyin ( & bstat - > bs_atime , & bstat32 - > bs_atime ) | |
xfs_ioctl32_bstime_copyin ( & bstat - > bs_mtime , & bstat32 - > bs_mtime ) | |
xfs_ioctl32_bstime_copyin ( & bstat - > bs_ctime , & bstat32 - > bs_ctime ) | |
get_user ( bstat - > bs_blocks , & bstat32 - > bs_size ) | |
get_user ( bstat - > bs_xflags , & bstat32 - > bs_size ) | |
get_user ( bstat - > bs_extsize , & bstat32 - > bs_extsize ) | |
get_user ( bstat - > bs_extents , & bstat32 - > bs_extents ) | |
get_user ( bstat - > bs_gen , & bstat32 - > bs_gen ) | |
2010-09-26 06:10:18 +00:00
get_user ( bstat - > bs_projid_lo , & bstat32 - > bs_projid_lo ) | |
get_user ( bstat - > bs_projid_hi , & bstat32 - > bs_projid_hi ) | |
2014-10-02 09:17:58 +10:00
get_user ( bstat - > bs_forkoff , & bstat32 - > bs_forkoff ) | |
2008-11-25 21:20:09 -06:00
get_user ( bstat - > bs_dmevmask , & bstat32 - > bs_dmevmask ) | |
get_user ( bstat - > bs_dmstate , & bstat32 - > bs_dmstate ) | |
get_user ( bstat - > bs_aextents , & bstat32 - > bs_aextents ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:09 -06:00
return 0 ;
}
2007-07-11 11:10:19 +10:00
/* XFS_IOC_FSBULKSTAT and friends */
2008-11-25 21:20:08 -06:00
STATIC int
xfs_bstime_store_compat (
compat_xfs_bstime_t __user * p32 ,
const xfs_bstime_t * p )
2007-07-11 11:10:19 +10:00
{
2008-11-25 21:20:08 -06:00
__s32 sec32 ;
2007-07-11 11:10:19 +10:00
sec32 = p - > tv_sec ;
if ( put_user ( sec32 , & p32 - > tv_sec ) | |
put_user ( p - > tv_nsec , & p32 - > tv_nsec ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
return 0 ;
}
2008-11-25 21:20:12 -06:00
/* Return 0 on success or positive error (to xfs_bulkstat()) */
2008-11-25 21:20:08 -06:00
STATIC int
xfs_bulkstat_one_fmt_compat (
2007-07-11 11:10:19 +10:00
void __user * ubuffer ,
2008-11-25 21:20:12 -06:00
int ubsize ,
int * ubused ,
2007-07-11 11:10:19 +10:00
const xfs_bstat_t * buffer )
{
2008-11-25 21:20:08 -06:00
compat_xfs_bstat_t __user * p32 = ubuffer ;
2007-07-11 11:10:19 +10:00
2008-11-25 21:20:12 -06:00
if ( ubsize < sizeof ( * p32 ) )
2014-06-25 14:58:08 +10:00
return - ENOMEM ;
2008-11-25 21:20:12 -06:00
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 ) | |
2007-07-11 11:10:19 +10:00
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 ) | |
2008-11-25 21:20:12 -06:00
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 ) | |
2010-09-26 06:10:18 +00:00
put_user ( buffer - > bs_projid_hi , & p32 - > bs_projid_hi ) | |
2014-10-02 09:17:58 +10:00
put_user ( buffer - > bs_forkoff , & p32 - > bs_forkoff ) | |
2008-11-25 21:20:12 -06:00
put_user ( buffer - > bs_dmevmask , & p32 - > bs_dmevmask ) | |
put_user ( buffer - > bs_dmstate , & p32 - > bs_dmstate ) | |
2007-07-11 11:10:19 +10:00
put_user ( buffer - > bs_aextents , & p32 - > bs_aextents ) )
2014-06-25 14:58:08 +10:00
return - EFAULT ;
2008-11-25 21:20:12 -06:00
if ( ubused )
* ubused = sizeof ( * p32 ) ;
return 0 ;
2007-07-11 11:10:19 +10:00
}
2008-11-25 21:20:11 -06:00
STATIC int
xfs_bulkstat_one_compat (
xfs_mount_t * mp , /* mount point for filesystem */
xfs_ino_t ino , /* inode number to get data for */
void __user * buffer , /* buffer to place output in */
int ubsize , /* size of buffer */
int * ubused , /* bytes used by me */
int * stat ) /* BULKSTAT_RV_... */
{
return xfs_bulkstat_one_int ( mp , ino , buffer , ubsize ,
2010-06-24 11:35:17 +10:00
xfs_bulkstat_one_fmt_compat ,
2010-06-23 18:11:11 +10:00
ubused , stat ) ;
2008-11-25 21:20:11 -06:00
}
2007-07-11 11:10:19 +10:00
/* copied from xfs_ioctl.c */
STATIC int
2008-11-25 21:20:11 -06:00
xfs_compat_ioc_bulkstat (
xfs_mount_t * mp ,
unsigned int cmd ,
compat_xfs_fsop_bulkreq_t __user * p32 )
2005-04-16 15:20:36 -07:00
{
u32 addr ;
2007-07-11 11:10:19 +10:00
xfs_fsop_bulkreq_t bulkreq ;
int count ; /* # of records returned */
xfs_ino_t inlast ; /* last inode number */
int done ;
int error ;
2018-12-17 09:35:27 -08:00
/*
* Output structure handling functions . Depending on the command ,
* either the xfs_bstat and xfs_inogrp structures are written out
* to userpace memory via bulkreq . ubuffer . Normally the compat
* functions and structure size are the correct ones to use . . .
*/
inumbers_fmt_pf inumbers_func = xfs_inumbers_fmt_compat ;
bulkstat_one_pf bs_one_func = xfs_bulkstat_one_compat ;
size_t bs_one_size = sizeof ( struct compat_xfs_bstat ) ;
# ifdef CONFIG_X86_X32
if ( in_x32_syscall ( ) ) {
/*
* . . . but on x32 the input xfs_fsop_bulkreq has pointers
* which must be handled in the " compat " ( 32 - bit ) way , while
* the xfs_bstat and xfs_inogrp structures follow native 64 -
* bit layout convention . So adjust accordingly , otherwise
* the data written out in compat layout will not match what
* x32 userspace expects .
*/
inumbers_func = xfs_inumbers_fmt ;
bs_one_func = xfs_bulkstat_one ;
bs_one_size = sizeof ( struct xfs_bstat ) ;
}
# endif
2007-07-11 11:10:19 +10:00
/* done = 1 if there are more stats to get and if bulkstat */
/* should be called again (unused here, but used in dmapi) */
2005-04-16 15:20:36 -07:00
2007-07-11 11:10:19 +10:00
if ( ! capable ( CAP_SYS_ADMIN ) )
2014-06-22 15:04:54 +10:00
return - EPERM ;
2007-07-11 11:10:19 +10:00
if ( XFS_FORCED_SHUTDOWN ( mp ) )
2014-06-22 15:04:54 +10:00
return - EIO ;
2007-07-11 11:10:19 +10:00
if ( get_user ( addr , & p32 - > lastip ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
bulkreq . lastip = compat_ptr ( addr ) ;
if ( get_user ( bulkreq . icount , & p32 - > icount ) | |
get_user ( addr , & p32 - > ubuffer ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
bulkreq . ubuffer = compat_ptr ( addr ) ;
if ( get_user ( addr , & p32 - > ocount ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
bulkreq . ocount = compat_ptr ( addr ) ;
2005-04-16 15:20:36 -07:00
2007-07-11 11:10:19 +10:00
if ( copy_from_user ( & inlast , bulkreq . lastip , sizeof ( __s64 ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
if ( ( count = bulkreq . icount ) < = 0 )
2014-06-22 15:04:54 +10:00
return - EINVAL ;
2007-07-11 11:10:19 +10:00
2007-11-23 16:30:32 +11:00
if ( bulkreq . ubuffer = = NULL )
2014-06-22 15:04:54 +10:00
return - EINVAL ;
2007-11-23 16:30:32 +11:00
2008-11-25 21:20:13 -06:00
if ( cmd = = XFS_IOC_FSINUMBERS_32 ) {
2007-07-11 11:10:19 +10:00
error = xfs_inumbers ( mp , & inlast , & count ,
2018-12-17 09:35:27 -08:00
bulkreq . ubuffer , inumbers_func ) ;
2008-11-25 21:20:13 -06:00
} else if ( cmd = = XFS_IOC_FSBULKSTAT_SINGLE_32 ) {
int res ;
2018-12-17 09:35:27 -08:00
error = bs_one_func ( mp , inlast , bulkreq . ubuffer ,
bs_one_size , NULL , & res ) ;
2008-11-25 21:20:13 -06:00
} else if ( cmd = = XFS_IOC_FSBULKSTAT_32 ) {
2007-07-11 11:10:19 +10:00
error = xfs_bulkstat ( mp , & inlast , & count ,
2018-12-17 09:35:27 -08:00
bs_one_func , bs_one_size ,
2010-06-23 18:11:11 +10:00
bulkreq . ubuffer , & done ) ;
2008-11-25 21:20:13 -06:00
} else
2014-06-25 14:58:08 +10:00
error = - EINVAL ;
2007-07-11 11:10:19 +10:00
if ( error )
2014-06-25 14:58:08 +10:00
return error ;
2007-07-11 11:10:19 +10:00
if ( bulkreq . ocount ! = NULL ) {
if ( copy_to_user ( bulkreq . lastip , & inlast ,
sizeof ( xfs_ino_t ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
if ( copy_to_user ( bulkreq . ocount , & count , sizeof ( count ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:19 +10:00
}
return 0 ;
2005-04-16 15:20:36 -07:00
}
2007-07-11 11:10:19 +10:00
2008-11-25 21:20:08 -06:00
STATIC int
xfs_compat_handlereq_copyin (
xfs_fsop_handlereq_t * hreq ,
compat_xfs_fsop_handlereq_t __user * arg32 )
2007-07-11 11:10:09 +10:00
{
2008-11-25 21:20:08 -06:00
compat_xfs_fsop_handlereq_t hreq32 ;
if ( copy_from_user ( & hreq32 , arg32 , sizeof ( compat_xfs_fsop_handlereq_t ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:08 -06:00
hreq - > fd = hreq32 . fd ;
hreq - > path = compat_ptr ( hreq32 . path ) ;
hreq - > oflags = hreq32 . oflags ;
hreq - > ihandle = compat_ptr ( hreq32 . ihandle ) ;
hreq - > ihandlen = hreq32 . ihandlen ;
hreq - > ohandle = compat_ptr ( hreq32 . ohandle ) ;
hreq - > ohandlen = compat_ptr ( hreq32 . ohandlen ) ;
return 0 ;
2007-07-11 11:10:09 +10:00
}
2009-01-19 02:02:57 +01:00
STATIC struct dentry *
xfs_compat_handlereq_to_dentry (
struct file * parfilp ,
compat_xfs_fsop_handlereq_t * hreq )
2008-11-25 21:20:14 -06:00
{
2009-01-19 02:02:57 +01:00
return xfs_handle_to_dentry ( parfilp ,
compat_ptr ( hreq - > ihandle ) , hreq - > ihandlen ) ;
2008-11-25 21:20:14 -06:00
}
STATIC int
xfs_compat_attrlist_by_handle (
2009-01-19 02:02:57 +01:00
struct file * parfilp ,
void __user * arg )
2008-11-25 21:20:14 -06:00
{
int error ;
attrlist_cursor_kern_t * cursor ;
2018-12-17 09:35:27 -08:00
compat_xfs_fsop_attrlist_handlereq_t __user * p = arg ;
2008-11-25 21:20:14 -06:00
compat_xfs_fsop_attrlist_handlereq_t al_hreq ;
2009-01-19 02:02:57 +01:00
struct dentry * dentry ;
2008-11-25 21:20:14 -06:00
char * kbuf ;
if ( ! capable ( CAP_SYS_ADMIN ) )
2014-06-22 15:04:54 +10:00
return - EPERM ;
2008-11-25 21:20:14 -06:00
if ( copy_from_user ( & al_hreq , arg ,
sizeof ( compat_xfs_fsop_attrlist_handlereq_t ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2013-10-31 21:00:10 +03:00
if ( al_hreq . buflen < sizeof ( struct attrlist ) | |
2015-10-12 16:02:56 +11:00
al_hreq . buflen > XFS_XATTR_LIST_MAX )
2014-06-22 15:04:54 +10:00
return - EINVAL ;
2008-11-25 21:20:14 -06:00
/*
* Reject flags , only allow namespaces .
*/
if ( al_hreq . flags & ~ ( ATTR_ROOT | ATTR_SECURE ) )
2014-06-22 15:04:54 +10:00
return - EINVAL ;
2008-11-25 21:20:14 -06:00
2009-01-19 02:02:57 +01:00
dentry = xfs_compat_handlereq_to_dentry ( parfilp , & al_hreq . hreq ) ;
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
2008-11-25 21:20:14 -06:00
2009-01-19 02:02:57 +01:00
error = - ENOMEM ;
2013-09-02 20:53:00 +10:00
kbuf = kmem_zalloc_large ( al_hreq . buflen , KM_SLEEP ) ;
if ( ! kbuf )
goto out_dput ;
2008-11-25 21:20:14 -06:00
cursor = ( attrlist_cursor_kern_t * ) & al_hreq . pos ;
2015-03-17 22:25:59 +00:00
error = xfs_attr_list ( XFS_I ( d_inode ( dentry ) ) , kbuf , al_hreq . buflen ,
2008-11-25 21:20:14 -06:00
al_hreq . flags , cursor ) ;
if ( error )
goto out_kfree ;
2018-12-17 09:35:27 -08:00
if ( copy_to_user ( & p - > pos , cursor , sizeof ( attrlist_cursor_kern_t ) ) ) {
error = - EFAULT ;
goto out_kfree ;
}
2008-11-25 21:20:14 -06:00
if ( copy_to_user ( compat_ptr ( al_hreq . buffer ) , kbuf , al_hreq . buflen ) )
error = - EFAULT ;
2013-09-02 20:53:00 +10:00
out_kfree :
kmem_free ( kbuf ) ;
out_dput :
2009-01-19 02:02:57 +01:00
dput ( dentry ) ;
return error ;
2008-11-25 21:20:14 -06:00
}
2008-11-25 21:20:15 -06:00
STATIC int
xfs_compat_attrmulti_by_handle (
2009-01-19 02:02:57 +01:00
struct file * parfilp ,
void __user * arg )
2008-11-25 21:20:15 -06:00
{
int error ;
compat_xfs_attr_multiop_t * ops ;
compat_xfs_fsop_attrmulti_handlereq_t am_hreq ;
2009-01-19 02:02:57 +01:00
struct dentry * dentry ;
2008-11-25 21:20:15 -06:00
unsigned int i , size ;
2010-01-20 10:47:48 +11:00
unsigned char * attr_name ;
2008-11-25 21:20:15 -06:00
if ( ! capable ( CAP_SYS_ADMIN ) )
2014-06-22 15:04:54 +10:00
return - EPERM ;
2008-11-25 21:20:15 -06:00
if ( copy_from_user ( & am_hreq , arg ,
sizeof ( compat_xfs_fsop_attrmulti_handlereq_t ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:15 -06:00
2010-03-23 09:51:22 +11:00
/* overflow check */
if ( am_hreq . opcount > = INT_MAX / sizeof ( compat_xfs_attr_multiop_t ) )
return - E2BIG ;
2009-01-19 02:02:57 +01:00
dentry = xfs_compat_handlereq_to_dentry ( parfilp , & am_hreq . hreq ) ;
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
2008-11-25 21:20:15 -06:00
2014-06-25 14:58:08 +10:00
error = - E2BIG ;
2008-11-25 21:20:15 -06:00
size = am_hreq . opcount * sizeof ( compat_xfs_attr_multiop_t ) ;
if ( ! size | | size > 16 * PAGE_SIZE )
2009-01-19 02:02:57 +01:00
goto out_dput ;
2008-11-25 21:20:15 -06:00
2009-04-08 15:08:04 +08:00
ops = memdup_user ( compat_ptr ( am_hreq . ops ) , size ) ;
if ( IS_ERR ( ops ) ) {
2015-01-22 10:04:24 +11:00
error = PTR_ERR ( ops ) ;
2009-01-19 02:02:57 +01:00
goto out_dput ;
2009-04-08 15:08:04 +08:00
}
2008-11-25 21:20:15 -06:00
2014-06-25 14:58:08 +10:00
error = - ENOMEM ;
2008-11-25 21:20:15 -06:00
attr_name = kmalloc ( MAXNAMELEN , GFP_KERNEL ) ;
if ( ! attr_name )
goto out_kfree_ops ;
error = 0 ;
for ( i = 0 ; i < am_hreq . opcount ; i + + ) {
2010-01-20 10:47:48 +11:00
ops [ i ] . am_error = strncpy_from_user ( ( char * ) attr_name ,
2008-11-25 21:20:15 -06:00
compat_ptr ( ops [ i ] . am_attrname ) ,
MAXNAMELEN ) ;
if ( ops [ i ] . am_error = = 0 | | ops [ i ] . am_error = = MAXNAMELEN )
2014-06-25 14:58:08 +10:00
error = - ERANGE ;
2008-11-25 21:20:15 -06:00
if ( ops [ i ] . am_error < 0 )
break ;
switch ( ops [ i ] . am_opcode ) {
case ATTR_OP_GET :
2009-01-19 02:02:57 +01:00
ops [ i ] . am_error = xfs_attrmulti_attr_get (
2015-03-17 22:25:59 +00:00
d_inode ( dentry ) , attr_name ,
2008-11-25 21:20:15 -06:00
compat_ptr ( ops [ i ] . am_attrvalue ) ,
& ops [ i ] . am_length , ops [ i ] . am_flags ) ;
break ;
case ATTR_OP_SET :
2011-11-23 11:57:51 -05:00
ops [ i ] . am_error = mnt_want_write_file ( parfilp ) ;
2009-01-19 02:03:03 +01:00
if ( ops [ i ] . am_error )
break ;
2009-01-19 02:02:57 +01:00
ops [ i ] . am_error = xfs_attrmulti_attr_set (
2015-03-17 22:25:59 +00:00
d_inode ( dentry ) , attr_name ,
2008-11-25 21:20:15 -06:00
compat_ptr ( ops [ i ] . am_attrvalue ) ,
ops [ i ] . am_length , ops [ i ] . am_flags ) ;
2011-12-09 08:06:57 -05:00
mnt_drop_write_file ( parfilp ) ;
2008-11-25 21:20:15 -06:00
break ;
case ATTR_OP_REMOVE :
2011-11-23 11:57:51 -05:00
ops [ i ] . am_error = mnt_want_write_file ( parfilp ) ;
2009-01-19 02:03:03 +01:00
if ( ops [ i ] . am_error )
break ;
2009-01-19 02:02:57 +01:00
ops [ i ] . am_error = xfs_attrmulti_attr_remove (
2015-03-17 22:25:59 +00:00
d_inode ( dentry ) , attr_name ,
2009-01-19 02:02:57 +01:00
ops [ i ] . am_flags ) ;
2011-12-09 08:06:57 -05:00
mnt_drop_write_file ( parfilp ) ;
2008-11-25 21:20:15 -06:00
break ;
default :
2014-06-25 14:58:08 +10:00
ops [ i ] . am_error = - EINVAL ;
2008-11-25 21:20:15 -06:00
}
}
if ( copy_to_user ( compat_ptr ( am_hreq . ops ) , ops , size ) )
2014-06-25 14:58:08 +10:00
error = - EFAULT ;
2008-11-25 21:20:15 -06:00
kfree ( attr_name ) ;
out_kfree_ops :
kfree ( ops ) ;
2009-01-19 02:02:57 +01:00
out_dput :
dput ( dentry ) ;
2014-06-25 14:58:08 +10:00
return error ;
2008-11-25 21:20:15 -06:00
}
2008-11-25 21:20:16 -06:00
STATIC int
xfs_compat_fssetdm_by_handle (
2009-01-19 02:02:57 +01:00
struct file * parfilp ,
void __user * arg )
2008-11-25 21:20:16 -06:00
{
int error ;
struct fsdmidata fsd ;
compat_xfs_fsop_setdm_handlereq_t dmhreq ;
2009-01-19 02:02:57 +01:00
struct dentry * dentry ;
2008-11-25 21:20:16 -06:00
if ( ! capable ( CAP_MKNOD ) )
2014-06-22 15:04:54 +10:00
return - EPERM ;
2008-11-25 21:20:16 -06:00
if ( copy_from_user ( & dmhreq , arg ,
sizeof ( compat_xfs_fsop_setdm_handlereq_t ) ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2008-11-25 21:20:16 -06:00
2009-01-19 02:02:57 +01:00
dentry = xfs_compat_handlereq_to_dentry ( parfilp , & dmhreq . hreq ) ;
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
2008-11-25 21:20:16 -06:00
2015-03-17 22:25:59 +00:00
if ( IS_IMMUTABLE ( d_inode ( dentry ) ) | | IS_APPEND ( d_inode ( dentry ) ) ) {
2014-06-22 15:04:54 +10:00
error = - EPERM ;
2008-11-25 21:20:16 -06:00
goto out ;
}
if ( copy_from_user ( & fsd , compat_ptr ( dmhreq . data ) , sizeof ( fsd ) ) ) {
2014-06-22 15:04:54 +10:00
error = - EFAULT ;
2008-11-25 21:20:16 -06:00
goto out ;
}
2015-03-17 22:25:59 +00:00
error = xfs_set_dmattrs ( XFS_I ( d_inode ( dentry ) ) , fsd . fsd_dmevmask ,
2008-11-25 21:20:16 -06:00
fsd . fsd_dmstate ) ;
out :
2009-01-19 02:02:57 +01:00
dput ( dentry ) ;
2008-11-25 21:20:16 -06:00
return error ;
}
2008-12-09 04:47:33 -05:00
long
xfs_file_compat_ioctl (
struct file * filp ,
unsigned cmd ,
unsigned long p )
2005-04-16 15:20:36 -07:00
{
2013-01-23 17:07:38 -05:00
struct inode * inode = file_inode ( filp ) ;
2008-12-09 04:47:33 -05:00
struct xfs_inode * ip = XFS_I ( inode ) ;
struct xfs_mount * mp = ip - > i_mount ;
void __user * arg = ( void __user * ) p ;
int error ;
2010-06-24 11:57:09 +10:00
trace_xfs_file_compat_ioctl ( ip ) ;
2005-04-16 15:20:36 -07:00
switch ( cmd ) {
2008-11-25 21:20:17 -06:00
/* No size or alignment issues on any arch */
2005-04-16 15:20:36 -07:00
case XFS_IOC_DIOINFO :
2019-04-12 07:41:16 -07:00
case XFS_IOC_FSGEOMETRY_V4 :
2005-04-16 15:20:36 -07:00
case XFS_IOC_FSGEOMETRY :
2019-04-12 07:41:17 -07:00
case XFS_IOC_AG_GEOMETRY :
2005-04-16 15:20:36 -07:00
case XFS_IOC_FSGETXATTR :
case XFS_IOC_FSSETXATTR :
case XFS_IOC_FSGETXATTRA :
case XFS_IOC_FSSETDM :
case XFS_IOC_GETBMAP :
case XFS_IOC_GETBMAPA :
case XFS_IOC_GETBMAPX :
case XFS_IOC_FSCOUNTS :
case XFS_IOC_SET_RESBLKS :
case XFS_IOC_GET_RESBLKS :
case XFS_IOC_FSGROWFSLOG :
case XFS_IOC_GOINGDOWN :
case XFS_IOC_ERROR_INJECTION :
case XFS_IOC_ERROR_CLEARALL :
2017-03-28 14:56:37 -07:00
case FS_IOC_GETFSMAP :
2017-10-17 21:37:34 -07:00
case XFS_IOC_SCRUB_METADATA :
2008-12-09 04:47:33 -05:00
return xfs_file_ioctl ( filp , cmd , p ) ;
2018-12-17 09:35:27 -08:00
# if !defined(BROKEN_X86_ALIGNMENT) || defined(CONFIG_X86_X32)
/*
* These are handled fine if no alignment issues . To support x32
* which uses native 64 - bit alignment we must emit these cases in
* addition to the ia - 32 compat set below .
*/
2008-11-25 21:20:17 -06:00
case XFS_IOC_ALLOCSP :
case XFS_IOC_FREESP :
case XFS_IOC_RESVSP :
case XFS_IOC_UNRESVSP :
case XFS_IOC_ALLOCSP64 :
case XFS_IOC_FREESP64 :
case XFS_IOC_RESVSP64 :
case XFS_IOC_UNRESVSP64 :
case XFS_IOC_FSGEOMETRY_V1 :
case XFS_IOC_FSGROWFSDATA :
case XFS_IOC_FSGROWFSRT :
2010-08-24 12:02:11 +10:00
case XFS_IOC_ZERO_RANGE :
2018-12-17 09:35:27 -08:00
# ifdef CONFIG_X86_X32
/*
* x32 special : this gets a different cmd number from the ia - 32 compat
* case below ; the associated data will match native 64 - bit alignment .
*/
case XFS_IOC_SWAPEXT :
# endif
2008-12-09 04:47:33 -05:00
return xfs_file_ioctl ( filp , cmd , p ) ;
2018-12-17 09:35:27 -08:00
# endif
# if defined(BROKEN_X86_ALIGNMENT)
2005-09-05 08:25:06 +10:00
case XFS_IOC_ALLOCSP_32 :
case XFS_IOC_FREESP_32 :
case XFS_IOC_ALLOCSP64_32 :
case XFS_IOC_FREESP64_32 :
case XFS_IOC_RESVSP_32 :
case XFS_IOC_UNRESVSP_32 :
case XFS_IOC_RESVSP64_32 :
2011-04-21 13:21:03 +00:00
case XFS_IOC_UNRESVSP64_32 :
case XFS_IOC_ZERO_RANGE_32 : {
2008-11-25 21:20:08 -06:00
struct xfs_flock64 bf ;
if ( xfs_compat_flock64_copyin ( & bf , arg ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2005-09-05 08:25:06 +10:00
cmd = _NATIVE_IOC ( cmd , struct xfs_flock64 ) ;
2016-07-20 11:29:35 +10:00
return xfs_ioc_space ( filp , cmd , & bf ) ;
2008-11-25 21:20:08 -06:00
}
2007-07-11 11:09:57 +10:00
case XFS_IOC_FSGEOMETRY_V1_32 :
2008-11-25 21:20:08 -06:00
return xfs_compat_ioc_fsgeometry_v1 ( mp , arg ) ;
2008-11-25 21:20:10 -06:00
case XFS_IOC_FSGROWFSDATA_32 : {
struct xfs_growfs_data in ;
if ( xfs_compat_growfs_data_copyin ( & in , arg ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2012-06-12 16:20:39 +02:00
error = mnt_want_write_file ( filp ) ;
if ( error )
return error ;
2008-11-25 21:20:10 -06:00
error = xfs_growfs_data ( mp , & in ) ;
2012-06-12 16:20:39 +02:00
mnt_drop_write_file ( filp ) ;
2014-06-25 14:58:08 +10:00
return error ;
2008-11-25 21:20:10 -06:00
}
case XFS_IOC_FSGROWFSRT_32 : {
struct xfs_growfs_rt in ;
if ( xfs_compat_growfs_rt_copyin ( & in , arg ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2012-06-12 16:20:39 +02:00
error = mnt_want_write_file ( filp ) ;
if ( error )
return error ;
2008-11-25 21:20:10 -06:00
error = xfs_growfs_rt ( mp , & in ) ;
2012-06-12 16:20:39 +02:00
mnt_drop_write_file ( filp ) ;
2014-06-25 14:58:08 +10:00
return error ;
2008-11-25 21:20:10 -06:00
}
2005-04-16 15:20:36 -07:00
# endif
2008-11-25 21:20:17 -06:00
/* long changes size, but xfs only copiese out 32 bits */
case XFS_IOC_GETXFLAGS_32 :
case XFS_IOC_SETXFLAGS_32 :
case XFS_IOC_GETVERSION_32 :
cmd = _NATIVE_IOC ( cmd , long ) ;
2008-12-09 04:47:33 -05:00
return xfs_file_ioctl ( filp , cmd , p ) ;
2009-09-01 14:03:08 -04:00
case XFS_IOC_SWAPEXT_32 : {
2008-11-25 21:20:17 -06:00
struct xfs_swapext sxp ;
struct compat_xfs_swapext __user * sxu = arg ;
/* Bulk copy in up to the sx_stat field, then copy bstat */
if ( copy_from_user ( & sxp , sxu ,
offsetof ( struct xfs_swapext , sx_stat ) ) | |
xfs_ioctl32_bstat_copyin ( & sxp . sx_stat , & sxu - > sx_stat ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2012-06-12 16:20:39 +02:00
error = mnt_want_write_file ( filp ) ;
if ( error )
return error ;
2013-08-12 20:49:48 +10:00
error = xfs_ioc_swapext ( & sxp ) ;
2012-06-12 16:20:39 +02:00
mnt_drop_write_file ( filp ) ;
2014-06-25 14:58:08 +10:00
return error ;
2008-11-25 21:20:17 -06:00
}
2007-07-11 11:10:19 +10:00
case XFS_IOC_FSBULKSTAT_32 :
case XFS_IOC_FSBULKSTAT_SINGLE_32 :
case XFS_IOC_FSINUMBERS_32 :
2008-11-25 21:20:11 -06:00
return xfs_compat_ioc_bulkstat ( mp , cmd , arg ) ;
2007-07-11 11:10:09 +10:00
case XFS_IOC_FD_TO_HANDLE_32 :
case XFS_IOC_PATH_TO_HANDLE_32 :
2008-11-25 21:20:08 -06:00
case XFS_IOC_PATH_TO_FSHANDLE_32 : {
struct xfs_fsop_handlereq hreq ;
if ( xfs_compat_handlereq_copyin ( & hreq , arg ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2007-07-11 11:10:09 +10:00
cmd = _NATIVE_IOC ( cmd , struct xfs_fsop_handlereq ) ;
2008-11-25 21:20:08 -06:00
return xfs_find_handle ( cmd , & hreq ) ;
}
case XFS_IOC_OPEN_BY_HANDLE_32 : {
struct xfs_fsop_handlereq hreq ;
if ( xfs_compat_handlereq_copyin ( & hreq , arg ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2009-01-19 02:02:57 +01:00
return xfs_open_by_handle ( filp , & hreq ) ;
2008-11-25 21:20:08 -06:00
}
case XFS_IOC_READLINK_BY_HANDLE_32 : {
struct xfs_fsop_handlereq hreq ;
if ( xfs_compat_handlereq_copyin ( & hreq , arg ) )
2014-06-22 15:04:54 +10:00
return - EFAULT ;
2009-01-19 02:02:57 +01:00
return xfs_readlink_by_handle ( filp , & hreq ) ;
2008-11-25 21:20:08 -06:00
}
2008-11-25 21:20:14 -06:00
case XFS_IOC_ATTRLIST_BY_HANDLE_32 :
2009-01-19 02:02:57 +01:00
return xfs_compat_attrlist_by_handle ( filp , arg ) ;
2008-11-25 21:20:15 -06:00
case XFS_IOC_ATTRMULTI_BY_HANDLE_32 :
2009-01-19 02:02:57 +01:00
return xfs_compat_attrmulti_by_handle ( filp , arg ) ;
2008-11-25 21:20:16 -06:00
case XFS_IOC_FSSETDM_BY_HANDLE_32 :
2009-01-19 02:02:57 +01:00
return xfs_compat_fssetdm_by_handle ( filp , arg ) ;
2005-04-16 15:20:36 -07:00
default :
2014-06-22 15:04:54 +10:00
return - ENOIOCTLCMD ;
2005-04-16 15:20:36 -07:00
}
}