| From b49050726d3153185b36bb7e2440a1ddfdf90f7a Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 24 Sep 2018 16:25:34 +0200 |
| Subject: rtc: armada38x: fix possible race condition |
| |
| From: Alexandre Belloni <alexandre.belloni@bootlin.com> |
| |
| [ Upstream commit 7d61cbb945a753af08e247b5f10bdd5dbb8d6c80 ] |
| |
| The IRQ is requested before the struct rtc is allocated and registered, but |
| this struct is used in the IRQ handler. This may lead to a NULL pointer |
| dereference. |
| |
| Switch to devm_rtc_allocate_device/rtc_register_device to allocate the rtc |
| before requesting the IRQ. |
| |
| Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/rtc/rtc-armada38x.c | 22 +++++++++++----------- |
| 1 file changed, 11 insertions(+), 11 deletions(-) |
| |
| diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c |
| index bde53c8ccee2c..b74338d6dde60 100644 |
| --- a/drivers/rtc/rtc-armada38x.c |
| +++ b/drivers/rtc/rtc-armada38x.c |
| @@ -514,7 +514,6 @@ MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); |
| |
| static __init int armada38x_rtc_probe(struct platform_device *pdev) |
| { |
| - const struct rtc_class_ops *ops; |
| struct resource *res; |
| struct armada38x_rtc *rtc; |
| const struct of_device_id *match; |
| @@ -551,6 +550,11 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) |
| dev_err(&pdev->dev, "no irq\n"); |
| return rtc->irq; |
| } |
| + |
| + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); |
| + if (IS_ERR(rtc->rtc_dev)) |
| + return PTR_ERR(rtc->rtc_dev); |
| + |
| if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq, |
| 0, pdev->name, rtc) < 0) { |
| dev_warn(&pdev->dev, "Interrupt not available.\n"); |
| @@ -560,28 +564,24 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) |
| |
| if (rtc->irq != -1) { |
| device_init_wakeup(&pdev->dev, 1); |
| - ops = &armada38x_rtc_ops; |
| + rtc->rtc_dev->ops = &armada38x_rtc_ops; |
| } else { |
| /* |
| * If there is no interrupt available then we can't |
| * use the alarm |
| */ |
| - ops = &armada38x_rtc_ops_noirq; |
| + rtc->rtc_dev->ops = &armada38x_rtc_ops_noirq; |
| } |
| rtc->data = (struct armada38x_rtc_data *)match->data; |
| |
| - |
| /* Update RTC-MBUS bridge timing parameters */ |
| rtc->data->update_mbus_timing(rtc); |
| |
| - rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, |
| - ops, THIS_MODULE); |
| - if (IS_ERR(rtc->rtc_dev)) { |
| - ret = PTR_ERR(rtc->rtc_dev); |
| + ret = rtc_register_device(rtc->rtc_dev); |
| + if (ret) |
| dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); |
| - return ret; |
| - } |
| - return 0; |
| + |
| + return ret; |
| } |
| |
| #ifdef CONFIG_PM_SLEEP |
| -- |
| 2.20.1 |
| |