From 697013072345a1231dbca836f65a6d635b255685 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Wed, 16 Nov 2016 15:03:16 +0800 Subject: [PATCH] fbdev/fb_notify: fix blank_mode pointer crash When fb event is not blank event, use *((int *)event->data) for blank_mode is very dangerous, see follow code on drivers/video/fbdev/core/fbmem.c: struct fb_event event; event.info = fb_info; fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); On FB_EVENT_FB_REGISTERED event, event->data is not initial, so get value from *(int*)event->data would crash. crash: [ 0.909647] Unable to handle kernel paging request at virtual address 12c000000000 [ 0.915506] pgd = ffffff8009147000 [ 0.915808] [12c000000000] *pgd=00000000f6ff9003, *pud=00000000f6ff9003, *pmd=0000000000000000 [ 0.916577] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 0.917067] Modules linked in: [ 0.917347] CPU: 4 PID: 51 Comm: kworker/u12:1 Not tainted 4.4.30 [ 0.917919] Hardware name: Rockchip RK3399 Evaluation Board v1 (Android) (DT) [ 1.098438] [] rkvr_fb_event_notify+0x38/0x18c [ 1.098976] [] notifier_call_chain+0x48/0x80 [ 1.099499] [] __blocking_notifier_call_chain+0x48/0x64 [ 1.100104] [] blocking_notifier_call_chain+0x14/0x1c [ 1.100699] [] fb_notifier_call_chain+0x44/0x50 [ 1.101242] [] register_framebuffer+0x1bc/0x288 [ 1.101790] [] drm_fb_helper_initial_config+0x2c0/0x354 [ 1.102395] [] rockchip_drm_fbdev_init+0xc8/0x104 [ 1.102957] [] rockchip_drm_load+0x91c/0x9c4 [ 1.103478] [] drm_dev_register+0x78/0xc0 [ 1.103978] [] rockchip_drm_bind+0x64/0x90 [ 1.104488] [] try_to_bring_up_master.part.3+0xb0/0x118 [ 1.105093] [] component_master_add_with_match+0xcc/0x12c [ 1.105714] [] rockchip_drm_platform_probe+0x198/0x1c8 [ 1.106313] [] platform_drv_probe+0x58/0xa4 [ 1.106827] [] driver_probe_device+0x114/0x280 [ 1.107362] [] __device_attach_driver+0x88/0x98 [ 1.107905] [] bus_for_each_drv+0x7c/0xac [ 1.108402] [] __device_attach+0xa8/0x128 [ 1.108900] [] device_initial_probe+0x10/0x18 [ 1.109427] [] bus_probe_device+0x2c/0x8c [ 1.109924] [] deferred_probe_work_func+0x74/0xa0 [ 1.110486] [] process_one_work+0x218/0x3e0 [ 1.111001] [] worker_thread+0x24c/0x374 [ 1.111490] [] kthread+0xe8/0xf0 [ 1.111922] [] ret_from_fork+0x10/0x40 Change-Id: I11f667830d913430d9e0b4da2b391815d335ecb8 Signed-off-by: Mark Yao --- arch/arm/mach-rockchip/ddr_freq.c | 5 ++--- arch/arm/mach-rockchip/dvfs.c | 4 ++-- arch/arm/mach-rockchip/rk3288.c | 5 ++--- drivers/hid/hid-rkvr.c | 4 +++- drivers/input/sensors/hall/mh248.c | 5 ++--- drivers/input/touchscreen/rockchip_gslX680_rk3128.c | 5 ++--- drivers/input/touchscreen/zet62xx/zet62xx.c | 6 ++---- drivers/power/rk818_battery.c | 3 +++ drivers/video/rockchip/dp/rockchip_dp.c | 5 ++--- .../video/rockchip/hdmi/rockchip-hdmiv1/rockchip_hdmiv1.c | 5 ++--- .../video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.c | 5 ++--- drivers/video/rockchip/tve/gm7122/gm7122_tve.c | 5 ++--- drivers/video/rockchip/tve/rk1000/rk1000_tve.c | 6 ++---- drivers/video/rockchip/tve/rk3036/rk3036_tve.c | 5 ++--- 14 files changed, 30 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-rockchip/ddr_freq.c b/arch/arm/mach-rockchip/ddr_freq.c index 470587b22efd..ea229d7aeafd 100644 --- a/arch/arm/mach-rockchip/ddr_freq.c +++ b/arch/arm/mach-rockchip/ddr_freq.c @@ -782,10 +782,9 @@ static int ddr_freq_suspend_notifier_call(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: rockchip_clear_system_status(SYS_STATUS_SUSPEND); break; @@ -794,7 +793,7 @@ static int ddr_freq_suspend_notifier_call(struct notifier_block *self, } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_POWERDOWN: rockchip_set_system_status(SYS_STATUS_SUSPEND); break; diff --git a/arch/arm/mach-rockchip/dvfs.c b/arch/arm/mach-rockchip/dvfs.c index f189f87cab1a..18d98e4dfccc 100644 --- a/arch/arm/mach-rockchip/dvfs.c +++ b/arch/arm/mach-rockchip/dvfs.c @@ -150,7 +150,7 @@ static int early_suspend_notifier_call(struct notifier_block *self, mutex_lock(&switch_vdd_gpu_mutex); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: early_suspend = 0; if (pd_gpu_off) { @@ -163,7 +163,7 @@ static int early_suspend_notifier_call(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_POWERDOWN: early_suspend = 1; if (pd_gpu_off) { diff --git a/arch/arm/mach-rockchip/rk3288.c b/arch/arm/mach-rockchip/rk3288.c index 0a768a98ba06..ca1ccbc40728 100755 --- a/arch/arm/mach-rockchip/rk3288.c +++ b/arch/arm/mach-rockchip/rk3288.c @@ -503,11 +503,10 @@ static int rk3288_pll_early_suspend_notifier_call(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); static bool enable = false; if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: if (!enable) { clk_prepare_enable(clk_get_sys(NULL, "clk_cpll")); @@ -519,7 +518,7 @@ static int rk3288_pll_early_suspend_notifier_call(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_POWERDOWN: if (enable) { clk_disable_unprepare(clk_get_sys(NULL, "clk_cpll")); diff --git a/drivers/hid/hid-rkvr.c b/drivers/hid/hid-rkvr.c index 0bdafb380a5f..eada6a54c520 100644 --- a/drivers/hid/hid-rkvr.c +++ b/drivers/hid/hid-rkvr.c @@ -1264,11 +1264,13 @@ static int rkvr_fb_event_notify(struct notifier_block *self, unsigned char buf[3] = {HID_REPORT_ID_RKVR, RKVR_ID_IDLE, 0}; struct hid_device *hid; struct fb_event *event = data; - int blank_mode = *((int *)event->data); + int blank_mode; if (action != FB_EARLY_EVENT_BLANK && action != FB_EVENT_BLANK) return NOTIFY_OK; + blank_mode = *((int *)event->data); + mutex_lock(&minors_lock); for (i = 0; i < RKVR_HIDRAW_MAX_DEVICES; i++) { if (!rkvr_hidraw_table[i] || !rkvr_hidraw_table[i]->exist) diff --git a/drivers/input/sensors/hall/mh248.c b/drivers/input/sensors/hall/mh248.c index 23a02924497b..0fa8a89aee61 100644 --- a/drivers/input/sensors/hall/mh248.c +++ b/drivers/input/sensors/hall/mh248.c @@ -51,13 +51,12 @@ static int hall_fb_notifier_callback(struct notifier_block *self, { struct mh248_para *mh248; struct fb_event *event = data; - int blank_mode = *((int *)event->data); mh248 = container_of(self, struct mh248_para, fb_notif); mutex_lock(&mh248->ops_lock); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -65,7 +64,7 @@ static int hall_fb_notifier_callback(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: mh248->is_suspend = 0; break; diff --git a/drivers/input/touchscreen/rockchip_gslX680_rk3128.c b/drivers/input/touchscreen/rockchip_gslX680_rk3128.c index a29ba0af10a9..691ae7c97ffc 100755 --- a/drivers/input/touchscreen/rockchip_gslX680_rk3128.c +++ b/drivers/input/touchscreen/rockchip_gslX680_rk3128.c @@ -791,10 +791,9 @@ static int gsl_ts_fb_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -802,7 +801,7 @@ static int gsl_ts_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: gsl_ts_resume(); break; diff --git a/drivers/input/touchscreen/zet62xx/zet62xx.c b/drivers/input/touchscreen/zet62xx/zet62xx.c index 90e77ad4138d..bee69d6f0845 100755 --- a/drivers/input/touchscreen/zet62xx/zet62xx.c +++ b/drivers/input/touchscreen/zet62xx/zet62xx.c @@ -4446,11 +4446,9 @@ static int zet622x_ts_fb_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); - if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -4458,7 +4456,7 @@ static int zet622x_ts_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: zet622x_ts_late_resume(); break; diff --git a/drivers/power/rk818_battery.c b/drivers/power/rk818_battery.c index f9e6d8f7c4bd..7933fcd979e1 100644 --- a/drivers/power/rk818_battery.c +++ b/drivers/power/rk818_battery.c @@ -1051,6 +1051,9 @@ static int rk818_bat_fb_notifier(struct notifier_block *nb, struct rk818_battery *di; struct fb_event *evdata = data; + if (event != FB_EARLY_EVENT_BLANK && event != FB_EVENT_BLANK) + return NOTIFY_OK; + di = container_of(nb, struct rk818_battery, fb_nb); di->fb_blank = *(int *)evdata->data; diff --git a/drivers/video/rockchip/dp/rockchip_dp.c b/drivers/video/rockchip/dp/rockchip_dp.c index d46f5eda4cab..9a9a6f31972f 100644 --- a/drivers/video/rockchip/dp/rockchip_dp.c +++ b/drivers/video/rockchip/dp/rockchip_dp.c @@ -172,11 +172,10 @@ static int rockchip_dp_fb_event_notify(struct notifier_block *self, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); struct dp_dev *dp_dev = container_of(self, struct dp_dev, fb_notif); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -187,7 +186,7 @@ static int rockchip_dp_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: if (dp_dev->hdmi->sleep) { dp_dev->early_suspended = false; diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmiv1/rockchip_hdmiv1.c b/drivers/video/rockchip/hdmi/rockchip-hdmiv1/rockchip_hdmiv1.c index 88610b8352d4..b11380fd25f2 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmiv1/rockchip_hdmiv1.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmiv1/rockchip_hdmiv1.c @@ -162,10 +162,9 @@ static int rockchip_hdmiv1_fb_event_notify(struct notifier_block *self, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -174,7 +173,7 @@ static int rockchip_hdmiv1_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: if (hdmi_dev->hdmi->sleep) rockchip_hdmiv1_early_resume(); diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.c b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.c index 6e607a27d993..4f7ee815035e 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.c @@ -330,7 +330,6 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); struct hdmi *hdmi = hdmi_dev->hdmi; struct pinctrl_state *gpio_state; #ifdef CONFIG_PINCTRL @@ -338,7 +337,7 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self, #endif if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -368,7 +367,7 @@ static int rockchip_hdmiv2_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: HDMIDBG("resume hdmi\n"); if (hdmi->sleep) { diff --git a/drivers/video/rockchip/tve/gm7122/gm7122_tve.c b/drivers/video/rockchip/tve/gm7122/gm7122_tve.c index 47642c762d94..4e8d92f27ece 100755 --- a/drivers/video/rockchip/tve/gm7122/gm7122_tve.c +++ b/drivers/video/rockchip/tve/gm7122/gm7122_tve.c @@ -282,10 +282,9 @@ tve_fb_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -300,7 +299,7 @@ tve_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: TVEDBG("resume tve\n"); if (gm7122_tve->suspend) { diff --git a/drivers/video/rockchip/tve/rk1000/rk1000_tve.c b/drivers/video/rockchip/tve/rk1000/rk1000_tve.c index a21c08851795..9bd6c0fe3f38 100755 --- a/drivers/video/rockchip/tve/rk1000/rk1000_tve.c +++ b/drivers/video/rockchip/tve/rk1000/rk1000_tve.c @@ -256,12 +256,10 @@ static int rk1000_fb_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event; - int blank_mode; event = data; - blank_mode = *((int *)event->data); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -269,7 +267,7 @@ static int rk1000_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: rk1000_early_resume(NULL); break; diff --git a/drivers/video/rockchip/tve/rk3036/rk3036_tve.c b/drivers/video/rockchip/tve/rk3036/rk3036_tve.c index b8415412dd1b..337fa346edd6 100755 --- a/drivers/video/rockchip/tve/rk3036/rk3036_tve.c +++ b/drivers/video/rockchip/tve/rk3036/rk3036_tve.c @@ -290,10 +290,9 @@ tve_fb_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; - int blank_mode = *((int *)event->data); if (action == FB_EARLY_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: break; default: @@ -310,7 +309,7 @@ tve_fb_event_notify(struct notifier_block *self, break; } } else if (action == FB_EVENT_BLANK) { - switch (blank_mode) { + switch (*((int *)event->data)) { case FB_BLANK_UNBLANK: TVEDBG("resume tve\n"); mutex_lock(&rk3036_tve->tve_lock); -- 2.34.1