| From b17c1bba9cec1727451b906d9a0c209774624873 Mon Sep 17 00:00:00 2001 |
| From: Rui Miguel Silva <rmfrfs@gmail.com> |
| Date: Mon, 23 Jan 2017 16:32:57 +0000 |
| Subject: staging: greybus: timesync: validate platform state callback |
| |
| From: Rui Miguel Silva <rmfrfs@gmail.com> |
| |
| commit b17c1bba9cec1727451b906d9a0c209774624873 upstream. |
| |
| When tearingdown timesync, and not in arche platform, the state platform |
| callback is not initialized. That will trigger the following NULL |
| dereferencing. |
| CallTrace: |
| |
| ? gb_timesync_platform_unlock_bus+0x11/0x20 [greybus] |
| gb_timesync_teardown+0x85/0xc0 [greybus] |
| gb_timesync_svc_remove+0xab/0x190 [greybus] |
| gb_svc_del+0x29/0x110 [greybus] |
| gb_hd_del+0x14/0x20 [greybus] |
| ap_disconnect+0x24/0x60 [gb_es2] |
| usb_unbind_interface+0x7a/0x2c0 |
| __device_release_driver+0x96/0x150 |
| device_release_driver+0x1e/0x30 |
| bus_remove_device+0xe7/0x130 |
| device_del+0x116/0x230 |
| usb_disable_device+0x97/0x1f0 |
| usb_disconnect+0x80/0x260 |
| hub_event+0x5ca/0x10e0 |
| process_one_work+0x126/0x3b0 |
| worker_thread+0x55/0x4c0 |
| ? process_one_work+0x3b0/0x3b0 |
| kthread+0xc4/0xe0 |
| ? kthread_park+0xb0/0xb0 |
| ret_from_fork+0x22/0x30 |
| |
| So, fix that by adding checks before use the callback. |
| |
| Fixes: 970dc85bd95d ("greybus: timesync: Add timesync core driver") |
| Signed-off-by: Rui Miguel Silva <rmfrfs@gmail.com> |
| Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org> |
| Reviewed-by: Johan Hovold <johan@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/staging/greybus/timesync_platform.c | 6 ++++++ |
| 1 file changed, 6 insertions(+) |
| |
| --- a/drivers/staging/greybus/timesync_platform.c |
| +++ b/drivers/staging/greybus/timesync_platform.c |
| @@ -45,12 +45,18 @@ u32 gb_timesync_platform_get_clock_rate( |
| |
| int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata) |
| { |
| + if (!arche_platform_change_state_cb) |
| + return 0; |
| + |
| return arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_TIME_SYNC, |
| pdata); |
| } |
| |
| void gb_timesync_platform_unlock_bus(void) |
| { |
| + if (!arche_platform_change_state_cb) |
| + return; |
| + |
| arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_ACTIVE, NULL); |
| } |
| |