From patchwork Tue May 31 11:35:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 9144431 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 7089A60777 for ; Tue, 31 May 2016 11:36:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6382B27BF1 for ; Tue, 31 May 2016 11:36:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5833F28188; Tue, 31 May 2016 11:36:23 +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 85C7F27BF1 for ; Tue, 31 May 2016 11:36:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751293AbcEaLgV (ORCPT ); Tue, 31 May 2016 07:36:21 -0400 Received: from mailout3.w1.samsung.com ([210.118.77.13]:23006 "EHLO mailout3.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750852AbcEaLgU (ORCPT ); Tue, 31 May 2016 07:36:20 -0400 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout3.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O8100AIOHKGPVB0@mailout3.w1.samsung.com>; Tue, 31 May 2016 12:36:16 +0100 (BST) X-AuditID: cbfec7f5-f792a6d000001302-83-574d7730fb63 Received: from eusync4.samsung.com ( [203.254.199.214]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id B4.4B.04866.0377D475; Tue, 31 May 2016 12:36:16 +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 <0O8100CV0HKB4J70@eusync4.samsung.com>; Tue, 31 May 2016 12:36:16 +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: Sylwester Nawrocki , Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz , stable@vger.kernel.org Subject: [PATCH] serial: samsung: Fix ERR pointer dereference on deferred probe Date: Tue, 31 May 2016 13:35:59 +0200 Message-id: <1464694559-29613-1-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.9.1 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpkluLIzCtJLcpLzFFi42I5/e/4NV2Dct9wg/av0hYbZ6xntWhevJ7N YsqGD0wWr18YWlzeNYfNYsb5fUwWZxb3slscftPOarFg4yNGB06P/XPXsHv0bVnF6LF+y1UW j8+b5AJYorhsUlJzMstSi/TtErgyrh+8yVwwQ7qi7coixgbGV2JdjBwcEgImEk1vwrsYOYFM MYkL99azdTFycQgJLGWU2L5pPwuE08gkcenVCSaQKjYBY4nNy5eAVYkIbGGUWPf0ISOIwyyw gVHi9MQN7CBVwgL+EjOmbWEDsVkEVCU+dT9hBbF5BdwlNq85wwaxT07i5LHJrBMYuRcwMqxi FE0tTS4oTkrPNdIrTswtLs1L10vOz93ECAmYrzsYlx6zOsQowMGoxMMb0e0TLsSaWFZcmXuI UYKDWUmEd3mpb7gQb0piZVVqUX58UWlOavEhRmkOFiVx3pm73ocICaQnlqRmp6YWpBbBZJk4 OKUaGK/efKe7tdv+dzJzreWtqk+TBbYsm7eKu0NvLm8Ju7XwrVuBv10WLCtilryyKnZm78l5 nmw8C7e+51CON7pSWLPvhAP/ppT/BjZLGn+FvHV8vOrTBtt1p0uurDB0nnN8+UOeOxxTrK/m TeuqcCy4YFVq6/9QZM5Ekc/px3/1TjukI9l5jn+VcZkSS3FGoqEWc1FxIgDwP/NbFAIAAA== 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 --- drivers/tty/serial/samsung.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 99bb23161dd6..a0183fe936f9 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -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 */