From e9278651e01f93c76fa8b93ff27c460d283cd0b2 Mon Sep 17 00:00:00 2001 From: Praveen Chavan <pchavan@codeaurora.org> Date: Wed, 20 Jan 2016 17:45:14 -0800 Subject: [PATCH] msm: vidc: Validate session_id in video hardware response Validate session_id present in video hardware response packet before processing it. This will avoid system reset resulting from invalid session_id returned from video hardware. Author: Maheshwar Ajja <majja@codeaurora.org> Change-Id: I37525a3d10b5efe00734c5533931e2700f3c7513 Signed-off-by: Maheshwar Ajja <majja@codeaurora.org> Signed-off-by: Praveen Chavan <pchavan@codeaurora.org> --- .../platform/msm/vidc/hfi_response_handler.c | 47 ++++++++++++++++++- drivers/media/platform/msm/vidc/q6_hfi.c | 10 +++- drivers/media/platform/msm/vidc/q6_hfi.h | 1 + drivers/media/platform/msm/vidc/venus_hfi.c | 11 ++++- drivers/media/platform/msm/vidc/venus_hfi.h | 1 + drivers/media/platform/msm/vidc/vidc_hfi.h | 3 +- 6 files changed, 69 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index f41e68efeef2..b044e685f276 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -78,6 +78,26 @@ static enum vidc_status hfi_map_err_status(int hfi_err) return vidc_err; } +static int sanitize_session_pkt(struct list_head *sessions, + struct hal_session *sess, struct mutex *session_lock) +{ + struct hal_session *session; + int invalid = 1; + if (session_lock) { + mutex_lock(session_lock); + list_for_each_entry(session, sessions, list) { + if (session == sess) { + invalid = 0; + break; + } + } + mutex_unlock(session_lock); + } + if (invalid) + dprintk(VIDC_WARN, "Invalid session from FW: %p\n", sess); + return invalid; +} + static void hfi_process_sess_evt_seq_changed( msm_vidc_callback callback, u32 device_id, struct hfi_msg_event_notify_packet *pkt) @@ -1183,9 +1203,11 @@ void hfi_process_sys_property_info( u32 hfi_process_msg_packet( msm_vidc_callback callback, u32 device_id, - struct vidc_hal_msg_pkt_hdr *msg_hdr) + struct vidc_hal_msg_pkt_hdr *msg_hdr, + struct list_head *sessions, struct mutex *session_lock) { u32 rc = 0; + struct hal_session *sess; if (!callback || !msg_hdr || msg_hdr->size < VIDC_IFACEQ_MIN_PKT_SIZE) { dprintk(VIDC_ERR, "hal_process_msg_packet:bad" @@ -1194,10 +1216,19 @@ u32 hfi_process_msg_packet( return rc; } +#define SANITIZE_SESSION_PKT(msg_pkt) ({ \ + sess = (struct hal_session *) \ + (((struct vidc_hal_session_cmd_pkt *) \ + msg_pkt)->session_id); \ + if (sanitize_session_pkt(sessions, sess, session_lock)) \ + break; \ + }) + dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet); rc = (u32) msg_hdr->packet; switch (msg_hdr->packet) { case HFI_MSG_EVENT_NOTIFY: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_event_notify(callback, device_id, (struct hfi_msg_event_notify_packet *) msg_hdr); break; @@ -1209,6 +1240,7 @@ u32 hfi_process_msg_packet( case HFI_MSG_SYS_IDLE: break; case HFI_MSG_SYS_SESSION_INIT_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_init_done(callback, device_id, (struct hfi_msg_sys_session_init_done_packet *) msg_hdr); @@ -1219,44 +1251,53 @@ u32 hfi_process_msg_packet( msg_hdr); break; case HFI_MSG_SYS_SESSION_END_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_end_done(callback, device_id, (struct hfi_msg_sys_session_end_done_packet *) msg_hdr); break; case HFI_MSG_SESSION_LOAD_RESOURCES_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_load_res_done(callback, device_id, (struct hfi_msg_session_load_resources_done_packet *) msg_hdr); break; case HFI_MSG_SESSION_START_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_start_done(callback, device_id, (struct hfi_msg_session_start_done_packet *) msg_hdr); break; case HFI_MSG_SESSION_STOP_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_stop_done(callback, device_id, (struct hfi_msg_session_stop_done_packet *) msg_hdr); break; case HFI_MSG_SESSION_EMPTY_BUFFER_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_etb_done(callback, device_id, (struct hfi_msg_session_empty_buffer_done_packet *) msg_hdr); break; case HFI_MSG_SESSION_FILL_BUFFER_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_ftb_done(callback, device_id, msg_hdr); break; case HFI_MSG_SESSION_FLUSH_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_flush_done(callback, device_id, (struct hfi_msg_session_flush_done_packet *) msg_hdr); break; case HFI_MSG_SESSION_PROPERTY_INFO: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_prop_info(callback, device_id, (struct hfi_msg_session_property_info_packet *) msg_hdr); break; case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_rel_res_done(callback, device_id, (struct hfi_msg_session_release_resources_done_packet *) msg_hdr); @@ -1267,18 +1308,21 @@ u32 hfi_process_msg_packet( msg_hdr); break; case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_get_seq_hdr_done( callback, device_id, (struct hfi_msg_session_get_sequence_header_done_packet*) msg_hdr); break; case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_rel_buf_done( callback, device_id, (struct hfi_msg_session_release_buffers_done_packet*) msg_hdr); break; case HFI_MSG_SYS_SESSION_ABORT_DONE: + SANITIZE_SESSION_PKT(msg_hdr); hfi_process_session_abort_done(callback, device_id, (struct hfi_msg_sys_session_abort_done_packet*) msg_hdr); break; @@ -1286,5 +1330,6 @@ u32 hfi_process_msg_packet( dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet); break; } +#undef SANITIZE_SESSION_PKT return rc; } diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c index bc3b93d2448e..9148846f5af0 100644 --- a/drivers/media/platform/msm/vidc/q6_hfi.c +++ b/drivers/media/platform/msm/vidc/q6_hfi.c @@ -184,7 +184,8 @@ static void q6_hfi_core_work_handler(struct work_struct *work) if (!rc) hfi_process_msg_packet(device->callback, device->device_id, - (struct vidc_hal_msg_pkt_hdr *) packet); + (struct vidc_hal_msg_pkt_hdr *) packet, + &device->sess_head, &device->session_lock); } while (!rc); if (rc != -ENODATA) @@ -483,6 +484,7 @@ static int q6_hfi_core_init(void *device) } INIT_LIST_HEAD(&dev->sess_head); + mutex_init(&dev->session_lock); if (!dev->event_queue.buffer) { rc = q6_init_event_queue(dev); @@ -583,7 +585,9 @@ static void *q6_hfi_session_init(void *device, u32 session_id, rc = -EBADE; goto err_session_init; } + mutex_lock(&dev->session_lock); list_add_tail(&new_session->list, &dev->sess_head); + mutex_unlock(&dev->session_lock); return new_session; err_session_init: @@ -646,7 +650,11 @@ static int q6_hfi_session_clean(void *session) sess_close = session; dprintk(VIDC_DBG, "deleted the session: 0x%x", sess_close->session_id); + mutex_lock(&((struct q6_hfi_device *) + sess_close->device)->session_lock); list_del(&sess_close->list); + mutex_unlock(&((struct q6_hfi_device *) + sess_close->device)->session_lock); kfree(sess_close); return 0; } diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h index 3dc4607130a4..c2ed9183df9a 100644 --- a/drivers/media/platform/msm/vidc/q6_hfi.h +++ b/drivers/media/platform/msm/vidc/q6_hfi.h @@ -43,6 +43,7 @@ struct q6_hfi_device { struct q6_resources resources; struct msm_vidc_platform_resources *res; void *apr; + struct mutex session_lock; }; struct q6_apr_cmd_sys_init_packet { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index ea2d6df861a6..c33bfa07689d 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1045,6 +1045,7 @@ static int venus_hfi_core_init(void *device) INIT_LIST_HEAD(&dev->sess_head); mutex_init(&dev->read_lock); mutex_init(&dev->write_lock); + mutex_init(&dev->session_lock); venus_hfi_set_registers(dev); if (!dev->hal_client) { @@ -1484,7 +1485,10 @@ static void *venus_hfi_session_init(void *device, u32 session_id, else if (session_type == 2) new_session->is_decoder = 1; new_session->device = dev; + + mutex_lock(&dev->session_lock); list_add_tail(&new_session->list, &dev->sess_head); + mutex_unlock(&dev->session_lock); if (create_pkt_cmd_sys_session_init(&pkt, (u32)new_session, session_type, codec_type)) { @@ -1554,7 +1558,11 @@ static int venus_hfi_session_clean(void *session) sess_close = session; dprintk(VIDC_DBG, "deleted the session: 0x%p", sess_close); + mutex_lock(&((struct venus_hfi_device *) + sess_close->device)->session_lock); list_del(&sess_close->list); + mutex_unlock(&((struct venus_hfi_device *) + sess_close->device)->session_lock); kfree(sess_close); return 0; } @@ -1985,7 +1993,8 @@ static void venus_hfi_response_handler(struct venus_hfi_device *device) while (!venus_hfi_iface_msgq_read(device, packet)) { rc = hfi_process_msg_packet(device->callback, device->device_id, - (struct vidc_hal_msg_pkt_hdr *) packet); + (struct vidc_hal_msg_pkt_hdr *) packet, + &device->sess_head, &device->session_lock); if (rc == HFI_MSG_EVENT_NOTIFY) venus_hfi_process_msg_event_notify( device, (void *)packet); diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h index a59a053f94c8..44cdf313a14a 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.h +++ b/drivers/media/platform/msm/vidc/venus_hfi.h @@ -188,6 +188,7 @@ struct venus_hfi_device { struct mutex read_lock; struct mutex write_lock; struct mutex clock_lock; + struct mutex session_lock; msm_vidc_callback callback; struct vidc_mem_addr iface_q_table; struct vidc_mem_addr qdss; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index 8a03751d3b27..a6646220de49 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -848,6 +848,7 @@ struct msm_vidc_fw { }; u32 hfi_process_msg_packet(msm_vidc_callback callback, - u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr); + u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + struct list_head *sessions, struct mutex *session_lock); #endif -- GitLab