Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2004-2005 Silicon Graphics, Inc.
0004  * All Rights Reserved.
0005  */
0006 #include <linux/mount.h>
0007 #include <linux/fsmap.h>
0008 #include "xfs.h"
0009 #include "xfs_fs.h"
0010 #include "xfs_shared.h"
0011 #include "xfs_format.h"
0012 #include "xfs_log_format.h"
0013 #include "xfs_trans_resv.h"
0014 #include "xfs_mount.h"
0015 #include "xfs_inode.h"
0016 #include "xfs_iwalk.h"
0017 #include "xfs_itable.h"
0018 #include "xfs_fsops.h"
0019 #include "xfs_rtalloc.h"
0020 #include "xfs_da_format.h"
0021 #include "xfs_da_btree.h"
0022 #include "xfs_attr.h"
0023 #include "xfs_ioctl.h"
0024 #include "xfs_ioctl32.h"
0025 #include "xfs_trace.h"
0026 #include "xfs_sb.h"
0027 
0028 #define  _NATIVE_IOC(cmd, type) \
0029       _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type))
0030 
0031 #ifdef BROKEN_X86_ALIGNMENT
0032 STATIC int
0033 xfs_compat_ioc_fsgeometry_v1(
0034     struct xfs_mount      *mp,
0035     compat_xfs_fsop_geom_v1_t __user *arg32)
0036 {
0037     struct xfs_fsop_geom      fsgeo;
0038 
0039     xfs_fs_geometry(mp, &fsgeo, 3);
0040     /* The 32-bit variant simply has some padding at the end */
0041     if (copy_to_user(arg32, &fsgeo, sizeof(struct compat_xfs_fsop_geom_v1)))
0042         return -EFAULT;
0043     return 0;
0044 }
0045 
0046 STATIC int
0047 xfs_compat_growfs_data_copyin(
0048     struct xfs_growfs_data   *in,
0049     compat_xfs_growfs_data_t __user *arg32)
0050 {
0051     if (get_user(in->newblocks, &arg32->newblocks) ||
0052         get_user(in->imaxpct,   &arg32->imaxpct))
0053         return -EFAULT;
0054     return 0;
0055 }
0056 
0057 STATIC int
0058 xfs_compat_growfs_rt_copyin(
0059     struct xfs_growfs_rt     *in,
0060     compat_xfs_growfs_rt_t  __user *arg32)
0061 {
0062     if (get_user(in->newblocks, &arg32->newblocks) ||
0063         get_user(in->extsize,   &arg32->extsize))
0064         return -EFAULT;
0065     return 0;
0066 }
0067 
0068 STATIC int
0069 xfs_fsinumbers_fmt_compat(
0070     struct xfs_ibulk        *breq,
0071     const struct xfs_inumbers   *ig)
0072 {
0073     struct compat_xfs_inogrp __user *p32 = breq->ubuffer;
0074     struct xfs_inogrp       ig1;
0075     struct xfs_inogrp       *igrp = &ig1;
0076 
0077     xfs_inumbers_to_inogrp(&ig1, ig);
0078 
0079     if (put_user(igrp->xi_startino,   &p32->xi_startino) ||
0080         put_user(igrp->xi_alloccount, &p32->xi_alloccount) ||
0081         put_user(igrp->xi_allocmask,  &p32->xi_allocmask))
0082         return -EFAULT;
0083 
0084     return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_inogrp));
0085 }
0086 
0087 #else
0088 #define xfs_fsinumbers_fmt_compat xfs_fsinumbers_fmt
0089 #endif  /* BROKEN_X86_ALIGNMENT */
0090 
0091 STATIC int
0092 xfs_ioctl32_bstime_copyin(
0093     xfs_bstime_t        *bstime,
0094     compat_xfs_bstime_t __user *bstime32)
0095 {
0096     old_time32_t        sec32;  /* tv_sec differs on 64 vs. 32 */
0097 
0098     if (get_user(sec32,     &bstime32->tv_sec)  ||
0099         get_user(bstime->tv_nsec,   &bstime32->tv_nsec))
0100         return -EFAULT;
0101     bstime->tv_sec = sec32;
0102     return 0;
0103 }
0104 
0105 /*
0106  * struct xfs_bstat has differing alignment on intel, & bstime_t sizes
0107  * everywhere
0108  */
0109 STATIC int
0110 xfs_ioctl32_bstat_copyin(
0111     struct xfs_bstat        *bstat,
0112     struct compat_xfs_bstat __user  *bstat32)
0113 {
0114     if (get_user(bstat->bs_ino, &bstat32->bs_ino)   ||
0115         get_user(bstat->bs_mode,    &bstat32->bs_mode)  ||
0116         get_user(bstat->bs_nlink,   &bstat32->bs_nlink) ||
0117         get_user(bstat->bs_uid, &bstat32->bs_uid)   ||
0118         get_user(bstat->bs_gid, &bstat32->bs_gid)   ||
0119         get_user(bstat->bs_rdev,    &bstat32->bs_rdev)  ||
0120         get_user(bstat->bs_blksize, &bstat32->bs_blksize)   ||
0121         get_user(bstat->bs_size,    &bstat32->bs_size)  ||
0122         xfs_ioctl32_bstime_copyin(&bstat->bs_atime, &bstat32->bs_atime) ||
0123         xfs_ioctl32_bstime_copyin(&bstat->bs_mtime, &bstat32->bs_mtime) ||
0124         xfs_ioctl32_bstime_copyin(&bstat->bs_ctime, &bstat32->bs_ctime) ||
0125         get_user(bstat->bs_blocks,  &bstat32->bs_size)  ||
0126         get_user(bstat->bs_xflags,  &bstat32->bs_size)  ||
0127         get_user(bstat->bs_extsize, &bstat32->bs_extsize)   ||
0128         get_user(bstat->bs_extents, &bstat32->bs_extents)   ||
0129         get_user(bstat->bs_gen, &bstat32->bs_gen)   ||
0130         get_user(bstat->bs_projid_lo, &bstat32->bs_projid_lo) ||
0131         get_user(bstat->bs_projid_hi, &bstat32->bs_projid_hi) ||
0132         get_user(bstat->bs_forkoff, &bstat32->bs_forkoff)   ||
0133         get_user(bstat->bs_dmevmask, &bstat32->bs_dmevmask) ||
0134         get_user(bstat->bs_dmstate, &bstat32->bs_dmstate)   ||
0135         get_user(bstat->bs_aextents, &bstat32->bs_aextents))
0136         return -EFAULT;
0137     return 0;
0138 }
0139 
0140 /* XFS_IOC_FSBULKSTAT and friends */
0141 
0142 STATIC int
0143 xfs_bstime_store_compat(
0144     compat_xfs_bstime_t __user *p32,
0145     const xfs_bstime_t  *p)
0146 {
0147     __s32           sec32;
0148 
0149     sec32 = p->tv_sec;
0150     if (put_user(sec32, &p32->tv_sec) ||
0151         put_user(p->tv_nsec, &p32->tv_nsec))
0152         return -EFAULT;
0153     return 0;
0154 }
0155 
0156 /* Return 0 on success or positive error (to xfs_bulkstat()) */
0157 STATIC int
0158 xfs_fsbulkstat_one_fmt_compat(
0159     struct xfs_ibulk        *breq,
0160     const struct xfs_bulkstat   *bstat)
0161 {
0162     struct compat_xfs_bstat __user  *p32 = breq->ubuffer;
0163     struct xfs_bstat        bs1;
0164     struct xfs_bstat        *buffer = &bs1;
0165 
0166     xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
0167 
0168     if (put_user(buffer->bs_ino,      &p32->bs_ino)     ||
0169         put_user(buffer->bs_mode,     &p32->bs_mode)    ||
0170         put_user(buffer->bs_nlink,    &p32->bs_nlink)   ||
0171         put_user(buffer->bs_uid,      &p32->bs_uid)     ||
0172         put_user(buffer->bs_gid,      &p32->bs_gid)     ||
0173         put_user(buffer->bs_rdev,     &p32->bs_rdev)    ||
0174         put_user(buffer->bs_blksize,  &p32->bs_blksize) ||
0175         put_user(buffer->bs_size,     &p32->bs_size)    ||
0176         xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) ||
0177         xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) ||
0178         xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) ||
0179         put_user(buffer->bs_blocks,   &p32->bs_blocks)  ||
0180         put_user(buffer->bs_xflags,   &p32->bs_xflags)  ||
0181         put_user(buffer->bs_extsize,  &p32->bs_extsize) ||
0182         put_user(buffer->bs_extents,  &p32->bs_extents) ||
0183         put_user(buffer->bs_gen,      &p32->bs_gen)     ||
0184         put_user(buffer->bs_projid,   &p32->bs_projid)  ||
0185         put_user(buffer->bs_projid_hi,  &p32->bs_projid_hi) ||
0186         put_user(buffer->bs_forkoff,  &p32->bs_forkoff) ||
0187         put_user(buffer->bs_dmevmask, &p32->bs_dmevmask)    ||
0188         put_user(buffer->bs_dmstate,  &p32->bs_dmstate) ||
0189         put_user(buffer->bs_aextents, &p32->bs_aextents))
0190         return -EFAULT;
0191 
0192     return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_bstat));
0193 }
0194 
0195 /* copied from xfs_ioctl.c */
0196 STATIC int
0197 xfs_compat_ioc_fsbulkstat(
0198     struct file     *file,
0199     unsigned int          cmd,
0200     struct compat_xfs_fsop_bulkreq __user *p32)
0201 {
0202     struct xfs_mount    *mp = XFS_I(file_inode(file))->i_mount;
0203     u32         addr;
0204     struct xfs_fsop_bulkreq bulkreq;
0205     struct xfs_ibulk    breq = {
0206         .mp     = mp,
0207         .mnt_userns = file_mnt_user_ns(file),
0208         .ocount     = 0,
0209     };
0210     xfs_ino_t       lastino;
0211     int         error;
0212 
0213     /*
0214      * Output structure handling functions.  Depending on the command,
0215      * either the xfs_bstat and xfs_inogrp structures are written out
0216      * to userpace memory via bulkreq.ubuffer.  Normally the compat
0217      * functions and structure size are the correct ones to use ...
0218      */
0219     inumbers_fmt_pf     inumbers_func = xfs_fsinumbers_fmt_compat;
0220     bulkstat_one_fmt_pf bs_one_func = xfs_fsbulkstat_one_fmt_compat;
0221 
0222 #ifdef CONFIG_X86_X32_ABI
0223     if (in_x32_syscall()) {
0224         /*
0225          * ... but on x32 the input xfs_fsop_bulkreq has pointers
0226          * which must be handled in the "compat" (32-bit) way, while
0227          * the xfs_bstat and xfs_inogrp structures follow native 64-
0228          * bit layout convention.  So adjust accordingly, otherwise
0229          * the data written out in compat layout will not match what
0230          * x32 userspace expects.
0231          */
0232         inumbers_func = xfs_fsinumbers_fmt;
0233         bs_one_func = xfs_fsbulkstat_one_fmt;
0234     }
0235 #endif
0236 
0237     /* done = 1 if there are more stats to get and if bulkstat */
0238     /* should be called again (unused here, but used in dmapi) */
0239 
0240     if (!capable(CAP_SYS_ADMIN))
0241         return -EPERM;
0242 
0243     if (xfs_is_shutdown(mp))
0244         return -EIO;
0245 
0246     if (get_user(addr, &p32->lastip))
0247         return -EFAULT;
0248     bulkreq.lastip = compat_ptr(addr);
0249     if (get_user(bulkreq.icount, &p32->icount) ||
0250         get_user(addr, &p32->ubuffer))
0251         return -EFAULT;
0252     bulkreq.ubuffer = compat_ptr(addr);
0253     if (get_user(addr, &p32->ocount))
0254         return -EFAULT;
0255     bulkreq.ocount = compat_ptr(addr);
0256 
0257     if (copy_from_user(&lastino, bulkreq.lastip, sizeof(__s64)))
0258         return -EFAULT;
0259 
0260     if (bulkreq.icount <= 0)
0261         return -EINVAL;
0262 
0263     if (bulkreq.ubuffer == NULL)
0264         return -EINVAL;
0265 
0266     breq.ubuffer = bulkreq.ubuffer;
0267     breq.icount = bulkreq.icount;
0268 
0269     /*
0270      * FSBULKSTAT_SINGLE expects that *lastip contains the inode number
0271      * that we want to stat.  However, FSINUMBERS and FSBULKSTAT expect
0272      * that *lastip contains either zero or the number of the last inode to
0273      * be examined by the previous call and return results starting with
0274      * the next inode after that.  The new bulk request back end functions
0275      * take the inode to start with, so we have to compute the startino
0276      * parameter from lastino to maintain correct function.  lastino == 0
0277      * is a special case because it has traditionally meant "first inode
0278      * in filesystem".
0279      */
0280     if (cmd == XFS_IOC_FSINUMBERS_32) {
0281         breq.startino = lastino ? lastino + 1 : 0;
0282         error = xfs_inumbers(&breq, inumbers_func);
0283         lastino = breq.startino - 1;
0284     } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
0285         breq.startino = lastino;
0286         breq.icount = 1;
0287         error = xfs_bulkstat_one(&breq, bs_one_func);
0288         lastino = breq.startino;
0289     } else if (cmd == XFS_IOC_FSBULKSTAT_32) {
0290         breq.startino = lastino ? lastino + 1 : 0;
0291         error = xfs_bulkstat(&breq, bs_one_func);
0292         lastino = breq.startino - 1;
0293     } else {
0294         error = -EINVAL;
0295     }
0296     if (error)
0297         return error;
0298 
0299     if (bulkreq.lastip != NULL &&
0300         copy_to_user(bulkreq.lastip, &lastino, sizeof(xfs_ino_t)))
0301         return -EFAULT;
0302 
0303     if (bulkreq.ocount != NULL &&
0304         copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
0305         return -EFAULT;
0306 
0307     return 0;
0308 }
0309 
0310 STATIC int
0311 xfs_compat_handlereq_copyin(
0312     xfs_fsop_handlereq_t        *hreq,
0313     compat_xfs_fsop_handlereq_t __user *arg32)
0314 {
0315     compat_xfs_fsop_handlereq_t hreq32;
0316 
0317     if (copy_from_user(&hreq32, arg32, sizeof(compat_xfs_fsop_handlereq_t)))
0318         return -EFAULT;
0319 
0320     hreq->fd = hreq32.fd;
0321     hreq->path = compat_ptr(hreq32.path);
0322     hreq->oflags = hreq32.oflags;
0323     hreq->ihandle = compat_ptr(hreq32.ihandle);
0324     hreq->ihandlen = hreq32.ihandlen;
0325     hreq->ohandle = compat_ptr(hreq32.ohandle);
0326     hreq->ohandlen = compat_ptr(hreq32.ohandlen);
0327 
0328     return 0;
0329 }
0330 
0331 STATIC struct dentry *
0332 xfs_compat_handlereq_to_dentry(
0333     struct file     *parfilp,
0334     compat_xfs_fsop_handlereq_t *hreq)
0335 {
0336     return xfs_handle_to_dentry(parfilp,
0337             compat_ptr(hreq->ihandle), hreq->ihandlen);
0338 }
0339 
0340 STATIC int
0341 xfs_compat_attrlist_by_handle(
0342     struct file     *parfilp,
0343     compat_xfs_fsop_attrlist_handlereq_t __user *p)
0344 {
0345     compat_xfs_fsop_attrlist_handlereq_t al_hreq;
0346     struct dentry       *dentry;
0347     int         error;
0348 
0349     if (!capable(CAP_SYS_ADMIN))
0350         return -EPERM;
0351     if (copy_from_user(&al_hreq, p, sizeof(al_hreq)))
0352         return -EFAULT;
0353 
0354     dentry = xfs_compat_handlereq_to_dentry(parfilp, &al_hreq.hreq);
0355     if (IS_ERR(dentry))
0356         return PTR_ERR(dentry);
0357 
0358     error = xfs_ioc_attr_list(XFS_I(d_inode(dentry)),
0359             compat_ptr(al_hreq.buffer), al_hreq.buflen,
0360             al_hreq.flags, &p->pos);
0361     dput(dentry);
0362     return error;
0363 }
0364 
0365 STATIC int
0366 xfs_compat_attrmulti_by_handle(
0367     struct file             *parfilp,
0368     void                    __user *arg)
0369 {
0370     int                 error;
0371     compat_xfs_attr_multiop_t       *ops;
0372     compat_xfs_fsop_attrmulti_handlereq_t   am_hreq;
0373     struct dentry               *dentry;
0374     unsigned int                i, size;
0375 
0376     if (!capable(CAP_SYS_ADMIN))
0377         return -EPERM;
0378     if (copy_from_user(&am_hreq, arg,
0379                sizeof(compat_xfs_fsop_attrmulti_handlereq_t)))
0380         return -EFAULT;
0381 
0382     /* overflow check */
0383     if (am_hreq.opcount >= INT_MAX / sizeof(compat_xfs_attr_multiop_t))
0384         return -E2BIG;
0385 
0386     dentry = xfs_compat_handlereq_to_dentry(parfilp, &am_hreq.hreq);
0387     if (IS_ERR(dentry))
0388         return PTR_ERR(dentry);
0389 
0390     error = -E2BIG;
0391     size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t);
0392     if (!size || size > 16 * PAGE_SIZE)
0393         goto out_dput;
0394 
0395     ops = memdup_user(compat_ptr(am_hreq.ops), size);
0396     if (IS_ERR(ops)) {
0397         error = PTR_ERR(ops);
0398         goto out_dput;
0399     }
0400 
0401     error = 0;
0402     for (i = 0; i < am_hreq.opcount; i++) {
0403         ops[i].am_error = xfs_ioc_attrmulti_one(parfilp,
0404                 d_inode(dentry), ops[i].am_opcode,
0405                 compat_ptr(ops[i].am_attrname),
0406                 compat_ptr(ops[i].am_attrvalue),
0407                 &ops[i].am_length, ops[i].am_flags);
0408     }
0409 
0410     if (copy_to_user(compat_ptr(am_hreq.ops), ops, size))
0411         error = -EFAULT;
0412 
0413     kfree(ops);
0414  out_dput:
0415     dput(dentry);
0416     return error;
0417 }
0418 
0419 long
0420 xfs_file_compat_ioctl(
0421     struct file     *filp,
0422     unsigned        cmd,
0423     unsigned long       p)
0424 {
0425     struct inode        *inode = file_inode(filp);
0426     struct xfs_inode    *ip = XFS_I(inode);
0427     void            __user *arg = compat_ptr(p);
0428     int         error;
0429 
0430     trace_xfs_file_compat_ioctl(ip);
0431 
0432     switch (cmd) {
0433 #if defined(BROKEN_X86_ALIGNMENT)
0434     case XFS_IOC_FSGEOMETRY_V1_32:
0435         return xfs_compat_ioc_fsgeometry_v1(ip->i_mount, arg);
0436     case XFS_IOC_FSGROWFSDATA_32: {
0437         struct xfs_growfs_data  in;
0438 
0439         if (xfs_compat_growfs_data_copyin(&in, arg))
0440             return -EFAULT;
0441         error = mnt_want_write_file(filp);
0442         if (error)
0443             return error;
0444         error = xfs_growfs_data(ip->i_mount, &in);
0445         mnt_drop_write_file(filp);
0446         return error;
0447     }
0448     case XFS_IOC_FSGROWFSRT_32: {
0449         struct xfs_growfs_rt    in;
0450 
0451         if (xfs_compat_growfs_rt_copyin(&in, arg))
0452             return -EFAULT;
0453         error = mnt_want_write_file(filp);
0454         if (error)
0455             return error;
0456         error = xfs_growfs_rt(ip->i_mount, &in);
0457         mnt_drop_write_file(filp);
0458         return error;
0459     }
0460 #endif
0461     /* long changes size, but xfs only copiese out 32 bits */
0462     case XFS_IOC_GETVERSION_32:
0463         cmd = _NATIVE_IOC(cmd, long);
0464         return xfs_file_ioctl(filp, cmd, p);
0465     case XFS_IOC_SWAPEXT_32: {
0466         struct xfs_swapext    sxp;
0467         struct compat_xfs_swapext __user *sxu = arg;
0468 
0469         /* Bulk copy in up to the sx_stat field, then copy bstat */
0470         if (copy_from_user(&sxp, sxu,
0471                    offsetof(struct xfs_swapext, sx_stat)) ||
0472             xfs_ioctl32_bstat_copyin(&sxp.sx_stat, &sxu->sx_stat))
0473             return -EFAULT;
0474         error = mnt_want_write_file(filp);
0475         if (error)
0476             return error;
0477         error = xfs_ioc_swapext(&sxp);
0478         mnt_drop_write_file(filp);
0479         return error;
0480     }
0481     case XFS_IOC_FSBULKSTAT_32:
0482     case XFS_IOC_FSBULKSTAT_SINGLE_32:
0483     case XFS_IOC_FSINUMBERS_32:
0484         return xfs_compat_ioc_fsbulkstat(filp, cmd, arg);
0485     case XFS_IOC_FD_TO_HANDLE_32:
0486     case XFS_IOC_PATH_TO_HANDLE_32:
0487     case XFS_IOC_PATH_TO_FSHANDLE_32: {
0488         struct xfs_fsop_handlereq   hreq;
0489 
0490         if (xfs_compat_handlereq_copyin(&hreq, arg))
0491             return -EFAULT;
0492         cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq);
0493         return xfs_find_handle(cmd, &hreq);
0494     }
0495     case XFS_IOC_OPEN_BY_HANDLE_32: {
0496         struct xfs_fsop_handlereq   hreq;
0497 
0498         if (xfs_compat_handlereq_copyin(&hreq, arg))
0499             return -EFAULT;
0500         return xfs_open_by_handle(filp, &hreq);
0501     }
0502     case XFS_IOC_READLINK_BY_HANDLE_32: {
0503         struct xfs_fsop_handlereq   hreq;
0504 
0505         if (xfs_compat_handlereq_copyin(&hreq, arg))
0506             return -EFAULT;
0507         return xfs_readlink_by_handle(filp, &hreq);
0508     }
0509     case XFS_IOC_ATTRLIST_BY_HANDLE_32:
0510         return xfs_compat_attrlist_by_handle(filp, arg);
0511     case XFS_IOC_ATTRMULTI_BY_HANDLE_32:
0512         return xfs_compat_attrmulti_by_handle(filp, arg);
0513     default:
0514         /* try the native version */
0515         return xfs_file_ioctl(filp, cmd, (unsigned long)arg);
0516     }
0517 }