Przeglądaj źródła

video: driver: fix use-after-free issues with __read_queue() api

Incase of synchronous cmd(HFI_CMD_INIT, HFI_CMD_STOP, HFI_CMD_CLOSE)
timeout cases, video driver will attempt to do core_deinit sequence
and will free all interface queues mappings as part of core_deinit.

If at same time ISR handler is fired then reverse thread will attempt
to dequeue packets from message and debug queue. Reverse thread will
not acquire core->lock for performance reasone. Dequeueing packets
without acquiring core->lock might lead to use-after-free issues.

Uploaded change to address above mentioned issue.

Change-Id: I2047b28d69611129c4fdefcfb8a843c895e11dbb
Signed-off-by: Govindaraj Rajagopal <[email protected]>
Govindaraj Rajagopal 3 lat temu
rodzic
commit
06643c1de9

+ 2 - 0
driver/vidc/inc/venus_hfi.h

@@ -68,6 +68,8 @@ int venus_hfi_set_ir_period(struct msm_vidc_inst *inst, u32 ir_type,
 void venus_hfi_pm_work_handler(struct work_struct *work);
 irqreturn_t venus_hfi_isr(int irq, void *data);
 irqreturn_t venus_hfi_isr_handler(int irq, void *data);
+int venus_hfi_interface_queues_init(struct msm_vidc_core *core);
+void venus_hfi_interface_queues_deinit(struct msm_vidc_core *core);
 
 int __write_register_masked(struct msm_vidc_core *core,
 		u32 reg, u32 value, u32 mask);

+ 10 - 0
driver/vidc/src/msm_vidc_probe.c

@@ -359,6 +359,8 @@ static int msm_vidc_remove_video_device(struct platform_device *pdev)
 
 	msm_vidc_core_deinit(core, true);
 
+	venus_hfi_interface_queues_deinit(core);
+
 	d_vpr_h("depopulating sub devices\n");
 	/*
 	 * Trigger remove for each sub-device i.e. qcom,msm-vidc,context-bank.
@@ -547,6 +549,12 @@ static int msm_vidc_probe_video_device(struct platform_device *pdev)
 		goto sub_dev_failed;
 	}
 
+	rc = venus_hfi_interface_queues_init(core);
+	if (rc) {
+		d_vpr_e("%s: interface queues init failed\n", __func__);
+		goto queues_init_failed;
+	}
+
 	rc = msm_vidc_core_init(core);
 	if (rc) {
 		d_vpr_e("%s: sys init failed\n", __func__);
@@ -557,6 +565,8 @@ static int msm_vidc_probe_video_device(struct platform_device *pdev)
 	return rc;
 
 core_init_failed:
+	venus_hfi_interface_queues_deinit(core);
+queues_init_failed:
 	of_platform_depopulate(&pdev->dev);
 sub_dev_failed:
 #ifdef CONFIG_MEDIA_CONTROLLER

+ 7 - 11
driver/vidc/src/venus_hfi.c

@@ -2203,7 +2203,7 @@ static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
 	q_hdr->qhdr_write_idx = 0x0;
 }
 
-static void __interface_queues_deinit(struct msm_vidc_core *core)
+void venus_hfi_interface_queues_deinit(struct msm_vidc_core *core)
 {
 	int i;
 
@@ -2227,7 +2227,7 @@ static void __interface_queues_deinit(struct msm_vidc_core *core)
 	core->sfr.align_device_addr = 0;
 }
 
-static int __interface_queues_init(struct msm_vidc_core *core)
+int venus_hfi_interface_queues_init(struct msm_vidc_core *core)
 {
 	int rc = 0;
 	struct hfi_queue_table_header *q_tbl_hdr;
@@ -2342,10 +2342,6 @@ static int __interface_queues_init(struct msm_vidc_core *core)
 	/* write sfr buffer size in first word */
 	*((u32 *)core->sfr.align_virtual_addr) = core->sfr.mem_size;
 
-	rc = call_venus_op(core, setup_ucregion_memmap, core);
-	if (rc)
-		return rc;
-
 	return 0;
 fail_alloc_queue:
 	return -ENOMEM;
@@ -2501,6 +2497,11 @@ int __load_fw(struct msm_vidc_core *core)
 	__hand_off_regulators(core);
 	trace_msm_v4l2_vidc_fw_load("END");
 
+	/* configure interface_queues memory to firmware */
+	rc = call_venus_op(core, setup_ucregion_memmap, core);
+	if (rc)
+		return rc;
+
 	return rc;
 fail_protect_mem:
 	if (core->dt->fw_cookie)
@@ -2704,10 +2705,6 @@ int venus_hfi_core_init(struct msm_vidc_core *core)
 	if (rc)
 		goto error;
 
-	rc = __interface_queues_init(core);
-	if (rc)
-		goto error;
-
 	rc = call_venus_op(core, boot_firmware, core);
 	if (rc)
 		goto error;
@@ -2772,7 +2769,6 @@ int venus_hfi_core_deinit(struct msm_vidc_core *core, bool force)
 	 */
 	if (msm_vidc_fw_dump)
 		fw_coredump(core);
-	__interface_queues_deinit(core);
 
 	return 0;
 }

+ 1 - 1
driver/vidc/src/venus_hfi_response.c

@@ -1945,7 +1945,7 @@ static int handle_session_response(struct msm_vidc_core *core,
 
 	inst = get_inst(core, hdr->session_id);
 	if (!inst) {
-		d_vpr_e("%s: Invalid params\n", __func__);
+		d_vpr_e("%s: Invalid inst\n", __func__);
 		return -EINVAL;
 	}