From patchwork Fri Sep 18 12:09:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 257595 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5642EC43464 for ; Fri, 18 Sep 2020 12:11:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1FA1822208 for ; Fri, 18 Sep 2020 12:11:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726276AbgIRMLO (ORCPT ); Fri, 18 Sep 2020 08:11:14 -0400 Received: from mout.kundenserver.de ([212.227.126.187]:55079 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726064AbgIRMLN (ORCPT ); Fri, 18 Sep 2020 08:11:13 -0400 Received: from threadripper.lan ([149.172.98.151]) by mrelayeu.kundenserver.de (mreue010 [212.227.15.129]) with ESMTPA (Nemesis) id 1MHo6Y-1kEHQL3GCc-00EsgF; Fri, 18 Sep 2020 14:10:43 +0200 From: Arnd Bergmann To: Adaptec OEM Raid Solutions , "James E.J. Bottomley" , "Martin K. Petersen" , Balsundar P Cc: Christoph Hellwig , Arnd Bergmann , Christoph Hellwig , Zou Wei , Hannes Reinecke , Sagar Biradar , linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/3] scsi: aacraid: improve compat_ioctl handlers Date: Fri, 18 Sep 2020 14:09:31 +0200 Message-Id: <20200918120955.1465510-1-arnd@arndb.de> X-Mailer: git-send-email 2.27.0 MIME-Version: 1.0 X-Provags-ID: V03:K1:turuYngxuWvvZGlQIzIUIkI/5MIDwtOTRRsAxoSfubHLS0nafsT Ztq8Y/VdxVa+9rY3KO9F62a+NgYuMeLRsnF/UU/rJOZsZYgi7EXR1Qy8Hvd6KErlRCqg9XD yp4ZT71D/sOpvi9fB00rCDvh6RQczR66k2/OZ+3TNFGF4mvGbFQZ9dbPCY7q1+JI02ovJ9T 5vrJTwTT7r88+K3jXP9gA== X-UI-Out-Filterresults: notjunk:1; V03:K0:3zo151Kxg3s=:X2HIUpg2rTwqsEIOSufltD 8zomUTVMWKzIyXKlScb+anMjCDM8HdXU+fAOIvvuUXkvEdW1GIw0O2Go1hggHc7jsYz+AJHBS HwMAwUaB27wcw2Yt6AiTYQTjz68bH+8e4q43HyDh7lGWp2jItDYXGVsH8ZmU9l2cxB91pPKP2 S2HDgNUnYZp2Z6I0+x0/ZxZxlm1GpZqR5nX2NyGy5dcCmhqA/hyX2lEjtR7VEzjd6a2oDKc6W 3F0AwfJcNjNFVg7DGTiANbQ/z0ZnNDq4O/oNYvXTtLNDOJJ8DYzjdQ1qb8Tly8qv/lD6TbJDZ Em7wH6L3gNTK+oO1pfzEpw5t68jj3x7yxWGbEYIvC8MSmNNatGm9Ut4IbesDXu2ZZaAD4Tcz/ m2ndkyhjXEAX84nVUog2EeCL7cmON02zCOleY/IOw2fNjQC+f2gbWz2oyaUqB5budJ0j4V4HU +4ptcW/t+muED3n025+OAgleerkQaPwRgf0x4Ienw8if9/kfbyCIdLweGUnwPh2mZS8CN8f5y vnqxSQ6kqSOtJLG++OIukIR0TxIfHzUbHfKHyujGfbisyjAM2jYkIYhoPocJuYXOcdopTjRuH df3JfBRh02X3p7phs0CWXyh/x0IY091tv47GEAnTxo9NG06myL/yGXnYbPg5XUg5VHflulSx/ FuhYap4y3IlHCzxYz32eQADWZkhzW8BITew2dIc/u/m3yWMDibY/fWm0jXieMtTUo3of1Mg32 JRUegL66alKkjH8d1m+x1UddE2rgtBS19o4HazSxnwWJopif36qo6c3T5Hbg/CQyU+teLvP18 Nol6YEq2H4miMIVOetA3v4WF7OKSEas0zCvpOAF2gBZVIw+WGDmm3wyf7SGN/8dHuUky/Zh Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org The use of compat_alloc_user_space() can be easily replaced by handling compat arguments in the regular handler, and this will make it work for big-endian kernels as well, which at the moment get an invalid indirect pointer argument. Calling aac_ioctl() instead of aac_compat_do_ioctl() means the compat and native code paths behave the same way again, which they stopped when the adapter health check was added only in the native function. Fixes: 572ee53a9bad ("scsi: aacraid: check adapter health") Reviewed-by: Christoph Hellwig Signed-off-by: Arnd Bergmann --- drivers/scsi/aacraid/commctrl.c | 22 ++++++++++-- drivers/scsi/aacraid/linit.c | 61 ++------------------------------- 2 files changed, 22 insertions(+), 61 deletions(-) diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 59e82a832042..3588360211e0 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /* ssleep prototype */ #include #include @@ -226,6 +227,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) return status; } +struct compat_fib_ioctl { + u32 fibctx; + s32 wait; + compat_uptr_t fib; +}; + /** * next_getadapter_fib - get the next fib * @dev: adapter to use @@ -243,8 +250,19 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) struct list_head * entry; unsigned long flags; - if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) - return -EFAULT; + if (in_compat_syscall()) { + struct compat_fib_ioctl cf; + + if (copy_from_user(&cf, arg, sizeof(struct compat_fib_ioctl))) + return -EFAULT; + + f.fibctx = cf.fibctx; + f.wait = cf.wait; + f.fib = compat_ptr(cf.fib); + } else { + if (copy_from_user(&f, arg, sizeof(struct fib_ioctl))) + return -EFAULT; + } /* * Verify that the HANDLE passed in was a valid AdapterFibContext * diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 8588da0a0655..8c0f55845138 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1182,63 +1182,6 @@ static long aac_cfg_ioctl(struct file *file, return aac_do_ioctl(aac, cmd, (void __user *)arg); } -#ifdef CONFIG_COMPAT -static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg) -{ - long ret; - switch (cmd) { - case FSACTL_MINIPORT_REV_CHECK: - case FSACTL_SENDFIB: - case FSACTL_OPEN_GET_ADAPTER_FIB: - case FSACTL_CLOSE_GET_ADAPTER_FIB: - case FSACTL_SEND_RAW_SRB: - case FSACTL_GET_PCI_INFO: - case FSACTL_QUERY_DISK: - case FSACTL_DELETE_DISK: - case FSACTL_FORCE_DELETE_DISK: - case FSACTL_GET_CONTAINERS: - case FSACTL_SEND_LARGE_FIB: - ret = aac_do_ioctl(dev, cmd, (void __user *)arg); - break; - - case FSACTL_GET_NEXT_ADAPTER_FIB: { - struct fib_ioctl __user *f; - - f = compat_alloc_user_space(sizeof(*f)); - ret = 0; - if (clear_user(f, sizeof(*f))) - ret = -EFAULT; - if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32))) - ret = -EFAULT; - if (!ret) - ret = aac_do_ioctl(dev, cmd, f); - break; - } - - default: - ret = -ENOIOCTLCMD; - break; - } - return ret; -} - -static int aac_compat_ioctl(struct scsi_device *sdev, unsigned int cmd, - void __user *arg) -{ - struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg); -} - -static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - return aac_compat_do_ioctl(file->private_data, cmd, arg); -} -#endif - static ssize_t aac_show_model(struct device *device, struct device_attribute *attr, char *buf) { @@ -1523,7 +1466,7 @@ static const struct file_operations aac_cfg_fops = { .owner = THIS_MODULE, .unlocked_ioctl = aac_cfg_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = aac_compat_cfg_ioctl, + .compat_ioctl = aac_cfg_ioctl, #endif .open = aac_cfg_open, .llseek = noop_llseek, @@ -1536,7 +1479,7 @@ static struct scsi_host_template aac_driver_template = { .info = aac_info, .ioctl = aac_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = aac_compat_ioctl, + .compat_ioctl = aac_ioctl, #endif .queuecommand = aac_queuecommand, .bios_param = aac_biosparm, From patchwork Fri Sep 18 12:15:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 296721 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69BBFC43464 for ; Fri, 18 Sep 2020 12:15:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3378A2078D for ; Fri, 18 Sep 2020 12:15:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726239AbgIRMPm (ORCPT ); Fri, 18 Sep 2020 08:15:42 -0400 Received: from mout.kundenserver.de ([212.227.126.187]:55367 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726064AbgIRMPm (ORCPT ); Fri, 18 Sep 2020 08:15:42 -0400 Received: from threadripper.lan ([149.172.98.151]) by mrelayeu.kundenserver.de (mreue009 [212.227.15.129]) with ESMTPA (Nemesis) id 1MhlCa-1kwiqN2nei-00dnUh; Fri, 18 Sep 2020 14:15:27 +0200 From: Arnd Bergmann To: Kashyap Desai , Sumit Saxena , Shivasharan S , "James E . J . Bottomley" , "Martin K . Petersen" Cc: Christoph Hellwig , anand.lodnoor@broadcom.com, megaraidlinux.pdl@broadcom.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Arnd Bergmann , stable@vger.kernel.org, Christoph Hellwig Subject: [PATCH v2 2/3] scsi: megaraid_sas: check user-provided offsets Date: Fri, 18 Sep 2020 14:15:22 +0200 Message-Id: <20200918121522.1466028-1-arnd@arndb.de> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200918120955.1465510-1-arnd@arndb.de> References: <20200918120955.1465510-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:6kJPcwuHge9uT864Zf5TyvhQnlmxeK+RpOYT34mVoK7SAncOfq9 1wvhRh03/TO74JK8VdAlLNISWQ5JFsbrhhGN08krYQ5ip4disf1Dbd4f2biDPp+wGScYwrk 2eqIMN9aKY5vKPnBcr335Ny6XSIVuPsdE2ZYCeV/dH1z1t5zLmiLylvjF/EJwebLxJi7oyz c/wyKFRfXQ+XgvvduDU/Q== X-UI-Out-Filterresults: notjunk:1; V03:K0:Y1hX+C4mHMY=:43H+a/hVFrzVJMDnWPMiay cx6NyNF/BlpGaJN2VMbhXKnFAUoAFIUL2o8vLIOvto/MOW22o0yxc6vbZrP+4pJ5ClXK0Jo5X pnr1oDmCnyoQr9dx7fzVXeiKj4sGLooEq5wEWP2c5e5zrTV5Sz/dtQU0vV4HsAPmVSeHIDqDv gEjwD7vIHAfesxccLMSReiW+X8cfXePqT5a8dfo6BYewocqUo/vhF+egLvLYZiUghSNzpefRj mWUdAu6vSbciUZaN8RgYVr9F4M1VC0mNRmvzehRL2oxJfgnTkueU0Gp+Ta5U6CbfVPAu+aPFq TxIbLHDZuMy0zd+P2n1ExQccEOoZiBZeZzYFasN6ToW0+01m//yuoNwnc5AsKdI6bDSJqecOx hqdkMmwYfDIkWiEDsi7QsPxbLraN59XYrbDKDO5aijgx/PBqCm2NCuyivOdy03b/X3DG0d/Td aYAhvgCm/KdBURelCzjc9ekESE4IrnNT8ORrcx7vIkSx95SupuvFT033NQ5hd3PkqW9sCSOZb ZkU1n1KGSztPAJj94sTngbby1LrqAM/VowTSXc57ml8oO1HhQoK/rXYXIZgJpSgxOuqmead/N Ssnw5VG1KbXAKySEc53MCZ6c5UQrfmu27A6z3Dt9ZjFq8AJEY+tij/Z0heNxrURLPBAWaAD24 qq0ALub2s/SCZxpnf3kfQjYRv/pSioLhmkpWZd6+xZ7rdXVoR577B1aCazF+XXTnIJrDUTU9r iNzuzGiESeQFdIZd732y8c9SLlL26hd1lRDAPgdLIWTV3lob8LDc+HJp7m0TtC6Obl7uRa65f LP0PFw5RPoZFz4asTLDC4Qh9hBlFaMfn/h04eahR7OexB9VNaLfuq+SHRO88FAoTqjRYArz Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org It sounds unwise to let user space pass an unchecked 32-bit offset into a kernel structure in an ioctl. This is an unsigned variable, so checking the upper bound for the size of the structure it points into is sufficient to avoid data corruption, but as the pointer might also be unaligned, it has to be written carefully as well. While I stumbled over this problem by reading the code, I did not continue checking the function for further problems like it. Cc: # v2.6.15+ Fixes: c4a3e0a529ab ("[SCSI] MegaRAID SAS RAID: new driver") Reviewed-by: Christoph Hellwig Signed-off-by: Arnd Bergmann --- drivers/scsi/megaraid/megaraid_sas_base.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 861f7140f52e..c3de69f3bee8 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -8095,7 +8095,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, int error = 0, i; void *sense = NULL; dma_addr_t sense_handle; - unsigned long *sense_ptr; + void *sense_ptr; u32 opcode = 0; int ret = DCMD_SUCCESS; @@ -8218,6 +8218,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, } if (ioc->sense_len) { + /* make sure the pointer is part of the frame */ + if (ioc->sense_off > (sizeof(union megasas_frame) - sizeof(__le64))) { + error = -EINVAL; + goto out; + } + sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len, &sense_handle, GFP_KERNEL); if (!sense) { @@ -8225,12 +8231,11 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, goto out; } - sense_ptr = - (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off); + sense_ptr = (void *)cmd->frame + ioc->sense_off; if (instance->consistent_mask_64bit) - *sense_ptr = cpu_to_le64(sense_handle); + put_unaligned_le64(sense_handle, sense_ptr); else - *sense_ptr = cpu_to_le32(sense_handle); + put_unaligned_le32(sense_handle, sense_ptr); } /* From patchwork Fri Sep 18 12:15:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 257594 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 48B81C43464 for ; Fri, 18 Sep 2020 12:16:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0732E20870 for ; Fri, 18 Sep 2020 12:16:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726312AbgIRMQD (ORCPT ); Fri, 18 Sep 2020 08:16:03 -0400 Received: from mout.kundenserver.de ([212.227.126.135]:37225 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726064AbgIRMQD (ORCPT ); Fri, 18 Sep 2020 08:16:03 -0400 Received: from threadripper.lan ([149.172.98.151]) by mrelayeu.kundenserver.de (mreue012 [212.227.15.129]) with ESMTPA (Nemesis) id 1MC0HF-1kBnB91zTx-00CUmb; Fri, 18 Sep 2020 14:15:46 +0200 From: Arnd Bergmann To: Kashyap Desai , Sumit Saxena , Shivasharan S , "James E . J . Bottomley" , "Martin K . Petersen" Cc: Christoph Hellwig , anand.lodnoor@broadcom.com, megaraidlinux.pdl@broadcom.com, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Arnd Bergmann Subject: [PATCH v2 3/3] scsi: megaraid_sas: simplify compat_ioctl handling Date: Fri, 18 Sep 2020 14:15:43 +0200 Message-Id: <20200918121543.1466090-1-arnd@arndb.de> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200918120955.1465510-1-arnd@arndb.de> References: <20200918120955.1465510-1-arnd@arndb.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:z9AIGG+qS63xAkhNlR+tgy9b3xlu4k/PonUBJLNH95P0Poita0W fWz2zaCv8oJCc8irsoaaVWIZqh6Z461i52DpIZsRIBRmm2Matu8bljNwTZuEp6pAayFItl7 MscbRKByL+0oLuwzRa9WN9NnJ3++ret0seWRJWKn1brE4BuXX/1jKinvZYv1k99Tkd1D9ua ncUevfikahluC74aHNQsw== X-UI-Out-Filterresults: notjunk:1; V03:K0:AERzY+NEGTU=:Dkbr3VlSvDqGNAeMasPAMr lK6edekI1h9ORqVKN2vq84L8Dat+Wpk0sT6UZBkAbyDcq/GisyUuYVQAHU5GAqtULUxdmWDlZ pDOID+4rJJLII9OSid3H2K8OTJ0/L0fwEJ8dOOqAp/jFmWWS/DpO0xumOcM1vAvHZgtStiY5v /6WVS5wWydkXEVotqWfoZBWzupLwRUfa1eSNgURal+1XlpUSU+la8iSaCh1ErXUU0i0dwQGjB wREHC0y62hjY0CpUrN8XusrdrQ0neU+k0fPiJAjyVIp05Vc3klTMiU3ppZ0eFz72Lb3KQMZSL uhLPkqaug1raIIcXQVOd99sv7JlmaRfZ19axnBGWcwVdOWPXXc6F1lzdhUqI3/Om24rgcg31U rq+zua5VhWMMGqEvamUl8PiHaq9jSyBprh4IA7Om3PnCqJSW+oq1N0c1td9P/NN+RuGvi/cqf fLG9v3/95mdTlzOV93YAIMoU83uxHufG/g35xLOZ/WE8j8YqOn0OwDC1BQHnnsJhtktiLs+fa 6iBwMLCXxAwfLU2rHrnZzHrzD8u+lNUILwuLu3NaPsNrZJ67nJbpObkZdiBaqT9FOVNbFk4Iu QWTDa9JicFrikkowRz+PU1mpTQCoMzFbso7ehTlEL7uu/Wzcl77/AxvHDtl+LpZLuvy4ShCdl oC7epELAtUu3I8o65e6SOql6NaJEOHd5pSpvdF77U50flJh6lzibSzq9GdknUs1IGu86dzGEp c5mBuLaTsZLspUlvCr5SpcNaCUFOJQ1WLWFPjvWOM0Ox9+EQyLvUax2MaValN/nAISBagSoqR R6mYPfJ8/UjOSzqy+b89IBllvc4V/cQ8Smfbpx4KjcdIajgZZKMgdM2mrA7uZju409QTcMz Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org There have been several attempts to fix serious problems in the compat handling in megasas_mgmt_compat_ioctl_fw(), and it also uses the compat_alloc_user_space() function. Folding the compat handling into the regular ioctl function with in_compat_syscall() simplifies it a lot and avoids some of the remaining problems: - missing handling of unaligned pointers - overflowing the ioc->frame.raw array from invalid input - compat_alloc_user_space() Signed-off-by: Arnd Bergmann Reviewed-by: Christoph Hellwig --- v2: address review comments from hch --- drivers/scsi/megaraid/megaraid_sas.h | 2 - drivers/scsi/megaraid/megaraid_sas_base.c | 117 +++++++++------------- include/linux/compat.h | 10 +- 3 files changed, 50 insertions(+), 79 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 5e4137f10e0e..0f808d63580e 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2605,7 +2605,6 @@ struct megasas_aen { u32 class_locale_word; } __attribute__ ((packed)); -#ifdef CONFIG_COMPAT struct compat_megasas_iocpacket { u16 host_no; u16 __pad1; @@ -2621,7 +2620,6 @@ struct compat_megasas_iocpacket { } __attribute__ ((packed)); #define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) -#endif #define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket) #define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index c3de69f3bee8..d91951ee16ab 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -8279,16 +8279,18 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, * copy out the sense */ if (ioc->sense_len) { + void __user *uptr; /* * sense_ptr points to the location that has the user * sense buffer address */ - sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw + - ioc->sense_off); + sense_ptr = (void *)ioc->frame.raw + ioc->sense_off; + if (in_compat_syscall()) + uptr = compat_ptr(get_unaligned((u32 *)sense_ptr)); + else + uptr = get_unaligned((void __user **)sense_ptr); - if (copy_to_user((void __user *)((unsigned long) - get_unaligned((unsigned long *)sense_ptr)), - sense, ioc->sense_len)) { + if (copy_to_user(uptr, sense, ioc->sense_len)) { dev_err(&instance->pdev->dev, "Failed to copy out to user " "sense data\n"); error = -EFAULT; @@ -8331,6 +8333,38 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, return error; } +static struct megasas_iocpacket * +megasas_compat_iocpacket_get_user(void __user *arg) +{ + struct megasas_iocpacket *ioc; + struct compat_megasas_iocpacket __user *cioc = arg; + size_t size; + int err = -EFAULT; + int i; + + ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) + return ERR_PTR(-ENOMEM); + size = offsetof(struct megasas_iocpacket, frame) + sizeof(ioc->frame); + if (copy_from_user(ioc, arg, size)) + goto out; + + for (i = 0; i < MAX_IOCTL_SGE; i++) { + compat_uptr_t iov_base; + if (get_user(iov_base, &cioc->sgl[i].iov_base) || + get_user(ioc->sgl[i].iov_len, &cioc->sgl[i].iov_len)) { + goto out; + } + ioc->sgl[i].iov_base = compat_ptr(iov_base); + } + + return ioc; +out: + kfree(ioc); + + return ERR_PTR(err); +} + static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) { struct megasas_iocpacket __user *user_ioc = @@ -8339,7 +8373,11 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) struct megasas_instance *instance; int error; - ioc = memdup_user(user_ioc, sizeof(*ioc)); + if (in_compat_syscall()) + ioc = megasas_compat_iocpacket_get_user(user_ioc); + else + ioc = memdup_user(user_ioc, sizeof(struct megasas_iocpacket)); + if (IS_ERR(ioc)) return PTR_ERR(ioc); @@ -8444,78 +8482,13 @@ megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT -static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) -{ - struct compat_megasas_iocpacket __user *cioc = - (struct compat_megasas_iocpacket __user *)arg; - struct megasas_iocpacket __user *ioc = - compat_alloc_user_space(sizeof(struct megasas_iocpacket)); - int i; - int error = 0; - compat_uptr_t ptr; - u32 local_sense_off; - u32 local_sense_len; - u32 user_sense_off; - - if (clear_user(ioc, sizeof(*ioc))) - return -EFAULT; - - if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) || - copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) || - copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) || - copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) || - copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) || - copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32))) - return -EFAULT; - - /* - * The sense_ptr is used in megasas_mgmt_fw_ioctl only when - * sense_len is not null, so prepare the 64bit value under - * the same condition. - */ - if (get_user(local_sense_off, &ioc->sense_off) || - get_user(local_sense_len, &ioc->sense_len) || - get_user(user_sense_off, &cioc->sense_off)) - return -EFAULT; - - if (local_sense_off != user_sense_off) - return -EINVAL; - - if (local_sense_len) { - void __user **sense_ioc_ptr = - (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off); - compat_uptr_t *sense_cioc_ptr = - (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off); - if (get_user(ptr, sense_cioc_ptr) || - put_user(compat_ptr(ptr), sense_ioc_ptr)) - return -EFAULT; - } - - for (i = 0; i < MAX_IOCTL_SGE; i++) { - if (get_user(ptr, &cioc->sgl[i].iov_base) || - put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) || - copy_in_user(&ioc->sgl[i].iov_len, - &cioc->sgl[i].iov_len, sizeof(compat_size_t))) - return -EFAULT; - } - - error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc); - - if (copy_in_user(&cioc->frame.hdr.cmd_status, - &ioc->frame.hdr.cmd_status, sizeof(u8))) { - printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n"); - return -EFAULT; - } - return error; -} - static long megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case MEGASAS_IOC_FIRMWARE32: - return megasas_mgmt_compat_ioctl_fw(file, arg); + return megasas_mgmt_ioctl_fw(file, arg); case MEGASAS_IOC_GET_AEN: return megasas_mgmt_ioctl_aen(file, arg); } diff --git a/include/linux/compat.h b/include/linux/compat.h index 1a530e1aa15a..a7a5a0ff59ef 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -91,6 +91,11 @@ static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) #endif /* COMPAT_SYSCALL_DEFINEx */ +struct compat_iovec { + compat_uptr_t iov_base; + compat_size_t iov_len; +}; + #ifdef CONFIG_COMPAT #ifndef compat_user_stack_pointer @@ -248,11 +253,6 @@ typedef struct compat_siginfo { } _sifields; } compat_siginfo_t; -struct compat_iovec { - compat_uptr_t iov_base; - compat_size_t iov_len; -}; - struct compat_rlimit { compat_ulong_t rlim_cur; compat_ulong_t rlim_max;