From 789c1093f02c436b320d78a739f9610c8271cb73 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 11 Oct 2021 21:21:14 +0800 Subject: [PATCH] rtc: class: don't call cdev_device_del() when cdev_device_add() failed 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 Signed-off-by: Yang Yingliang Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211011132114.3663509-1-yangyingliang@huawei.com --- drivers/rtc/class.c | 9 ++++++--- include/linux/rtc.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index f77bc089eb6b75..654e921244bff2 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -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); diff --git a/include/linux/rtc.h b/include/linux/rtc.h index bd611e26291d45..354e0843ab17f4 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -80,6 +80,7 @@ struct rtc_timer { /* flags */ #define RTC_DEV_BUSY 0 +#define RTC_NO_CDEV 1 struct rtc_device { struct device dev;