From patchwork Fri Jan 20 07:34:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Lin X-Patchwork-Id: 9527623 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 808FA60434 for ; Fri, 20 Jan 2017 07:36:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7137C285DF for ; Fri, 20 Jan 2017 07:36:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 65ADA28642; Fri, 20 Jan 2017 07:36:57 +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=-6.9 required=2.0 tests=BAYES_00,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 1D5B3285DF for ; Fri, 20 Jan 2017 07:36:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751324AbdATHgj (ORCPT ); Fri, 20 Jan 2017 02:36:39 -0500 Received: from lucky1.263xmail.com ([211.157.147.135]:43530 "EHLO lucky1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751320AbdATHgj (ORCPT ); Fri, 20 Jan 2017 02:36:39 -0500 Received: from shawn.lin?rock-chips.com (unknown [192.168.167.11]) by lucky1.263xmail.com (Postfix) with ESMTP id 4455F83F; Fri, 20 Jan 2017 15:35:43 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 1 X-MAIL-DELIVERY: 0 X-KSVirus-check: 0 X-ABS-CHECKED: 4 Received: from localhost.localdomain (localhost [127.0.0.1]) by smtp.263.net (Postfix) with ESMTP id B08BE3A7; Fri, 20 Jan 2017 15:35:42 +0800 (CST) X-RL-SENDER: shawn.lin@rock-chips.com X-FST-TO: ulf.hansson@linaro.org X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: shawn.lin@rock-chips.com X-UNIQUE-TAG: <775dc85dd92eac4b2eb95fbb3c6c7e88> X-ATTACHMENT-NUM: 0 X-SENDER: lintao@rock-chips.com X-DNS-TYPE: 0 Received: from localhost.localdomain (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith ESMTP id 6693KQQJOQ; Fri, 20 Jan 2017 15:35:43 +0800 (CST) From: Shawn Lin To: Ulf Hansson Cc: linux-mmc@vger.kernel.org, Shawn Lin Subject: [PATCH v2] mmc: sdio: check the buffer address for sdio API Date: Fri, 20 Jan 2017 15:34:01 +0800 Message-Id: <1484897641-216803-1-git-send-email-shawn.lin@rock-chips.com> X-Mailer: git-send-email 1.9.1 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP It's fine if the host driver use PIO mode to transfer the vmalloc area buffer but not for DMA mode. The sdio APIs haven't provide the capability to tell the caller whether it will use DMA to finish the IO transfer or not, so don't give the randomly insmoded sdio function driver the possibility to break the kernel. Also the APIs shouldn't take the liberty to do a copy for these cases and just kick out these requests should be enough. This issue is observed by doing insmod a downloaded wifi module driver and the kernel panic right away. Unfortunately we don't have the source code but adding this patch that it proves that the module driver was passing on a vmalloc area buffer for sdio APIs. It could very easy to be reproduced by writing a simple function module driver and insmod it, and panic log looks like: unsigned u8 __aligned(32) buf[PAGE_SIZE]; static int wifi_probe(struct sdio_func *func, const struct sdio_device_id *id) { sdio_claim_host(func); sdio_enable_func(func); sdio_memcpy_toio(func, 0x0, buf, 0x200); } [ 236.748210] wifi_probe: buf = 0xffffff8000a40b80 [ 236.748258] swiotlb_tbl_map_single: orig_addr = 0xfffffffff8c40b80, tlb_addr = 0xf7eae000 //I added log here [ 236.748276] Unable to handle kernel paging request at virtual address fffffffff8c40b80 [ 236.776486] pgd = ffffffc0b3417000 [ 236.776789] [fffffffff8c40b80] *pgd=00000000b3427003, *pud=00000000b3427003, *pmd=0000000000000000 [ 236.777601] Internal error: Oops: 96000005 [#1] PREEMPT SMP [ 236.778093] Modules linked in: drvtst(O+) [ 236.778463] CPU: 0 PID: 1918 Comm: insmod Tainted: G O 4.4.36 #25 [ 236.779096] Hardware name: Rockchip RK3399 Evaluation Board v3 edp (Android) (DT) [ 236.779753] task: ffffffc0e3db0c40 ti: ffffffc0b342c000 task.ti: ffffffc0b342c000 [ 236.780418] PC is at __memcpy+0x100/0x180 [ 236.780777] LR is at swiotlb_tbl_map_single+0x254/0x274 [ 236.781237] pc : [] lr : [] ... [ 236.941392] f460: 3d20726464615f67 6666666666783020 [ 236.941826] [] __memcpy+0x100/0x180 [ 236.942274] [] swiotlb_map_sg_attrs+0xa8/0x170 [ 236.942810] [] __swiotlb_map_sg_attrs+0x24/0x8c [ 236.943353] [] dw_mci_pre_dma_transfer.isra.16+0xf0/0x11c [ 236.943967] [] __dw_mci_start_request+0x17c/0x4d0 [ 236.944520] [] dw_mci_request+0xb8/0xf0 [ 236.945002] [] __mmc_start_request+0x9c/0xc0 [ 236.945520] [] mmc_start_request.part.17+0x100/0x11c [ 236.946097] [] mmc_wait_for_req+0x78/0x1a8 [ 236.946600] [] mmc_io_rw_extended+0x27c/0x2fc [ 236.947124] [] sdio_io_rw_ext_helper+0x1e4/0x238 [ 236.947670] [] sdio_memcpy_toio+0x24/0x2c [ 236.948169] [] wifi_probe+0xa8/0x198 [drvtst] [ 236.948708] [] sdio_bus_probe+0xb0/0x140 [ 236.949195] [] driver_probe_device+0x118/0x2b0 [ 236.949724] [] __driver_attach+0x64/0x90 [ 236.950212] [] bus_for_each_dev+0x80/0xb0 [ 236.950706] [] driver_attach+0x20/0x28 [ 236.951176] [] bus_add_driver+0xe8/0x1ec [ 236.951661] [] driver_register+0x98/0xe4 [ 236.952147] [] sdio_register_driver+0x24/0x2c [ 236.952675] [] wifi_sdio_init+0x30/0x68 [drvtst] [ 236.953241] [] wifi_drv_init+0xc/0x38 [drvtst] [ 236.953789] [] do_one_initcall+0x17c/0x198 [ 236.954293] [] do_init_module+0x60/0x1b8 [ 236.954779] [] load_module+0x1660/0x1a50 [ 236.955264] [] SyS_init_module+0x14c/0x180 [ 236.955765] [] el0_svc_naked+0x24/0x28 So the kernel crash since the vmalloc area buffer, on-stack buffer or the on-module buffer aren't physical continuous and swiotlb couldn't find the correct mapping address in fact. Anyway, don't give the chance to panic kernel by using sdio APIs. Signed-off-by: Shawn Lin --- Changes in v2: - add new function to check the addr of vmalloc/module/stack drivers/mmc/core/sdio_io.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 406e5f0..5d0344a 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -298,6 +299,12 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz) } EXPORT_SYMBOL_GPL(sdio_align_size); +static int sdio_io_addr_sanity_check(void *addr) +{ + return (is_vmalloc_or_module_addr(addr) || + object_is_on_stack(addr)); +} + /* Split an arbitrarily sized data transfer into several * IO_RW_EXTENDED commands. */ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, @@ -307,7 +314,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, unsigned max_blocks; int ret; - if (!func || (func->num > 7)) + if (!func || (func->num > 7) || sdio_io_addr_sanity_check(buf)) return -EINVAL; /* Do the bulk of the transfer using block mode (if supported). */