From d7eae61ec4c7cee29ad2c0117d0f53617df2069b Mon Sep 17 00:00:00 2001 From: Shivakumar Malke Date: Tue, 21 Feb 2023 12:12:37 +0530 Subject: [PATCH 1/3] msm: camera: smmu: Use get_file to increase ref count Due to race condition, fd pointing to a particular dma buf is released by userspace before incrementing ref count and hence freed that dma buf. When the call returns it still uses the freed dma buf causing use-after-free. This fix includes get_file API to increment ref count before dma_buf_fd. CRs-Fixed: 3341070 Change-Id: I8ebc37b4ceb5f8691bbbb3d26b8b64878d832fbe Signed-off-by: Shivakumar Malke --- drivers/cam_req_mgr/cam_mem_mgr.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/cam_req_mgr/cam_mem_mgr.c b/drivers/cam_req_mgr/cam_mem_mgr.c index 369f6639638f..2cf85ed77136 100644 --- a/drivers/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/cam_req_mgr/cam_mem_mgr.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -438,7 +438,6 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, struct dma_buf **buf, int *fd) { - struct dma_buf *dmabuf = NULL; int rc = 0; struct timespec64 ts1, ts2; long microsec = 0; @@ -457,6 +456,12 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, *buf = ion_alloc(len, heap_id_mask, flags); if (IS_ERR_OR_NULL(*buf)) return -ENOMEM; + /* + * increment the ref count so that ref count becomes 2 here + * when we close fd, refcount becomes 1 and when we do + * dmap_put_buf, ref count becomes 0 and memory will be freed. + */ + get_dma_buf(*buf); *fd = dma_buf_fd(*buf, O_CLOEXEC); if (*fd < 0) { @@ -465,17 +470,6 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, goto get_fd_fail; } - /* - * increment the ref count so that ref count becomes 2 here - * when we close fd, refcount becomes 1 and when we do - * dmap_put_buf, ref count becomes 0 and memory will be freed. - */ - dmabuf = dma_buf_get(*fd); - if (IS_ERR_OR_NULL(dmabuf)) { - CAM_ERR(CAM_MEM, "dma_buf_get failed, *fd=%d", *fd); - rc = -EINVAL; - } - if (tbl.alloc_profile_enable) { CAM_GET_TIMESTAMP(ts2); CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts1, ts2, microsec); From 53152ba8cdb3313c3387a72c09af1d9aabd8964c Mon Sep 17 00:00:00 2001 From: Shivakumar Malke Date: Wed, 22 Feb 2023 17:30:09 +0530 Subject: [PATCH 2/3] msm: camera: ope: Avoid deadlock in OPE PF handling In OPE fault handler, while dumping pf info ctx_mutex is acquired and corresponding page fault ops is called. In pagefault ops same mutex is getting acquired again causing a dead lock. This commit avoids locking the same mutex again. CRs-Fixed: 3419490 Change-Id: I2e37f725865d091f2cb682fc62f5d21278b93959 Signed-off-by: Shivakumar Malke --- drivers/cam_ope/cam_ope_context.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cam_ope/cam_ope_context.c b/drivers/cam_ope/cam_ope_context.c index c8be0da353d4..de93c02a0eab 100644 --- a/drivers/cam_ope/cam_ope_context.c +++ b/drivers/cam_ope/cam_ope_context.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -39,7 +40,6 @@ static int cam_ope_context_dump_active_request(void *data, return -EINVAL; } - mutex_lock(&ctx->ctx_mutex); if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { CAM_ERR(CAM_OPE, "Invalid state ope ctx %d state %d", ctx->ctx_id, ctx->state); @@ -65,7 +65,6 @@ static int cam_ope_context_dump_active_request(void *data, } end: - mutex_unlock(&ctx->ctx_mutex); return rc; } From 9b3f91ecabd6a069bfe6026cecbdadc6795fd8d6 Mon Sep 17 00:00:00 2001 From: Yash Upadhyay Date: Tue, 14 Mar 2023 21:38:14 +0530 Subject: [PATCH 3/3] msm: camera: cdm: check irq status on hang detection Problem: Check IRQ status on hang detection if the inline IRQ is set then the cdm has triggered IRQ but there is a workqueue scheduling delay which is causing the cdm's config timeout. Solution: To prevent the timeout due to scheduling delay check the work record and irq status and return true if its delay. CRs-Fixed: 3433175 Change-Id: Iaa34f8ff9b57e7da9f80677a7da9b4f9a53dad14 Signed-off-by: Yash Upadhyay --- drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c | 40 ++++++++++----------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c index e5342bd95163..6f25c913b352 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c @@ -2648,6 +2648,7 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, struct cam_tfe_hw_mgr_ctx *ctx; struct cam_isp_prepare_hw_update_data *hw_update_data; bool cdm_hang_detect = false; + unsigned long rem_jiffies = 0; if (!hw_mgr_priv || !config_hw_args) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -2814,12 +2815,13 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, goto end; for (i = 0; i < CAM_TFE_HW_CONFIG_WAIT_MAX_TRY; i++) { - rc = wait_for_completion_timeout( + rem_jiffies = wait_for_completion_timeout( &ctx->config_done_complete, msecs_to_jiffies( CAM_TFE_HW_CONFIG_TIMEOUT)); - if (rc <= 0) { - if (!cam_cdm_detect_hang_error(ctx->cdm_handle)) { + if (rem_jiffies <= 0) { + rc = cam_cdm_detect_hang_error(ctx->cdm_handle); + if (rc == 0) { CAM_ERR(CAM_ISP, "CDM workqueue delay detected, wait for some more time req_id=%llu rc=%d ctx_index %d", cfg->request_id, rc, @@ -2831,24 +2833,19 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, CAM_DEFAULT_VALUE, CAM_DEFAULT_VALUE, rc); continue; - } - - CAM_ERR(CAM_ISP, - "config done completion timeout for req_id=%llu rc=%d ctx_index %d", - cfg->request_id, rc, - ctx->ctx_index); - - cam_req_mgr_debug_delay_detect(); - trace_cam_delay_detect("ISP", - "config done completion timeout", - cfg->request_id, ctx->ctx_index, - CAM_DEFAULT_VALUE, CAM_DEFAULT_VALUE, - rc); - - if (rc == 0) + } else { + CAM_ERR(CAM_ISP, + "config done completion timeout, cdm_hang=%d on req_id=%llu ctx_index %d", + true, cfg->request_id, ctx->ctx_index); + cam_req_mgr_debug_delay_detect(); + trace_cam_delay_detect("ISP", + "config done completion timeout", + cfg->request_id, ctx->ctx_index, + CAM_DEFAULT_VALUE, CAM_DEFAULT_VALUE, + rc); rc = -ETIMEDOUT; - - goto end; + break; + } } else { rc = 0; CAM_DBG(CAM_ISP, @@ -2859,7 +2856,8 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv, } if ((i == CAM_TFE_HW_CONFIG_WAIT_MAX_TRY) && (rc == 0)) - rc = -ETIMEDOUT; + CAM_DBG(CAM_ISP, + "Wq delayed but IRQ CDM done"); end: CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id);