From patchwork Tue May 31 14:00:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 9144897 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 CF7F160761 for ; Tue, 31 May 2016 14:00:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B8BA8208C2 for ; Tue, 31 May 2016 14:00:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ABBFE2793B; Tue, 31 May 2016 14:00:24 +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 762BA208C2 for ; Tue, 31 May 2016 14:00:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752884AbcEaOAV (ORCPT ); Tue, 31 May 2016 10:00:21 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:58258 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752505AbcEaOAU (ORCPT ); Tue, 31 May 2016 10:00:20 -0400 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout2.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O8100593O8FVH60@mailout2.w1.samsung.com>; Tue, 31 May 2016 15:00:15 +0100 (BST) X-AuditID: cbfec7f4-f796c6d000001486-77-574d98efb48b Received: from eusync4.samsung.com ( [203.254.199.214]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id F3.13.05254.FE89D475; Tue, 31 May 2016 15:00:15 +0100 (BST) Received: from AMDC2174.DIGITAL.local ([106.120.53.17]) by eusync4.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0O81009ECO8CIM20@eusync4.samsung.com>; Tue, 31 May 2016 15:00:15 +0100 (BST) From: Krzysztof Kozlowski To: Greg Kroah-Hartman , Jiri Slaby , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org Cc: Bartlomiej Zolnierkiewicz , Sylwester Nawrocki , Krzysztof Kozlowski , stable@vger.kernel.org Subject: [PATCH v2 1/2] serial: samsung: Fix ERR pointer dereference on deferred probe Date: Tue, 31 May 2016 16:00:05 +0200 Message-id: <1464703206-1615-1-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.9.1 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpkluLIzCtJLcpLzFFi42I5/e/4Nd33M3zDDdpmGVlsnLGe1aJ58Xo2 iykbPjBZvH5haHF51xw2ixnn9zFZnFncy25x+E07q8WCjY8YHTg99s9dw+7Rt2UVo8f6LVdZ PD5vkgtgieKySUnNySxLLdK3S+DKeL+7maVgm3zF3UVPWRoYp0p1MXJySAiYSLzcNYMRwhaT uHBvPVsXIxeHkMBSRom3M7cyQTiNTBKvpv5mB6liEzCW2Lx8CViViMAWRol1Tx8ygjjMAhsY JZ423gdyODiEBSIkdpzTAGlgEVCV2P9kAhuIzSvgJnHnzQM2iHVyEiePTWadwMi9gJFhFaNo amlyQXFSeq6hXnFibnFpXrpecn7uJkZIwHzZwbj4mNUhRgEORiUe3shun3Ah1sSy4srcQ4wS HMxKIrzF033DhXhTEiurUovy44tKc1KLDzFKc7AoifPO3fU+REggPbEkNTs1tSC1CCbLxMEp 1cBoKb+ztZAj5pq85au7Eu4u6fsS175aFrVn29lzOUkCu0Pb1bef7WjcW3ZSWG2bjJlM+ccs ZQ27zK178iY8MKsv3iRxO+d6r6ajT0vF+1ecxyczl+fJTXaOMxDZm7bF5PjyVUdULxjMif5r 7+o+4XDJ06DG9C+R2/mXzgpaZLTqg0hPUnHBbhslluKMREMt5qLiRACEPp6qFAIAAA== Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When the clk_get() of "uart" clock returns EPROBE_DEFER, the next re-probe finishes with success but uses invalid (ERR_PTR) values. This leads to dereferencing of ERR_PTR stored under ourport->clk: 12c30000.serial: Controller clock not found (...) 12c30000.serial: ttySAC3 at MMIO 0x12c30000 (irq = 61, base_baud = 0) is a S3C6400/10 Unable to handle kernel paging request at virtual address fffffdfb (clk_prepare) from [] (s3c24xx_serial_pm+0x20/0x128) (s3c24xx_serial_pm) from [] (uart_change_pm+0x38/0x40) (uart_change_pm) from [] (uart_add_one_port+0x31c/0x44c) (uart_add_one_port) from [] (s3c24xx_serial_probe+0x2a8/0x418) (s3c24xx_serial_probe) from [] (platform_drv_probe+0x50/0xb0) (platform_drv_probe) from [] (driver_probe_device+0x1f4/0x2b0) (driver_probe_device) from [] (bus_for_each_drv+0x44/0x8c) (bus_for_each_drv) from [] (__device_attach+0x9c/0x100) (__device_attach) from [] (bus_probe_device+0x84/0x8c) (bus_probe_device) from [] (deferred_probe_work_func+0x60/0x8c) (deferred_probe_work_func) from [] (process_one_work+0x120/0x328) (process_one_work) from [] (worker_thread+0x2c/0x4ac) (worker_thread) from [] (kthread+0xd8/0xf4) (kthread) from [] (ret_from_fork+0x14/0x3c) The first unsuccessful clk_get() causes s3c24xx_serial_init_port() to exit with failure but the s3c24xx_uart_port is left half-configured (e.g. port->mapbase is set, clk contains ERR_PTR). On next re-probe, the function s3c24xx_serial_init_port() will exit early with success because of configured port->mapbase and driver will use old values, including the ERR_PTR as clock. Fix this by cleaning the port->mapbase on error path so each re-probe will initialize all of the port settings. Fixes: 60e93575476f ("serial: samsung: enable clock before clearing pending interrupts during init") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Tested-by: Kevin Hilman --- Changes since v1: 1. Apply suggestion from Bartlomiej (offline) that early check for port->mapbase in s3c24xx_serial_init_port() should fail if it is already set. The port->mapbase is now always cleared when probe fails, so re-probing with 'port->mapbase != 0' is unexpected. --- drivers/tty/serial/samsung.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 99bb23161dd6..f0bd2ec0db59 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1684,7 +1684,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, return -ENODEV; if (port->mapbase != 0) - return 0; + return -EINVAL; /* setup info for port */ port->dev = &platdev->dev; @@ -1738,22 +1738,25 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->dma = devm_kzalloc(port->dev, sizeof(*ourport->dma), GFP_KERNEL); - if (!ourport->dma) - return -ENOMEM; + if (!ourport->dma) { + ret = -ENOMEM; + goto err; + } } ourport->clk = clk_get(&platdev->dev, "uart"); if (IS_ERR(ourport->clk)) { pr_err("%s: Controller clock not found\n", dev_name(&platdev->dev)); - return PTR_ERR(ourport->clk); + ret = PTR_ERR(ourport->clk); + goto err; } ret = clk_prepare_enable(ourport->clk); if (ret) { pr_err("uart: clock failed to prepare+enable: %d\n", ret); clk_put(ourport->clk); - return ret; + goto err; } /* Keep all interrupts masked and cleared */ @@ -1769,7 +1772,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* reset the fifos (and setup the uart) */ s3c24xx_serial_resetport(port, cfg); + return 0; + +err: + port->mapbase = 0; + return ret; } /* Device driver serial port probe */