fbdev/fb_notify: fix blank_mode pointer crash
authorMark Yao <mark.yao@rock-chips.com>
Wed, 16 Nov 2016 07:03:16 +0000 (15:03 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 16 Nov 2016 10:39:24 +0000 (18:39 +0800)
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] [<ffffff8008729fb0>] rkvr_fb_event_notify+0x38/0x18c
[    1.098976] [<ffffff80080b8c7c>] notifier_call_chain+0x48/0x80
[    1.099499] [<ffffff80080b8fb8>] __blocking_notifier_call_chain+0x48/0x64
[    1.100104] [<ffffff80080b8fe8>] blocking_notifier_call_chain+0x14/0x1c
[    1.100699] [<ffffff80083e4abc>] fb_notifier_call_chain+0x44/0x50
[    1.101242] [<ffffff80083e6da8>] register_framebuffer+0x1bc/0x288
[    1.101790] [<ffffff8008431e00>] drm_fb_helper_initial_config+0x2c0/0x354
[    1.102395] [<ffffff80084630e4>] rockchip_drm_fbdev_init+0xc8/0x104
[    1.102957] [<ffffff8008459fec>] rockchip_drm_load+0x91c/0x9c4
[    1.103478] [<ffffff800843a4c0>] drm_dev_register+0x78/0xc0
[    1.103978] [<ffffff8008458c0c>] rockchip_drm_bind+0x64/0x90
[    1.104488] [<ffffff800849e93c>] try_to_bring_up_master.part.3+0xb0/0x118
[    1.105093] [<ffffff800849eb68>] component_master_add_with_match+0xcc/0x12c
[    1.105714] [<ffffff80084591e0>] rockchip_drm_platform_probe+0x198/0x1c8
[    1.106313] [<ffffff80084a55b0>] platform_drv_probe+0x58/0xa4
[    1.106827] [<ffffff80084a38a0>] driver_probe_device+0x114/0x280
[    1.107362] [<ffffff80084a3b5c>] __device_attach_driver+0x88/0x98
[    1.107905] [<ffffff80084a1d7c>] bus_for_each_drv+0x7c/0xac
[    1.108402] [<ffffff80084a36d8>] __device_attach+0xa8/0x128
[    1.108900] [<ffffff80084a3ca0>] device_initial_probe+0x10/0x18
[    1.109427] [<ffffff80084a2d1c>] bus_probe_device+0x2c/0x8c
[    1.109924] [<ffffff80084a3170>] deferred_probe_work_func+0x74/0xa0
[    1.110486] [<ffffff80080b2e34>] process_one_work+0x218/0x3e0
[    1.111001] [<ffffff80080b3530>] worker_thread+0x24c/0x374
[    1.111490] [<ffffff80080b7dbc>] kthread+0xe8/0xf0
[    1.111922] [<ffffff8008082690>] ret_from_fork+0x10/0x40

Change-Id: I11f667830d913430d9e0b4da2b391815d335ecb8
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
14 files changed:
arch/arm/mach-rockchip/ddr_freq.c
arch/arm/mach-rockchip/dvfs.c
arch/arm/mach-rockchip/rk3288.c
drivers/hid/hid-rkvr.c
drivers/input/sensors/hall/mh248.c
drivers/input/touchscreen/rockchip_gslX680_rk3128.c
drivers/input/touchscreen/zet62xx/zet62xx.c
drivers/power/rk818_battery.c
drivers/video/rockchip/dp/rockchip_dp.c
drivers/video/rockchip/hdmi/rockchip-hdmiv1/rockchip_hdmiv1.c
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2.c
drivers/video/rockchip/tve/gm7122/gm7122_tve.c
drivers/video/rockchip/tve/rk1000/rk1000_tve.c
drivers/video/rockchip/tve/rk3036/rk3036_tve.c

index 470587b22efda502e63c9e0172d9f3197277401f..ea229d7aeafd55e210d36ca81b7dece9871d1e5c 100644 (file)
@@ -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;
index f189f87cab1a008f85cf692ed888de25870f7ba2..18d98e4dfcccbd4d689cde058673ec697e0d2b40 100644 (file)
@@ -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) {
index 0a768a98ba06a68388b119a3236dedaff66d87ec..ca1ccbc407289f73b5bd5806d67ba40b0670e417 100755 (executable)
@@ -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"));
index 0bdafb380a5fdd82b8f91c24bfef204dafce4ca8..eada6a54c520b54a582abfbd7753b8cf752399ac 100644 (file)
@@ -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)
index 23a02924497b98b978a238879d4cf89c960a3479..0fa8a89aee61792a05aaa20334b039c3bb32cbbf 100644 (file)
@@ -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;
index a29ba0af10a9dbf0e3e0a1da69c54056c816fb44..691ae7c97ffcc70c064a7e703d1ae0f6c0fe31d4 100755 (executable)
@@ -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;
index 90e77ad4138d0f418bd84201b67b3f4275f4bc43..bee69d6f08452c0b9be3758ba1b066db51c302ba 100755 (executable)
@@ -4446,11 +4446,9 @@ static int zet622x_ts_fb_event_notify(struct notifier_block *self,
                                      unsigned long action, void *data)\r
 {\r
        struct fb_event *event = data;\r
-       int blank_mode = *((int *)event->data);\r
-       \r
 \r
        if (action == FB_EARLY_EVENT_BLANK) {\r
-               switch (blank_mode) {\r
+               switch (*((int *)event->data)) {
                case FB_BLANK_UNBLANK:\r
                        break;\r
                default:\r
@@ -4458,7 +4456,7 @@ static int zet622x_ts_fb_event_notify(struct notifier_block *self,
                        break;\r
                }\r
        } else if (action == FB_EVENT_BLANK) {\r
-               switch (blank_mode) {\r
+               switch (*((int *)event->data)) {
                case FB_BLANK_UNBLANK:\r
                        zet622x_ts_late_resume();\r
                        break;\r
index f9e6d8f7c4bdfb9d8564b9d753eb602556c970cf..7933fcd979e156ea0cddc4334d3ca1bcd5f610d0 100644 (file)
@@ -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;
 
index d46f5eda4cab12112e1fb523a657eba81f336e65..9a9a6f31972f3650ff2a2fdc6f08fc59ec43dbad 100644 (file)
@@ -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;
index 88610b8352d49378faddb85bf7cd02b169e36516..b11380fd25f26b887324c333c5e43dbff694a20a 100644 (file)
@@ -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();
index 6e607a27d993c222e524ddd19b746826546ff385..4f7ee815035e5879e1bd3385256b388c574bb3bd 100644 (file)
@@ -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) {
index 47642c762d94eef92a178f4ce5f81fae2f9c4e33..4e8d92f27eceb6e97e862d565dd9574971d3838d 100755 (executable)
@@ -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) {
index a21c08851795c0fdd19c967f662676a68a082496..9bd6c0fe3f3836921a284cfafafccab52c5e5339 100755 (executable)
@@ -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;
index b8415412dd1b5c1e2b0213634ba2edf21531bc36..337fa346edd635f00e2f9efaeb9c25c88e39b038 100755 (executable)
@@ -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);