rtc: armada38x: fix possible race condition
authorAlexandre Belloni <alexandre.belloni@bootlin.com>
Mon, 24 Sep 2018 14:25:34 +0000 (16:25 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Nov 2019 17:47:52 +0000 (18:47 +0100)
[ 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

index bde53c8..b74338d 100644 (file)
@@ -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