From patchwork Wed Oct 9 19:10:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 11181903 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 97290912 for ; Wed, 9 Oct 2019 19:13:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7118D218DE for ; Wed, 9 Oct 2019 19:13:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732004AbfJITNd (ORCPT ); Wed, 9 Oct 2019 15:13:33 -0400 Received: from mout.kundenserver.de ([212.227.126.133]:49065 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731976AbfJITLY (ORCPT ); Wed, 9 Oct 2019 15:11:24 -0400 Received: from threadripper.lan ([149.172.19.189]) by mrelayeu.kundenserver.de (mreue011 [212.227.15.129]) with ESMTPA (Nemesis) id 1MJmX3-1iY1zi19LN-00K63S; Wed, 09 Oct 2019 21:11:11 +0200 From: Arnd Bergmann To: Al Viro Cc: linux-kernel@vger.kernel.org, y2038@lists.linaro.org, linux-fsdevel@vger.kernel.org, Arnd Bergmann , Heiko Carstens , =?utf-8?q?Kai_M=C3=A4kisara?= , linux-scsi@vger.kernel.org, "James E.J. Bottomley" , "Martin K. Petersen" , "David S. Miller" Subject: [PATCH v6 14/43] compat_ioctl: move tape handling into drivers Date: Wed, 9 Oct 2019 21:10:14 +0200 Message-Id: <20191009191044.308087-14-arnd@arndb.de> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20191009190853.245077-1-arnd@arndb.de> References: <20191009190853.245077-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:dX6EYr/e+tXqH/3i7CUAu5i2JPBoHn6xZkuxBVVBRC86zLcXHtN AP9fh28WHIAve+RkZd6GTnNfeagwgbIuBqZRS2GCuPLWhBKEHQhffYZ/nmlN6jdHVZp9dUI rnM2FTUttKIgSQiQbHnu8o8IZMrWxPb0aZZOPkvcC5umqHzWHX/8PsnSMSDTtLw/hQqn03N +zpOJI7Mv7FQGjZZyBDlg== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:qO/OYT39+Po=:/BAoFq03WGJOzNLnxE4e/x 7052GJzjVUJsihh8IW0rb9qaJP3ZyZnfEgygA7Wp8CmW7Fa5fgFB9UqQBf7JqGTsN/SHazJZL Bhix6nfoTuOLYdGEVxQotGFtlaAf1zHLTz6U2f0s+ApSsaqj1glgBpc0X7dOHdv/96Tbm0Guq wmS9Mo1vAgwGdTIzkDmZLC4iWE1lovohjzGJ8RJLi0B1QEzAfeQQMortreXNCJdAIrkZ+xF3s rNV8B46A/D5rE7Ye4lxrc6Cgev5roPjoQ3G+SZR9C/d+n+Xka5SMo4pOADTgEh3U67pHpMkY/ dDST9zqLkh5F1R6P7GsdWA7f3fYN4rgsVp90GaeKBv72ox6hFpPR/iF780kFbrmbIJ6a0BtRi gT4/nXc5MqALaCNZKSiYC3kGloe36XjPJp70ErjN50X//EX6+ymGZbKwnb7aMy3lSQERim3pa TUn/tK5p1JpAR5q1XFDDpGIvi5mfdRtrnlswBH+IvA51hVgiACpYVJd7K72gKa2k4ocbPzdFe VZpLF9ZpMqzcUmn56xcKi2wk9flbnGDDf4/mn67Dw4BKu5VeB9igFhB4bzHL8jTdmgD6K2ETn mYgRaZ+q44n7wIOoX37gU56Fzw8Lm61Ar9/oX/Szz5tSH/jApNBV+AeeJYPaagdnuo6pB6IS/ HRAvLTRHyfdFhl1MoCMkKPvYaEtyCJGnpxbfWZp8DutFc/1ku6wmbirlEYmpAgF829hyS9/1A Zi3rsWbxRRKJp8J2Nz49yELVOch06kzjs5ecV0FkpbodZ2caLCImdWJlUhmTUDgNSbg7c76fi NLSlavAzdXadAjt5VydWU1UaYUndDZF/Vh7JNPeS4EzLIOjUuNru8e6Zq5BZUycCmCfSt8/cw hGxflgnmorzw0/YxUs9V46hGAXsKCxIdgH3z/sN9n2SSwVyjxAYOecJPbruQzepBgAJbkuqn5 LV8LfvvcfnDT3O4nAXVeXxA8fRVu3kf8= Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org MTIOCPOS and MTIOCGET are incompatible between 32-bit and 64-bit user space, and traditionally have been translated in fs/compat_ioctl.c. To get rid of that translation handler, move a corresponding implementation into each of the four drivers implementing those commands. The interesting part of that is now in a new linux/mtio.h header that wraps the existing uapi/linux/mtio.h header and provides an abstraction to let drivers handle both cases easily. Using an in_compat_syscall() check, the caller does not have to keep track of whether this was called through .unlocked_ioctl() or .compat_ioctl(). Acked-by: Heiko Carstens Cc: "Kai Mäkisara" Cc: linux-scsi@vger.kernel.org Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: "David S. Miller" Signed-off-by: Arnd Bergmann --- drivers/ide/ide-tape.c | 27 ++++++++++--- drivers/s390/char/tape_char.c | 41 +++++++------------- drivers/scsi/st.c | 28 +++++++++----- fs/compat_ioctl.c | 73 ----------------------------------- include/linux/mtio.h | 60 ++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 115 deletions(-) create mode 100644 include/linux/mtio.h diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index db1a65f4b490..3e7482695f77 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -19,6 +19,7 @@ #define IDETAPE_VERSION "1.20" +#include #include #include #include @@ -1407,14 +1408,10 @@ static long do_idetape_chrdev_ioctl(struct file *file, if (tape->drv_write_prot) mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); - if (copy_to_user(argp, &mtget, sizeof(struct mtget))) - return -EFAULT; - return 0; + return put_user_mtget(argp, &mtget); case MTIOCPOS: mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; - if (copy_to_user(argp, &mtpos, sizeof(struct mtpos))) - return -EFAULT; - return 0; + return put_user_mtpos(argp, &mtpos); default: if (tape->chrdev_dir == IDETAPE_DIR_READ) ide_tape_discard_merge_buffer(drive, 1); @@ -1432,6 +1429,22 @@ static long idetape_chrdev_ioctl(struct file *file, return ret; } +static long idetape_chrdev_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + + if (cmd == MTIOCPOS32) + cmd = MTIOCPOS; + else if (cmd == MTIOCGET32) + cmd = MTIOCGET; + + mutex_lock(&ide_tape_mutex); + ret = do_idetape_chrdev_ioctl(file, cmd, arg); + mutex_unlock(&ide_tape_mutex); + return ret; +} + /* * Do a mode sense page 0 with block descriptor and if it succeeds set the tape * block size with the reported value. @@ -1886,6 +1899,8 @@ static const struct file_operations idetape_fops = { .read = idetape_chrdev_read, .write = idetape_chrdev_write, .unlocked_ioctl = idetape_chrdev_ioctl, + .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ? + idetape_chrdev_compat_ioctl : NULL, .open = idetape_chrdev_open, .release = idetape_chrdev_release, .llseek = noop_llseek, diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index ea4253939555..8abb42923307 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -341,14 +341,14 @@ tapechar_release(struct inode *inode, struct file *filp) */ static int __tapechar_ioctl(struct tape_device *device, - unsigned int no, unsigned long data) + unsigned int no, void __user *data) { int rc; if (no == MTIOCTOP) { struct mtop op; - if (copy_from_user(&op, (char __user *) data, sizeof(op)) != 0) + if (copy_from_user(&op, data, sizeof(op)) != 0) return -EFAULT; if (op.mt_count < 0) return -EINVAL; @@ -392,9 +392,7 @@ __tapechar_ioctl(struct tape_device *device, if (rc < 0) return rc; pos.mt_blkno = rc; - if (copy_to_user((char __user *) data, &pos, sizeof(pos)) != 0) - return -EFAULT; - return 0; + return put_user_mtpos(data, &pos); } if (no == MTIOCGET) { /* MTIOCGET: query the tape drive status. */ @@ -424,15 +422,12 @@ __tapechar_ioctl(struct tape_device *device, get.mt_blkno = rc; } - if (copy_to_user((char __user *) data, &get, sizeof(get)) != 0) - return -EFAULT; - - return 0; + return put_user_mtget(data, &get); } /* Try the discipline ioctl function. */ if (device->discipline->ioctl_fn == NULL) return -EINVAL; - return device->discipline->ioctl_fn(device, no, data); + return device->discipline->ioctl_fn(device, no, (unsigned long)data); } static long @@ -445,7 +440,7 @@ tapechar_ioctl(struct file *filp, unsigned int no, unsigned long data) device = (struct tape_device *) filp->private_data; mutex_lock(&device->mutex); - rc = __tapechar_ioctl(device, no, data); + rc = __tapechar_ioctl(device, no, (void __user *)data); mutex_unlock(&device->mutex); return rc; } @@ -455,23 +450,17 @@ static long tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data) { struct tape_device *device = filp->private_data; - int rval = -ENOIOCTLCMD; - unsigned long argp; + long rc; - /* The 'arg' argument of any ioctl function may only be used for - * pointers because of the compat pointer conversion. - * Consider this when adding new ioctls. - */ - argp = (unsigned long) compat_ptr(data); - if (device->discipline->ioctl_fn) { - mutex_lock(&device->mutex); - rval = device->discipline->ioctl_fn(device, no, argp); - mutex_unlock(&device->mutex); - if (rval == -EINVAL) - rval = -ENOIOCTLCMD; - } + if (no == MTIOCPOS32) + no = MTIOCPOS; + else if (no == MTIOCGET32) + no = MTIOCGET; - return rval; + mutex_lock(&device->mutex); + rc = __tapechar_ioctl(device, no, compat_ptr(data)); + mutex_unlock(&device->mutex); + return rc; } #endif /* CONFIG_COMPAT */ diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index e3266a64a477..9e3fff2de83e 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -22,6 +22,7 @@ static const char *verstr = "20160209"; #include +#include #include #include #include @@ -3800,14 +3801,11 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) if (STp->cleaning_req) mt_status.mt_gstat |= GMT_CLN(0xffffffff); - i = copy_to_user(p, &mt_status, sizeof(struct mtget)); - if (i) { - retval = (-EFAULT); + retval = put_user_mtget(p, &mt_status); + if (retval) goto out; - } STp->recover_reg = 0; /* Clear after read */ - retval = 0; goto out; } /* End of MTIOCGET */ if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { @@ -3821,9 +3819,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) goto out; } mt_pos.mt_blkno = blk; - i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); - if (i) - retval = (-EFAULT); + retval = put_user_mtpos(p, &mt_pos); goto out; } mutex_unlock(&STp->lock); @@ -3857,14 +3853,26 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) } #ifdef CONFIG_COMPAT -static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) { + void __user *p = compat_ptr(arg); struct scsi_tape *STp = file->private_data; struct scsi_device *sdev = STp->device; int ret = -ENOIOCTLCMD; + + /* argument conversion is handled using put_user_mtpos/put_user_mtget */ + switch (cmd_in) { + case MTIOCTOP: + return st_ioctl(file, MTIOCTOP, (unsigned long)p); + case MTIOCPOS32: + return st_ioctl(file, MTIOCPOS, (unsigned long)p); + case MTIOCGET32: + return st_ioctl(file, MTIOCGET, (unsigned long)p); + } + if (sdev->host->hostt->compat_ioctl) { - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); + ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); } return ret; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 47da220f95b1..b65eef3d4787 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -361,73 +360,6 @@ static int ppp_scompress(struct file *file, unsigned int cmd, return do_ioctl(file, PPPIOCSCOMPRESS, (unsigned long) odata); } -#ifdef CONFIG_BLOCK -struct mtget32 { - compat_long_t mt_type; - compat_long_t mt_resid; - compat_long_t mt_dsreg; - compat_long_t mt_gstat; - compat_long_t mt_erreg; - compat_daddr_t mt_fileno; - compat_daddr_t mt_blkno; -}; -#define MTIOCGET32 _IOR('m', 2, struct mtget32) - -struct mtpos32 { - compat_long_t mt_blkno; -}; -#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) - -static int mt_ioctl_trans(struct file *file, - unsigned int cmd, void __user *argp) -{ - /* NULL initialization to make gcc shut up */ - struct mtget __user *get = NULL; - struct mtget32 __user *umget32; - struct mtpos __user *pos = NULL; - struct mtpos32 __user *upos32; - unsigned long kcmd; - void *karg; - int err = 0; - - switch(cmd) { - case MTIOCPOS32: - kcmd = MTIOCPOS; - pos = compat_alloc_user_space(sizeof(*pos)); - karg = pos; - break; - default: /* MTIOCGET32 */ - kcmd = MTIOCGET; - get = compat_alloc_user_space(sizeof(*get)); - karg = get; - break; - } - if (karg == NULL) - return -EFAULT; - err = do_ioctl(file, kcmd, (unsigned long)karg); - if (err) - return err; - switch (cmd) { - case MTIOCPOS32: - upos32 = argp; - err = convert_in_user(&pos->mt_blkno, &upos32->mt_blkno); - break; - case MTIOCGET32: - umget32 = argp; - err = convert_in_user(&get->mt_type, &umget32->mt_type); - err |= convert_in_user(&get->mt_resid, &umget32->mt_resid); - err |= convert_in_user(&get->mt_dsreg, &umget32->mt_dsreg); - err |= convert_in_user(&get->mt_gstat, &umget32->mt_gstat); - err |= convert_in_user(&get->mt_erreg, &umget32->mt_erreg); - err |= convert_in_user(&get->mt_fileno, &umget32->mt_fileno); - err |= convert_in_user(&get->mt_blkno, &umget32->mt_blkno); - break; - } - return err ? -EFAULT: 0; -} - -#endif /* CONFIG_BLOCK */ - /* Bluetooth ioctls */ #define HCIUARTSETPROTO _IOW('U', 200, int) #define HCIUARTGETPROTO _IOR('U', 201, int) @@ -479,8 +411,6 @@ IGNORE_IOCTL(VT_GETMODE) */ COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */ COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ -/* Little m */ -COMPATIBLE_IOCTL(MTIOCTOP) #ifdef CONFIG_BLOCK /* md calls this on random blockdevs */ IGNORE_IOCTL(RAID_VERSION) @@ -846,9 +776,6 @@ static long do_ioctl_trans(unsigned int cmd, return sg_ioctl_trans(file, cmd, argp); case SG_GET_REQUEST_TABLE: return sg_grt_trans(file, cmd, argp); - case MTIOCGET32: - case MTIOCPOS32: - return mt_ioctl_trans(file, cmd, argp); #endif } diff --git a/include/linux/mtio.h b/include/linux/mtio.h new file mode 100644 index 000000000000..67d03156f2c2 --- /dev/null +++ b/include/linux/mtio.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_MTIO_COMPAT_H +#define _LINUX_MTIO_COMPAT_H + +#include +#include +#include + +/* + * helper functions for implementing compat ioctls on the four tape + * drivers: we define the 32-bit layout of each incompatible structure, + * plus a wrapper function to copy it to user space in either format. + */ + +struct mtget32 { + s32 mt_type; + s32 mt_resid; + s32 mt_dsreg; + s32 mt_gstat; + s32 mt_erreg; + s32 mt_fileno; + s32 mt_blkno; +}; +#define MTIOCGET32 _IOR('m', 2, struct mtget32) + +struct mtpos32 { + s32 mt_blkno; +}; +#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) + +static inline int put_user_mtget(void __user *u, struct mtget *k) +{ + struct mtget32 k32 = { + .mt_type = k->mt_type, + .mt_resid = k->mt_resid, + .mt_dsreg = k->mt_dsreg, + .mt_gstat = k->mt_gstat, + .mt_erreg = k->mt_erreg, + .mt_fileno = k->mt_fileno, + .mt_blkno = k->mt_blkno, + }; + int ret; + + if (in_compat_syscall()) + ret = copy_to_user(u, &k32, sizeof(k32)); + else + ret = copy_to_user(u, k, sizeof(*k)); + + return ret ? -EFAULT : 0; +} + +static inline int put_user_mtpos(void __user *u, struct mtpos *k) +{ + if (in_compat_syscall()) + return put_user(k->mt_blkno, (u32 __user *)u); + else + return put_user(k->mt_blkno, (long __user *)u); +} + +#endif From patchwork Wed Oct 9 19:10:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 11181881 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E4BD0912 for ; Wed, 9 Oct 2019 19:12:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BF9192190F for ; Wed, 9 Oct 2019 19:12:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731590AbfJITMh (ORCPT ); Wed, 9 Oct 2019 15:12:37 -0400 Received: from mout.kundenserver.de ([212.227.126.134]:39725 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732022AbfJITLb (ORCPT ); Wed, 9 Oct 2019 15:11:31 -0400 Received: from threadripper.lan ([149.172.19.189]) by mrelayeu.kundenserver.de (mreue011 [212.227.15.129]) with ESMTPA (Nemesis) id 1Ma1oK-1idCOx1GgG-00VwZ9; Wed, 09 Oct 2019 21:11:19 +0200 From: Arnd Bergmann To: Al Viro Cc: linux-kernel@vger.kernel.org, y2038@lists.linaro.org, linux-fsdevel@vger.kernel.org, Arnd Bergmann , Steffen Maier , linux-scsi@vger.kernel.org, Doug Gilbert , "James E.J. Bottomley" , "Martin K. Petersen" Subject: [PATCH v6 32/43] compat_ioctl: reimplement SG_IO handling Date: Wed, 9 Oct 2019 21:10:33 +0200 Message-Id: <20191009191044.308087-33-arnd@arndb.de> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20191009190853.245077-1-arnd@arndb.de> References: <20191009190853.245077-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:9Lan3CbTNW1DttWti80g654pL0EZohQZ5/fSs6vMVrkOPe0wm7i dkgS3xONX3vJj7b50q4/3ifwfCxNfkAdgn5cysVvPu7f7LfJllX9Gri8J3dRsiasXNopZEp ox9rXFP/EIj6bTHLNgvyb4rdraNhIMW0lr+nAH1VKNHJWhdmN9pDvAZO3bx/DUSeiJNLNPN qFLbG5nPPvBOY+CvMCfqg== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:Vy3QkX8f6mQ=:dWhmrN/ZcGTKpT1LUqMdzp 47hIBlnF/rgLZouOdWXWDmvA7kxnzZ3M9kDPUnXikVdjw28VFM97HZxBQrbt1dl1+tl7x6XsA qbVtdIULgosARAANDA9/8cLg4tsTztITjitBdygUnUbKz2L/F0t9qo1CJvPi6WSyCtSOSGCfn 25uiopb/Krxlf9eHL74G03YEwmAPl9cql6CSt/8NNC29JMc7j+x4FluD1ULqRrnqZOj0dL/oA Y/9VStfc0zwMrJ2pJFmyHyV9hsq9Qw1gbCS/hsg3ZMhowrL94RiyS54RyypkKX9byZHotH8zg dwDTTcVF0OcoI+HxgbMXN7RzWRKE1uODQG0xwugd2mpd8T1ygvXD0K8iS9eo7xd3UqEQn88rs PTEo/ZT4XLpsoqlPatSOJa4ygwpswYyavoVdq7lX1m1ydEq5yrtEumBHw43J4GgL9vxepGwBh QqsqahNT9+LDtlZlA9RWigGdacWC3f9Hr2L4lC9ijH4Lu1JaUITwU2Xw9OF1ePzLFHZSoDxGT rIYEc30NJR9eY8ZhMP8jcDkUSdReg4+V8fXFLJKH6o/u1NsvqlrJtrfXnUxsnQ/bPtR0HQPMS +DZe7fa9db4qQePNh5e73BT5D/4RNMSpBF/UDsgznscZ/WXLi+uCi/OKu1WohxOJZZp+vZKpS STueBHaAHzVnDjNqE0adAYsOzMbrW2dW7FS8ScbgpQatGtsyhKC5a1lZ3Ws0NSyco4xniQoFY 1FQYTfxx8sXsfps6WRzgnUXq0J9V4wNgRFXogu3YbY/2Eet7CmmYmwN3WpyYvCF+HShyQjUhg SXyrcAeSuijoMMiJX+mUDtgEjyNi0l6/VbBXR20x9G6znZjnYXmZ418gJ0x/wX/2AbJpn24yv h8V9SzcT7QHBYGxUnUQg== Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org 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. Steffen Maier helped debug an issue in an earlier version of this patch. Cc: Steffen Maier Cc: linux-scsi@vger.kernel.org Cc: Doug Gilbert Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" 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..650bade5ea5a 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(hdr32))) + 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 f3ea78b0c91c..2c8cd22b176b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -870,6 +870,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 639d5e7014c1..ffb52f2c0ef4 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 Oct 9 19:10:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 11181875 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 40681912 for ; Wed, 9 Oct 2019 19:12:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2BA43218DE for ; Wed, 9 Oct 2019 19:12:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732091AbfJITLd (ORCPT ); Wed, 9 Oct 2019 15:11:33 -0400 Received: from mout.kundenserver.de ([212.227.126.131]:45423 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732066AbfJITLd (ORCPT ); Wed, 9 Oct 2019 15:11:33 -0400 Received: from threadripper.lan ([149.172.19.189]) by mrelayeu.kundenserver.de (mreue011 [212.227.15.129]) with ESMTPA (Nemesis) id 1MXotA-1ib0Xm0A5U-00Y8QV; Wed, 09 Oct 2019 21:11:22 +0200 From: Arnd Bergmann To: Al Viro Cc: linux-kernel@vger.kernel.org, y2038@lists.linaro.org, linux-fsdevel@vger.kernel.org, Arnd Bergmann , linux-scsi@vger.kernel.org, Doug Gilbert , "James E.J. Bottomley" , "Martin K. Petersen" Subject: [PATCH v6 41/43] compat_ioctl: move SG_GET_REQUEST_TABLE handling Date: Wed, 9 Oct 2019 21:10:42 +0200 Message-Id: <20191009191044.308087-42-arnd@arndb.de> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20191009190853.245077-1-arnd@arndb.de> References: <20191009190853.245077-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:p7Tc//BuR7qdz2xwgrqekZl/T08X8CkoWdOtYvxnp+Bnzgn9Uj7 sAo1jJmlSHjzs5xbyAt88mQJgrMQQkQlwzqT+rSKafIvWdfeMntJkYSBMs+BkJy82ISeh0H cIsrVtG2023QK4n/BOJ/SXqjlr6TRtcLNDDt5CVctNJTL0LmzQ9SRSfu7eEaTflg8MfvlnX T4k+u6NPrU4atJQvOg9Mw== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:d4mN/yyRcj8=:TTGVKCdrOl6cbcoLsASAxH kEVn9N9blBIh/ydPtDoiNrGXUt0w+lsODlOQ4ZbQ10H7P0nGg5FB8Ix2gqOzHwQPg5XjYvA0M OxUWCMQuGZ6e2hiDbTK7u6VvVLryKAbvKE5d7HfNePfwIi8nwwKUCwZ5VZBU8H8J8kRfqLb5B q6Lbp46cimVpv3E83rzt/wq0YxKERx4nGqHZ1YpBztjPBuAGLuh11mdTZTnnKeeHi09MrubPl 9BL7+y6WbEyCuWOHIxmPrHHGkpe4pvuIL26//2Nbi7D3u511PEMowfGuDFBF0xqAvd1zHAL4i unBTi8+fTlnq3kzqbdrn2V5N2uhMinIrDNqv6hmm5kpxLozsE9OJu91n5xzye5CSUNNIScPeX Hw++dibuo02BNKb493CplF4yRZlxIGW7cpMJxg2OF+bxEq0NVQ21cgJ4yGzwIj08KZPJ8wUGn VG70GU21vGUva1yJrY8e1cz8PQLg009xUSWHOPqI64FN6UBDzmvxZzImnnDEfVnXvFGX4ra+D eEnrakXeTjJbmSQ1javGLTQICDgHjcFEjfO3cOAKfWNzdxmfEQSXfhvz1OaiOvQ2lbClhvRmG DWB/VWNLLLv7qrljQFMCAZzIQSS2Pq+4qPOHSVOV/dnLtEf4QFpH8wGkUynZy+8LxgyYPHZas opv6lbCaVeqYW7YYNkEf80JuxWQMyxLCoRcy13mlz00Uu3AASfuSMJ/xLwo7yIUnofnmDdZHO eeVfsGhwQu4mMURh1fQxLhwxr4YApqOLakENRSJXlo++sCJmCqokyXVMJy8PquYBhWcG5TP5L +mHLDB6hbb8JrMiieemRSJKIszB2z6RZcNLbSnNDoMKohPz5vcXywWsR3BtSOKUiWWhv6LLRI eslWOrwcydSqNlIZ4EkA== Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org 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 Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Signed-off-by: Arnd Bergmann --- 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 -#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; } From patchwork Wed Oct 9 19:10:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 11181885 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3DDEE912 for ; Wed, 9 Oct 2019 19:12:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 294082190F for ; Wed, 9 Oct 2019 19:12:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732343AbfJITMv (ORCPT ); Wed, 9 Oct 2019 15:12:51 -0400 Received: from mout.kundenserver.de ([212.227.126.131]:46385 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732044AbfJITLa (ORCPT ); Wed, 9 Oct 2019 15:11:30 -0400 Received: from threadripper.lan ([149.172.19.189]) by mrelayeu.kundenserver.de (mreue011 [212.227.15.129]) with ESMTPA (Nemesis) id 1MofLl-1hleRX2T5V-00p7Pi; Wed, 09 Oct 2019 21:11:22 +0200 From: Arnd Bergmann To: Al Viro Cc: linux-kernel@vger.kernel.org, y2038@lists.linaro.org, linux-fsdevel@vger.kernel.org, Arnd Bergmann , linux-scsi@vger.kernel.org, "James E.J. Bottomley" , "Martin K. Petersen" Subject: [PATCH v6 43/43] scsi: sd: enable compat ioctls for sed-opal Date: Wed, 9 Oct 2019 21:10:44 +0200 Message-Id: <20191009191044.308087-44-arnd@arndb.de> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20191009190853.245077-1-arnd@arndb.de> References: <20191009190853.245077-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:zX1dBOxTNEIjEWC6S6Aboc9GLFenI7/73H9gQTcEXZJuXQOOPKQ m3Fd1C/SOXXiF/vgpisdbgSmCcJpi/8S/vO/qXr1qfrJIStRYB3s3dEawxyMSUMn+0NTfXy Ab9xMpMNOALYbbrUsRd2FLw0Ye7wS9Iq5k27P/7uitVAlIrvvypAqXWfA5vkc0tbPYZF+1m NIF5nP/JU3XKb21XnisJw== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:lFQ+r8yms6g=:sbWCiEgDC0Wd/x2FxEm0lO HIOHewpro6Y6RhDe6KbndIDg0JNlUin7WJAs+q2iO5twgzE03hJmvtw+q/+cNaD+grzoD4Oda gFzYZwLfS9Ef35ZuoxQBOuKAIMQZ7UrTAbC7A4HGnHBdrCJeuL+FAvMkx8d9Q3v8oDLoRK99G guyQ9i6W0+p2M2w3TlNGT+w7ZOCMJIl9i//enaD+YsHcY26KZ2FFZUau1fGlpuhXhAcqODDXX SIcsD74vNvgKtyEPxV9tc3Q2lfXhV6s74yPR+l6P2GlsQnPmu3EOvVNP8zyq8PBq4AP4/0PxD 8mt6NCkQTa6kLkw69qrXpOki8HjCDcvQ2jcGjludeml2Gae0+PG+4flcA4nJzyRMb5pG2bXde Gss218kuyh26mcuzvCMUzxMxLCoTBtDQiVx8PY3oe69kv15zMI+htD6Ocko1S9T0fX+4tn3KN g/dqGY4gdlj/BH/PsPlw7NfC3JvJtW5J8KgG0SAfphyamwOela5x8WVCzovCgjr4yuqFbGZXi /0zOytzYJdzQerNej9emCJzBg4g//n0fKkVR99ce+YbHmaRFLD0+QnF41NuB2SNqlkNEVDWLQ JkJ/iUs6UBYMGqIj35uk/P8skn4f3tiRIkaDlpRk4Rb8G8J9bl8MaT4JrR+dlNzyR1EswTS2M NFx1iku9lwAxHQrhCwDBbP+1xC3i60il2GQ0PiXA9ETGMcBWbWH3QQYqw3bkOQebzBgN1ezzI ucj68bPQaHNnBwPCpejCq7sFoYI8x1G2hI0OzAx8IWJrONDM4BrJghfQQvnMXkjO57YmRW3KR ppoc3ztmdrjMOaKOPqMKgvjeTkKkkZM5MPa/hI7eeaQeYRXyvd6rEK8MQdP/6fH4SgeGNu6Ru eU2kfW0Ze1W96JFfciaA== Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org 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") Cc: linux-scsi@vger.kernel.org Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" 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 50928bc266eb..5abdf03083ae 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1692,20 +1692,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