rtc: class: don't call cdev_device_del() when cdev_device_add() failed
authorYang Yingliang <yangyingliang@huawei.com>
Mon, 11 Oct 2021 13:21:14 +0000 (21:21 +0800)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Fri, 15 Oct 2021 19:05:33 +0000 (21:05 +0200)
I got a null-ptr-deref report when doing fault injection test:

general protection fault, probably for non-canonical address 0xdffffc0000000022: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x0000000000000110-0x0000000000000117]
RIP: 0010:device_del+0x132/0xdc0
Call Trace:
 cdev_device_del+0x1a/0x80
 devm_rtc_unregister_device+0x37/0x80
 release_nodes+0xc3/0x3b0

If cdev_device_add() fails, 'dev->p' is not set, it causes
null-ptr-deref when calling cdev_device_del(). Registering
character device is optional, we don't return error code
here, so introduce a new flag 'RTC_NO_CDEV' to indicate
if it has character device, cdev_device_del() is called
when this bit is not set.

Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20211011132114.3663509-1-yangyingliang@huawei.com
drivers/rtc/class.c
include/linux/rtc.h

index f77bc089eb6b758a763ea668f5b809c5c11d9ea6..654e921244bff27e38868f1cd50a4ca0fda6b996 100644 (file)
@@ -334,7 +334,8 @@ static void devm_rtc_unregister_device(void *data)
         * letting any rtc_class_open() users access it again
         */
        rtc_proc_del_device(rtc);
-       cdev_device_del(&rtc->char_dev, &rtc->dev);
+       if (!test_bit(RTC_NO_CDEV, &rtc->flags))
+               cdev_device_del(&rtc->char_dev, &rtc->dev);
        rtc->ops = NULL;
        mutex_unlock(&rtc->ops_lock);
 }
@@ -397,12 +398,14 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc)
        rtc_dev_prepare(rtc);
 
        err = cdev_device_add(&rtc->char_dev, &rtc->dev);
-       if (err)
+       if (err) {
+               set_bit(RTC_NO_CDEV, &rtc->flags);
                dev_warn(rtc->dev.parent, "failed to add char device %d:%d\n",
                         MAJOR(rtc->dev.devt), rtc->id);
-       else
+       } else {
                dev_dbg(rtc->dev.parent, "char device (%d:%d)\n",
                        MAJOR(rtc->dev.devt), rtc->id);
+       }
 
        rtc_proc_add_device(rtc);
 
index bd611e26291d456eb43503f1079fd28c1aa377d0..354e0843ab17f4ec3bd3cb8403b9b36bd819fe15 100644 (file)
@@ -80,6 +80,7 @@ struct rtc_timer {
 
 /* flags */
 #define RTC_DEV_BUSY 0
+#define RTC_NO_CDEV  1
 
 struct rtc_device {
        struct device dev;