From patchwork Wed Aug 14 20:49:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 11094579 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1151A13B1 for ; Wed, 14 Aug 2019 20:54:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 003D128848 for ; Wed, 14 Aug 2019 20:54:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E81CA2885E; Wed, 14 Aug 2019 20:54:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 090F128848 for ; Wed, 14 Aug 2019 20:54:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729836AbfHNUyQ (ORCPT ); Wed, 14 Aug 2019 16:54:16 -0400 Received: from mout.kundenserver.de ([212.227.126.135]:42871 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727975AbfHNUyP (ORCPT ); Wed, 14 Aug 2019 16:54:15 -0400 Received: from threadripper.lan ([149.172.19.189]) by mrelayeu.kundenserver.de (mreue012 [212.227.15.129]) with ESMTPA (Nemesis) id 1MnWx3-1ifH7b3rC1-00jcFW; Wed, 14 Aug 2019 22:53:43 +0200 From: Arnd Bergmann To: linux-kernel@vger.kernel.org, viro@zeniv.linux.org.uk, linux-fsdevel@vger.kernel.org, Jens Axboe , Doug Gilbert , "James E.J. Bottomley" , "Martin K. Petersen" Cc: Arnd Bergmann , Chaitanya Kulkarni , Thomas Gleixner , Mauro Carvalho Chehab , Omar Sandoval , linux-block@vger.kernel.org, linux-scsi@vger.kernel.org Subject: [PATCH v5 07/18] compat_ioctl: reimplement SG_IO handling Date: Wed, 14 Aug 2019 22:49:19 +0200 Message-Id: <20190814205245.121691-2-arnd@arndb.de> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20190814204259.120942-1-arnd@arndb.de> References: <20190814204259.120942-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:/JQAz9jbmNi46KdiXkmQBzuzdZGvU7yA4i2fYTIxsCWcn54Byn+ cZSLNL4wecRpJeB91mHzyKN9NNSJ3ULDskRlMVxYXOTO+ptqPBOWuE58W/Zey9cnvoZ/ovy UtgaVm4/NG8hfni+6Js5WJEi9KApQ25Y7TnAG3cmdBsqsQ8OO8jvecnRbTxzrYgpjHl8s0+ 1ND4U/lB+ZPB8uDowQj2A== X-UI-Out-Filterresults: notjunk:1;V03:K0:8FuODb/6KPU=:gOdtUHMZdpbvut9olHBgd6 DkWH+wqXU9cvMxiHCdC7DpM+xeDBjcinYvg6WNWYeaj+wYQbEzD5y2kIWP3/YI+QE8X4JlbWa HHzWST7F5eSSyDYa6Lyqw52NH+kE7eiZrsE9XK6u7RgELNEYIsUPJaNgBLRcHEVaxMmUIsYrF B/0PGqDsjudRd9blhA+aVRqYyOD34HrfPcw9NvRuao434oNgDHXaz3mH0gceEbaDf1NTP4M5w rrAJqJd6Ph/Dq2cOqKVMA1Cj93HScfjd6FKChJzpSKo1uf2Qc+TbstnF17fkRyzaMcERJqafW LKAzVdDVRG+H1nD+8BIIxwzJFBetCVeSsXvXzq4VNE/8R1UxjnePVJCsm53Hfj+qNmlq98xAY zaHRxnP0YfP0JZcv5U53SGBr2kb6jRaFdBSczcpsofU1h94f8BuVhWEMlGCIFMpkiP53xNL0A mYO44gp5h+PsmbqExAuPH0Ib88cJpIpjxWN13J5h4biRGxb/CN7uVR/OfmFv2pkiVGGBXeQ8w YJ+GWIeoiP0tUNkgQDI2bWuYc/avQYRsR3iwOcfnL0re5lBCGK0IQ/oeP/PSkScluXXYukOnJ 6Yy6wC1JZfnd+oJ/YqNobNEOdq4AvN6HOOqP7tkIgJ9oELugIb4ZWxPVtfDypetursZmtMZJa WsmPAITMwAtWde59K0qUUhAcAuQB1IOgNkSeqCCzJA7cvi/Ac7gFPsNaLizPQegTo0twTblmG DnjtAd4YwQ+B78088p9b4g9buz+WkDP4iR238A== Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There are two code locations that implement the SG_IO ioctl: the old sg.c driver, and the generic scsi_ioctl helper that is in turn used by multiple drivers. To eradicate the old compat_ioctl conversion handler for the SG_IO command, I implement a readable pair of put_sg_io_hdr() /get_sg_io_hdr() helper functions that can be used for both compat and native mode, and then I call this from both drivers. For the iovec handling, there is already a compat_import_iovec() function that can simply be called in place of import_iovec(). To avoid having to pass the compat/native state through multiple indirections, I mark the SG_IO command itself as compatible in fs/compat_ioctl.c and use in_compat_syscall() to figure out where we are called from. As a side-effect of this, the sg.c driver now also accepts the 32-bit sg_io_hdr format in compat mode using the read/write interface, not just ioctl. This should improve compatiblity with old 32-bit binaries, but it would break if any application intentionally passes the 64-bit data structure in compat mode here. Signed-off-by: Arnd Bergmann --- block/scsi_ioctl.c | 132 ++++++++++++++++++++++++++++++++++-- drivers/scsi/sg.c | 19 +++--- fs/compat_ioctl.c | 148 +---------------------------------------- include/linux/blkdev.h | 2 + lib/iov_iter.c | 1 + 5 files changed, 143 insertions(+), 159 deletions(-) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index f5e0ad65e86a..cbeb629ee917 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2001 Jens Axboe */ +#include #include #include #include @@ -327,7 +328,14 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, struct iov_iter i; struct iovec *iov = NULL; - ret = import_iovec(rq_data_dir(rq), +#ifdef CONFIG_COMPAT + if (in_compat_syscall()) + ret = compat_import_iovec(rq_data_dir(rq), + hdr->dxferp, hdr->iovec_count, + 0, &iov, &i); + else +#endif + ret = import_iovec(rq_data_dir(rq), hdr->dxferp, hdr->iovec_count, 0, &iov, &i); if (ret < 0) @@ -542,6 +550,122 @@ static inline int blk_send_start_stop(struct request_queue *q, return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); } +#ifdef CONFIG_COMPAT +struct compat_sg_io_hdr { + compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ + compat_int_t dxfer_direction; /* [i] data transfer direction */ + unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char mx_sb_len; /* [i] max length to write to sbp */ + unsigned short iovec_count; /* [i] 0 implies no scatter gather */ + compat_uint_t dxfer_len; /* [i] byte count of data transfer */ + compat_uint_t dxferp; /* [i], [*io] points to data transfer memory + or scatter gather list */ + compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ + compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ + compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ + compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ + compat_int_t pack_id; /* [i->o] unused internally (normally) */ + compat_uptr_t usr_ptr; /* [i->o] unused internally */ + unsigned char status; /* [o] scsi status */ + unsigned char masked_status; /* [o] shifted, masked scsi status */ + unsigned char msg_status; /* [o] messaging level data (optional) */ + unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ + unsigned short host_status; /* [o] errors from host adapter */ + unsigned short driver_status; /* [o] errors from software driver */ + compat_int_t resid; /* [o] dxfer_len - actual_transferred */ + compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ + compat_uint_t info; /* [o] auxiliary information */ +}; +#endif + +int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp) +{ +#ifdef CONFIG_COMPAT + if (in_compat_syscall()) { + struct compat_sg_io_hdr hdr32 = { + .interface_id = hdr->interface_id, + .dxfer_direction = hdr->dxfer_direction, + .cmd_len = hdr->cmd_len, + .mx_sb_len = hdr->mx_sb_len, + .iovec_count = hdr->iovec_count, + .dxfer_len = hdr->dxfer_len, + .dxferp = (uintptr_t)hdr->dxferp, + .cmdp = (uintptr_t)hdr->cmdp, + .sbp = (uintptr_t)hdr->sbp, + .timeout = hdr->timeout, + .flags = hdr->flags, + .pack_id = hdr->pack_id, + .usr_ptr = (uintptr_t)hdr->usr_ptr, + .status = hdr->status, + .masked_status = hdr->masked_status, + .msg_status = hdr->msg_status, + .sb_len_wr = hdr->sb_len_wr, + .host_status = hdr->host_status, + .driver_status = hdr->driver_status, + .resid = hdr->resid, + .duration = hdr->duration, + .info = hdr->info, + }; + + if (copy_to_user(argp, &hdr32, sizeof(hdr))) + return -EFAULT; + + return 0; + } +#endif + + if (copy_to_user(argp, &hdr, sizeof(hdr))) + return -EFAULT; + + return 0; +} +EXPORT_SYMBOL(put_sg_io_hdr); + +int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp) +{ +#ifdef CONFIG_COMPAT + struct compat_sg_io_hdr hdr32; + + if (in_compat_syscall()) { + if (copy_from_user(&hdr32, argp, sizeof(hdr32))) + return -EFAULT; + + *hdr = (struct sg_io_hdr) { + .interface_id = hdr32.interface_id, + .dxfer_direction = hdr32.dxfer_direction, + .cmd_len = hdr32.cmd_len, + .mx_sb_len = hdr32.mx_sb_len, + .iovec_count = hdr32.iovec_count, + .dxfer_len = hdr32.dxfer_len, + .dxferp = compat_ptr(hdr32.dxferp), + .cmdp = compat_ptr(hdr32.cmdp), + .sbp = compat_ptr(hdr32.sbp), + .timeout = hdr32.timeout, + .flags = hdr32.flags, + .pack_id = hdr32.pack_id, + .usr_ptr = compat_ptr(hdr32.usr_ptr), + .status = hdr32.status, + .masked_status = hdr32.masked_status, + .msg_status = hdr32.msg_status, + .sb_len_wr = hdr32.sb_len_wr, + .host_status = hdr32.host_status, + .driver_status = hdr32.driver_status, + .resid = hdr32.resid, + .duration = hdr32.duration, + .info = hdr32.info, + }; + + return 0; + } +#endif + + if (copy_from_user(&hdr, argp, sizeof(hdr))) + return -EFAULT; + + return 0; +} +EXPORT_SYMBOL(get_sg_io_hdr); + int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode, unsigned int cmd, void __user *arg) { @@ -581,14 +705,14 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod case SG_IO: { struct sg_io_hdr hdr; - err = -EFAULT; - if (copy_from_user(&hdr, arg, sizeof(hdr))) + err = get_sg_io_hdr(&hdr, arg); + if (err) break; err = sg_io(q, bd_disk, &hdr, mode); if (err == -EFAULT) break; - if (copy_to_user(arg, &hdr, sizeof(hdr))) + if (put_sg_io_hdr(&hdr, arg)) err = -EFAULT; break; } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index cce757506383..8ae096af2667 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -447,8 +447,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) retval = -ENOMEM; goto free_old_hdr; } - retval =__copy_from_user - (new_hdr, buf, SZ_SG_IO_HDR); + retval = get_sg_io_hdr(new_hdr, buf); req_pack_id = new_hdr->pack_id; kfree(new_hdr); if (retval) { @@ -589,10 +588,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) } if (hp->masked_status || hp->host_status || hp->driver_status) hp->info |= SG_INFO_CHECK; - if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) { - err = -EFAULT; - goto err_out; - } + err = put_sg_io_hdr(hp, buf); err_out: err2 = sg_finish_rem_req(srp); sg_remove_request(sfp, srp); @@ -735,7 +731,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, } srp->sg_io_owned = sg_io_owned; hp = &srp->header; - if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) { + if (get_sg_io_hdr(hp, buf)) { sg_remove_request(sfp, srp); return -EFAULT; } @@ -1797,7 +1793,14 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) struct iovec *iov = NULL; struct iov_iter i; - res = import_iovec(rw, hp->dxferp, iov_count, 0, &iov, &i); +#ifdef CONFIG_COMPAT + if (in_compat_syscall()) + res = compat_import_iovec(rw, hp->dxferp, iov_count, + 0, &iov, &i); + else +#endif + res = import_iovec(rw, hp->dxferp, iov_count, + 0, &iov, &i); if (res < 0) return res; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 10ba2d9e20bc..f279e77df256 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -64,151 +64,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_BLOCK -typedef struct sg_io_hdr32 { - compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ - compat_int_t dxfer_direction; /* [i] data transfer direction */ - unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ - unsigned char mx_sb_len; /* [i] max length to write to sbp */ - unsigned short iovec_count; /* [i] 0 implies no scatter gather */ - compat_uint_t dxfer_len; /* [i] byte count of data transfer */ - compat_uint_t dxferp; /* [i], [*io] points to data transfer memory - or scatter gather list */ - compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ - compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ - compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ - compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ - compat_int_t pack_id; /* [i->o] unused internally (normally) */ - compat_uptr_t usr_ptr; /* [i->o] unused internally */ - unsigned char status; /* [o] scsi status */ - unsigned char masked_status; /* [o] shifted, masked scsi status */ - unsigned char msg_status; /* [o] messaging level data (optional) */ - unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ - unsigned short host_status; /* [o] errors from host adapter */ - unsigned short driver_status; /* [o] errors from software driver */ - compat_int_t resid; /* [o] dxfer_len - actual_transferred */ - compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ - compat_uint_t info; /* [o] auxiliary information */ -} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ - -typedef struct sg_iovec32 { - compat_uint_t iov_base; - compat_uint_t iov_len; -} sg_iovec32_t; - -static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count) -{ - sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1); - sg_iovec32_t __user *iov32 = dxferp; - int i; - - for (i = 0; i < iovec_count; i++) { - u32 base, len; - - if (get_user(base, &iov32[i].iov_base) || - get_user(len, &iov32[i].iov_len) || - put_user(compat_ptr(base), &iov[i].iov_base) || - put_user(len, &iov[i].iov_len)) - return -EFAULT; - } - - if (put_user(iov, &sgio->dxferp)) - return -EFAULT; - return 0; -} - -static int sg_ioctl_trans(struct file *file, unsigned int cmd, - sg_io_hdr32_t __user *sgio32) -{ - sg_io_hdr_t __user *sgio; - u16 iovec_count; - u32 data; - void __user *dxferp; - int err; - int interface_id; - - if (get_user(interface_id, &sgio32->interface_id)) - return -EFAULT; - if (interface_id != 'S') - return do_ioctl(file, cmd, (unsigned long)sgio32); - - if (get_user(iovec_count, &sgio32->iovec_count)) - return -EFAULT; - - { - void __user *top = compat_alloc_user_space(0); - void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) + - (iovec_count * sizeof(sg_iovec_t))); - if (new > top) - return -EINVAL; - - sgio = new; - } - - /* Ok, now construct. */ - if (copy_in_user(&sgio->interface_id, &sgio32->interface_id, - (2 * sizeof(int)) + - (2 * sizeof(unsigned char)) + - (1 * sizeof(unsigned short)) + - (1 * sizeof(unsigned int)))) - return -EFAULT; - - if (get_user(data, &sgio32->dxferp)) - return -EFAULT; - dxferp = compat_ptr(data); - if (iovec_count) { - if (sg_build_iovec(sgio, dxferp, iovec_count)) - return -EFAULT; - } else { - if (put_user(dxferp, &sgio->dxferp)) - return -EFAULT; - } - - { - unsigned char __user *cmdp; - unsigned char __user *sbp; - - if (get_user(data, &sgio32->cmdp)) - return -EFAULT; - cmdp = compat_ptr(data); - - if (get_user(data, &sgio32->sbp)) - return -EFAULT; - sbp = compat_ptr(data); - - if (put_user(cmdp, &sgio->cmdp) || - put_user(sbp, &sgio->sbp)) - return -EFAULT; - } - - if (copy_in_user(&sgio->timeout, &sgio32->timeout, - 3 * sizeof(int))) - return -EFAULT; - - if (get_user(data, &sgio32->usr_ptr)) - return -EFAULT; - if (put_user(compat_ptr(data), &sgio->usr_ptr)) - return -EFAULT; - - err = do_ioctl(file, cmd, (unsigned long) sgio); - - if (err >= 0) { - void __user *datap; - - if (copy_in_user(&sgio32->pack_id, &sgio->pack_id, - sizeof(int)) || - get_user(datap, &sgio->usr_ptr) || - put_user((u32)(unsigned long)datap, - &sgio32->usr_ptr) || - copy_in_user(&sgio32->status, &sgio->status, - (4 * sizeof(unsigned char)) + - (2 * sizeof(unsigned short)) + - (3 * sizeof(int)))) - err = -EFAULT; - } - - return err; -} - struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ char req_state; char orphan; @@ -358,6 +213,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) #endif #ifdef CONFIG_BLOCK /* SG stuff */ +COMPATIBLE_IOCTL(SG_IO) COMPATIBLE_IOCTL(SG_SET_TIMEOUT) COMPATIBLE_IOCTL(SG_GET_TIMEOUT) COMPATIBLE_IOCTL(SG_EMULATED_HOST) @@ -435,8 +291,6 @@ static long do_ioctl_trans(unsigned int cmd, case PPPIOCSACTIVE32: return ppp_sock_fprog_ioctl_trans(file, cmd, argp); #ifdef CONFIG_BLOCK - case SG_IO: - return sg_ioctl_trans(file, cmd, argp); case SG_GET_REQUEST_TABLE: return sg_grt_trans(file, cmd, argp); #endif diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1ef375dafb1c..a1050710d846 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -853,6 +853,8 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, unsigned int, void __user *); extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, struct scsi_ioctl_command __user *); +extern int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp); +extern int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp); extern int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags); extern void blk_queue_exit(struct request_queue *q); diff --git a/lib/iov_iter.c b/lib/iov_iter.c index f1e0569b4539..7baaa989404b 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1678,6 +1678,7 @@ ssize_t compat_import_iovec(int type, *iov = p == *iov ? NULL : p; return n; } +EXPORT_SYMBOL(compat_import_iovec); #endif int import_single_range(int rw, void __user *buf, size_t len, From patchwork Wed Aug 14 20:54:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 11094609 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 34C7B112C for ; Wed, 14 Aug 2019 20:58:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 23A482887E for ; Wed, 14 Aug 2019 20:58:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1644428848; Wed, 14 Aug 2019 20:58:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9789E28848 for ; Wed, 14 Aug 2019 20:58:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730064AbfHNU6r (ORCPT ); Wed, 14 Aug 2019 16:58:47 -0400 Received: from mout.kundenserver.de ([212.227.126.130]:54847 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729984AbfHNU6r (ORCPT ); Wed, 14 Aug 2019 16:58:47 -0400 Received: from threadripper.lan ([149.172.19.189]) by mrelayeu.kundenserver.de (mreue011 [212.227.15.129]) with ESMTPA (Nemesis) id 1MWixU-1hmtSX2IDQ-00X2el; Wed, 14 Aug 2019 22:57:17 +0200 From: Arnd Bergmann To: linux-kernel@vger.kernel.org, viro@zeniv.linux.org.uk, linux-fsdevel@vger.kernel.org, Doug Gilbert , "James E.J. Bottomley" , "Martin K. Petersen" Cc: Arnd Bergmann , Hannes Reinecke , linux-scsi@vger.kernel.org Subject: [PATCH v5 16/18] compat_ioctl: move SG_GET_REQUEST_TABLE handling Date: Wed, 14 Aug 2019 22:54:51 +0200 Message-Id: <20190814205521.122180-7-arnd@arndb.de> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20190814204259.120942-1-arnd@arndb.de> References: <20190814204259.120942-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:Oh96NWxdPZEW/yuDMF44sbWZBSLaeWtZ7p1wHLQUZgKNUin6CaT SZsCIC9diZmfoU/GHahmeQsbLYDGVw9hBTHQoYo+YRxvApsSXI4/JvVsY94AYTDxLkf9CMi 5MpmJ74hVdE/JoAAlIpgiEZxJzKJTxI15YS2DiE/O5HamfDJ1XxqguJssl1WJOIVRNW2q/y cMHt+ifIU8CzvdCJuIrzw== X-UI-Out-Filterresults: notjunk:1;V03:K0:0HxL3DcyvMs=:Z7H2CT2juldoHXDfO9q1XL Fgz7raKdxxOXC6ou7IDYER15xW5hebo9Q0WrHIgFrXoe9Nj09LOZE1qAlCjGZk3l4H5hu+aPC DRBYOuEgMjUMonLNSKQfT3dxF11JNbxlSq0mEnrnFMpXgApAd+ceoP1pA3vOZ1p8V6mifgx5y iuJmYinYWHp0IqrhSRR5l/fdfslGO2rNu/iCpFOhHgtieX/nSqSrtKSLR60j86VsSGeWmT5+q 0vI3NSoUcZ6kQCjQ0hJjyx0OiP01uuKF3TgD7KYEn7UwKwECabMZFKmttvOG9A2I0fuxLe7lR ZgKFifwRqHJbeaPq6nwLPdBM4t9EKIw6OdbCm5IfLTmgp2w3owSEADl/GmXt42+JvYrfVG4m5 61b6jOlUBMZ/qz9xqITSIjoYcmo5+y4BgawmhjaghExwj+xro2w6uk9N2firAF8FTlnK042Oc yzFt+sEqUOqNZo8xi2RRPVAtiCtOOwRVKX9DRwxGsUEm1YUfV2OQ0AgH3BEF604YwN+igSTYL +V+Fuv3yn/h5SZahPgmffvZOj2V0pir7DGuZlTR0jZq91fgX7Fe0BhOrzsSNOlEvK8bWYtoSk YuTGG5BRHL4sNjiBwmwngw/U5fYLuwCB7SF32u7MH+MgftGGEGOpXYR1dNzCdUYt0MGESyhFp ZODj5N5oLP+p5bGOenb2BwLCrsx3quIlcHQ3swWCy/EaLhDiUQP3DnY9DhbbdhRR8nDjr7s26 bP625blLw14sfIHa1ovsph3fNpRQCgDMip3/n1ZXtiO2nlM95cS/5yeRoCpQ0hW1RP3HtfCU4 sGHgQtIR0OEy5FPnN2XiGMCtWisrQ== Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Arnd Bergmann --- drivers/scsi/sg.c | 40 ++++++++++++++++++++++++++++++----- fs/compat_ioctl.c | 54 +---------------------------------------------- 2 files changed, 36 insertions(+), 58 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 3d127bb6357a..6837a3904b8c 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -52,53 +52,6 @@ #include -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); -} - -#ifdef CONFIG_BLOCK -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,13 +110,7 @@ COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN) static long do_ioctl_trans(unsigned int cmd, unsigned long arg, struct file *file) { - void __user *argp = compat_ptr(arg); - switch (cmd) { -#ifdef CONFIG_BLOCK - case SG_GET_REQUEST_TABLE: - return sg_grt_trans(file, cmd, argp); -#endif } return -ENOIOCTLCMD; From patchwork Wed Aug 14 20:54:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 11094605 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 62A1413B1 for ; Wed, 14 Aug 2019 20:58:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 50241287BE for ; Wed, 14 Aug 2019 20:58:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 436B02885E; Wed, 14 Aug 2019 20:58:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DF47F287BE for ; Wed, 14 Aug 2019 20:58:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729984AbfHNU6I (ORCPT ); Wed, 14 Aug 2019 16:58:08 -0400 Received: from mout.kundenserver.de ([212.227.126.187]:33739 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729752AbfHNU6I (ORCPT ); Wed, 14 Aug 2019 16:58:08 -0400 Received: from threadripper.lan ([149.172.19.189]) by mrelayeu.kundenserver.de (mreue011 [212.227.15.129]) with ESMTPA (Nemesis) id 1Mfpf7-1iVP9a30qP-00gHok; Wed, 14 Aug 2019 22:57:43 +0200 From: Arnd Bergmann To: linux-kernel@vger.kernel.org, viro@zeniv.linux.org.uk, linux-fsdevel@vger.kernel.org, "James E.J. Bottomley" , "Martin K. Petersen" Cc: Arnd Bergmann , Christoph Hellwig , Tejun Heo , Bart Van Assche , Hannes Reinecke , Jens Axboe , linux-scsi@vger.kernel.org Subject: [PATCH v5 18/18] scsi: sd: enable compat ioctls for sed-opal Date: Wed, 14 Aug 2019 22:54:53 +0200 Message-Id: <20190814205521.122180-9-arnd@arndb.de> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20190814204259.120942-1-arnd@arndb.de> References: <20190814204259.120942-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:GHU2BOUolFMuYU4JHf6S7Epw6n2I5F+s2JL2xcZ0QVFOtlz3LTM Cg1Y0P2DCMYs/77HHCx1SBY6ljRsMtpIZLwfU9oRltiVTFqbskRhozs7BR1P4kelS1oZQdf NO3WcQWcvIZWwBG0eNOOKMNkbslk2VdBMFzYBppBkPwj0oVa+cGYH4/9qltFy28mV3yE9NN os1WcG3Ajoz39bCTJnZgg== X-UI-Out-Filterresults: notjunk:1;V03:K0:zpxeGQV2Lis=:DxZ29hcJwmhH8cHBeJLpFh cbl964bB0IHU8mgW586im24i2LN4vSL9QCCunqRoHxS7JbPtdo5H45SQ6PWsw9mw/Ulb/ScC1 0wRZL4DfLEEd0+uxjvjXcsGHZWHGCFNQLqo4Q25G0MVi5VwZyzkAsDZ51/SJZ5+QyVes+Qt9I jpKCw8zab86I+Rl7XhCLexRa9CBJThsIiej6aL+7uuwzbweouesQv0N8hCkZYPSHT+ujCSWh0 kLdAOCE6Biopn5K/CGKUYmuSjZ9apaCSOVDn5i0Q6JdR0putP+DLV+uMO99uB7qL1273rW5AM aiOAT7BbnDBhLmofbzGwXZvCbgrWP9CBdLFxRXsB0Gh9sC8duzp3M3okSQ8EhDEBLKt7Xr82Y 69IHO+8bAGW0Avqxepran8c+dzq2jov2jsQrrxJqinBc6KXjj1lwSbbsVisl1WnukDYcN6k2l bXhBO2kcCQjrrjs8o/B2IdMo5vHHxsu883UHlrOuPk0+Pmdf4TrAwNirMNkik7rmJCC1VWD0M YZ4JfrKoykoTAIz6RHX4zUk0RvgX/5+6B3ms7hZ5+mWytecx9vFhvM6dbSTVopHsuOfKorbtd C/xUO8wK1iajpYzXGo+S0nhiHKBNVa/kboscA0C7kx3Ybwba60OSBHWJ1wHuQrvP5fihDvrMU 3yg76Yq3EpfucvHZpAOym5tAjj1kALpm3aXVMSJBtBSlqHml5cwYgTvD1OW8YuOeCwuxBz2fH 2hKYaB8bwrOK32MdonrxWgBxhRv5SfKCbUepsQ== Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The sed_ioctl() function is written to be compatible between 32-bit and 64-bit processes, however compat mode is only wired up for nvme, not for sd. Add the missing call to sed_ioctl() in sd_compat_ioctl(). Fixes: d80210f25ff0 ("sd: add support for TCG OPAL self encrypting disks") Signed-off-by: Arnd Bergmann --- drivers/scsi/sd.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 149d406aacc9..8b71664c54bd 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1693,20 +1693,30 @@ static void sd_rescan(struct device *dev) static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + struct gendisk *disk = bdev->bd_disk; + struct scsi_disk *sdkp = scsi_disk(disk); + struct scsi_device *sdev = sdkp->device; + void __user *p = compat_ptr(arg); int error; + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + error = scsi_ioctl_block_when_processing_errors(sdev, cmd, (mode & FMODE_NDELAY) != 0); if (error) return error; + + if (is_sed_ioctl(cmd)) + return sed_ioctl(sdkp->opal_dev, cmd, p); /* * Let the static ioctl translation table take care of it. */ if (!sdev->host->hostt->compat_ioctl) return -ENOIOCTLCMD; - return sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); + return sdev->host->hostt->compat_ioctl(sdev, cmd, p); } #endif