lkml.org 
[lkml]   [2019]   [Oct]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v6 41/43] compat_ioctl: move SG_GET_REQUEST_TABLE handling
    Date
    SG_GET_REQUEST_TABLE is now the last ioctl command that needs a conversion
    handler. This is only used in a single file, so the implementation should
    be there.

    I'm trying to simplify it in the process, to get rid of
    the compat_alloc_user_space() and extra copy, by adding a
    put_compat_request_table() function instead, which copies the data in
    the right format to user space.

    Cc: linux-scsi@vger.kernel.org
    Cc: Doug Gilbert <dgilbert@interlog.com>
    Cc: "James E.J. Bottomley" <jejb@linux.ibm.com>
    Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
    Signed-off-by: Arnd Bergmann <arnd@arndb.de>
    ---
    drivers/scsi/sg.c | 40 ++++++++++++++++++++++++++++-----
    fs/compat_ioctl.c | 57 +----------------------------------------------
    2 files changed, 36 insertions(+), 61 deletions(-)

    diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
    index 8ae096af2667..9e4ef22b3579 100644
    --- a/drivers/scsi/sg.c
    +++ b/drivers/scsi/sg.c
    @@ -889,6 +889,33 @@ sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
    }
    }

    +#ifdef CONFIG_COMPAT
    +struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
    + char req_state;
    + char orphan;
    + char sg_io_owned;
    + char problem;
    + int pack_id;
    + compat_uptr_t usr_ptr;
    + unsigned int duration;
    + int unused;
    +};
    +
    +static int put_compat_request_table(struct compat_sg_req_info __user *o,
    + struct sg_req_info *rinfo)
    +{
    + int i;
    + for (i = 0; i < SG_MAX_QUEUE; i++) {
    + if (copy_to_user(o + i, rinfo + i, offsetof(sg_req_info_t, usr_ptr)) ||
    + put_user((uintptr_t)rinfo[i].usr_ptr, &o[i].usr_ptr) ||
    + put_user(rinfo[i].duration, &o[i].duration) ||
    + put_user(rinfo[i].unused, &o[i].unused))
    + return -EFAULT;
    + }
    + return 0;
    +}
    +#endif
    +
    static long
    sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
    {
    @@ -1069,9 +1096,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
    val = (sdp->device ? 1 : 0);
    return put_user(val, ip);
    case SG_GET_REQUEST_TABLE:
    - if (!access_ok(p, SZ_SG_REQ_INFO * SG_MAX_QUEUE))
    - return -EFAULT;
    - else {
    + {
    sg_req_info_t *rinfo;

    rinfo = kcalloc(SG_MAX_QUEUE, SZ_SG_REQ_INFO,
    @@ -1081,8 +1106,13 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
    read_lock_irqsave(&sfp->rq_list_lock, iflags);
    sg_fill_request_table(sfp, rinfo);
    read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
    - result = __copy_to_user(p, rinfo,
    - SZ_SG_REQ_INFO * SG_MAX_QUEUE);
    + #ifdef CONFIG_COMPAT
    + if (in_compat_syscall())
    + result = put_compat_request_table(p, rinfo);
    + else
    + #endif
    + result = copy_to_user(p, rinfo,
    + SZ_SG_REQ_INFO * SG_MAX_QUEUE);
    result = result ? -EFAULT : 0;
    kfree(rinfo);
    return result;
    diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
    index 3cf8b6d113c3..9ae90d728c0f 100644
    --- a/fs/compat_ioctl.c
    +++ b/fs/compat_ioctl.c
    @@ -52,53 +52,6 @@

    #include <linux/sort.h>

    -#ifdef CONFIG_BLOCK
    -static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    -{
    - int err;
    -
    - err = security_file_ioctl(file, cmd, arg);
    - if (err)
    - return err;
    -
    - return vfs_ioctl(file, cmd, arg);
    -}
    -
    -struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
    - char req_state;
    - char orphan;
    - char sg_io_owned;
    - char problem;
    - int pack_id;
    - compat_uptr_t usr_ptr;
    - unsigned int duration;
    - int unused;
    -};
    -
    -static int sg_grt_trans(struct file *file,
    - unsigned int cmd, struct compat_sg_req_info __user *o)
    -{
    - int err, i;
    - sg_req_info_t __user *r;
    - r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE);
    - err = do_ioctl(file, cmd, (unsigned long)r);
    - if (err < 0)
    - return err;
    - for (i = 0; i < SG_MAX_QUEUE; i++) {
    - void __user *ptr;
    - int d;
    -
    - if (copy_in_user(o + i, r + i, offsetof(sg_req_info_t, usr_ptr)) ||
    - get_user(ptr, &r[i].usr_ptr) ||
    - get_user(d, &r[i].duration) ||
    - put_user((u32)(unsigned long)(ptr), &o[i].usr_ptr) ||
    - put_user(d, &o[i].duration))
    - return -EFAULT;
    - }
    - return err;
    -}
    -#endif /* CONFIG_BLOCK */
    -
    /*
    * simple reversible transform to make our table more evenly
    * distributed after sorting.
    @@ -121,6 +74,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
    #ifdef CONFIG_BLOCK
    /* SG stuff */
    COMPATIBLE_IOCTL(SG_IO)
    +COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
    COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
    COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
    COMPATIBLE_IOCTL(SG_EMULATED_HOST)
    @@ -156,15 +110,6 @@ COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
    static long do_ioctl_trans(unsigned int cmd,
    unsigned long arg, struct file *file)
    {
    -#ifdef CONFIG_BLOCK
    - void __user *argp = compat_ptr(arg);
    -
    - switch (cmd) {
    - case SG_GET_REQUEST_TABLE:
    - return sg_grt_trans(file, cmd, argp);
    - }
    -#endif
    -
    return -ENOIOCTLCMD;
    }

    --
    2.20.0
    \
     
     \ /
      Last update: 2019-10-09 21:12    [W:7.445 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site