From a46d30bf9245fddf027eabe86fec9367683dfad4 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Wed, 26 Jun 2024 18:08:57 +0530 Subject: [PATCH 1/4] msm: camera: common: Add missing put_cpu_buf calls Add cam_mem_put_cpu_buf calls in error scenarios to avoid memory leak. CRs-Fixed: 3866880 Change-Id: I26ee4c58ab88458d109b13a04cfcaea3502b31a3 Signed-off-by: Nirmal Abraham --- drivers/cam_isp/cam_isp_context.c | 6 ++++-- .../cam_sensor_module/cam_flash/cam_flash_core.c | 16 ++++++++++++---- drivers/cam_sensor_module/cam_ois/cam_ois_core.c | 5 +++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index da0a59be2353..b324b25e1a05 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -4791,8 +4791,10 @@ static int __cam_isp_ctx_config_dev_in_top_state( if ((len < sizeof(struct cam_packet)) || ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { CAM_ERR(CAM_ISP, "invalid buff length: %zu or offset", len); - rc = -EINVAL; - goto free_req; + spin_lock_bh(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + return -EINVAL; } remain_len -= (size_t)cmd->offset; diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index 029ec542d491..cbe33b043a51 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -1065,9 +1065,10 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) /* Loop through multiple command buffers */ for (i = 1; i < csl_packet->num_cmd_buf; i++) { rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); - if (rc) + if (rc) { + cam_mem_put_cpu_buf(config.packet_handle); return rc; - + } total_cmd_buf_in_bytes = cmd_desc[i].length; processed_cmd_buf_in_bytes = 0; if (!total_cmd_buf_in_bytes) @@ -1278,8 +1279,8 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = fctrl->func_tbl.apply_setting(fctrl, 1); if (rc) { CAM_ERR(CAM_FLASH, "cannot apply fire settings rc = %d", rc); - return rc; } + cam_mem_put_cpu_buf(config.packet_handle); return rc; } break; @@ -1344,8 +1345,10 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) goto update_req_mgr; } case CAM_FLASH_PACKET_OPCODE_STREAM_OFF: { - if (fctrl->streamoff_count > 0) + if (fctrl->streamoff_count > 0) { + cam_mem_put_cpu_buf(config.packet_handle); return rc; + } CAM_DBG(CAM_FLASH, "Received Stream off Settings"); i2c_data = &(fctrl->i2c_data); @@ -1362,6 +1365,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) if (rc) { CAM_ERR(CAM_FLASH, "Failed in parsing i2c Stream off packets"); + cam_mem_put_cpu_buf(config.packet_handle); return rc; } break; @@ -1638,6 +1642,8 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + cmd_desc->offset); if (!cmd_buf) { + cam_mem_put_cpu_buf(cmd_desc->mem_handle); + cam_mem_put_cpu_buf(config.packet_handle); rc = -EINVAL; return rc; } @@ -1654,6 +1660,8 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) CAM_WARN(CAM_FLASH, "Rxed Flash fire ops without linking"); flash_data->cmn_attr.is_settings_valid = false; + cam_mem_put_cpu_buf(cmd_desc->mem_handle); + cam_mem_put_cpu_buf(config.packet_handle); return -EINVAL; } if (remain_len < sizeof(struct cam_flash_set_on_off)) { diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index e62e00d88d27..45a63a9eb9cb 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -544,9 +544,10 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) /* Loop through multiple command buffers */ for (i = 0; i < csl_packet->num_cmd_buf; i++) { rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); - if (rc) + if (rc) { + cam_mem_put_cpu_buf(dev_config.packet_handle); return rc; - + } total_cmd_buf_in_bytes = cmd_desc[i].length; if (!total_cmd_buf_in_bytes) continue; From 305a2c3187ed22d67a53579eea6dc78e762dda15 Mon Sep 17 00:00:00 2001 From: Swami Reddy Reddy Date: Wed, 24 Jul 2024 18:53:36 +0530 Subject: [PATCH 2/4] msm: camera: sensor: TOCTOU error handling - Proper Handling in case of invalid pinctrl index - Removing dead code and unused variables - Change to dereference s_ctrl only after proper NULL Dereference Check. CRs-Fixed: 3875406 Change-Id: I8e2c717b22efff2a7d6503d38c048e30eff230da Signed-off-by: Swami Reddy Reddy --- drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c | 13 ++++++++----- .../cam_sensor_module/cam_sensor/cam_sensor_core.c | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index 5165f6b2d1c9..146967f076a9 100644 --- a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -379,7 +380,7 @@ static int cam_res_mgr_shared_pinctrl_select_state( cam_res->pctrl_res[idx].pstatus = PINCTRL_STATUS_SUSPEND; } - return 0; + return rc; } static int cam_res_mgr_add_device(struct device *dev, @@ -577,11 +578,9 @@ static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) bool need_free = true; int dev_num = 0; struct cam_gpio_res *gpio_res = NULL; - bool is_shared_gpio = false; bool is_shared_pctrl_gpio = false; int pctrl_idx = -1; - is_shared_gpio = cam_res_mgr_gpio_is_in_shared_gpio(gpio); is_shared_pctrl_gpio = cam_res_mgr_gpio_is_in_shared_pctrl_gpio(gpio); @@ -634,8 +633,12 @@ static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) pctrl_idx = cam_res_mgr_util_get_idx_from_shared_pctrl_gpio( gpio); - cam_res_mgr_shared_pinctrl_select_state( - pctrl_idx, false); + if (pctrl_idx >= 0) { + cam_res_mgr_shared_pinctrl_select_state( + pctrl_idx, false); + } else { + CAM_ERR(CAM_RES, "invalid pinctrl idx: %d", pctrl_idx); + } } CAM_DBG(CAM_RES, "freeing gpio: %u", gpio); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 999fec038324..a31023e4101c 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -719,13 +719,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, { int rc = 0, pkt_opcode = 0; struct cam_control *cmd = (struct cam_control *)arg; - struct cam_sensor_power_ctrl_t *power_info = - &s_ctrl->sensordata->power_info; + struct cam_sensor_power_ctrl_t *power_info = NULL; if (!s_ctrl || !arg) { CAM_ERR(CAM_SENSOR, "s_ctrl is NULL"); return -EINVAL; } + power_info = &s_ctrl->sensordata->power_info; + if (cmd->op_code != CAM_SENSOR_PROBE_CMD) { if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { CAM_ERR(CAM_SENSOR, "Invalid handle type: %d", From 343ba19fd7d679ec3408ac3a8939aa51c92b6b79 Mon Sep 17 00:00:00 2001 From: chengxue Date: Tue, 8 Oct 2024 15:38:01 +0800 Subject: [PATCH 3/4] msm: camera: ois: Copy packet header in kernel After getting the mapped buffer through cam_mem_get_cpu_buf() in kernel, userspace is still able to access those buffers. This change copy ois packet header in kernel to avoid TOCTOU issue. CRs-Fixed: 3885381 Change-Id: I185381f81a6a736a029b516dc7f99cce1cac7129 Signed-off-by: chengxue --- .../cam_sensor_module/cam_ois/cam_ois_core.c | 130 +++++++++--------- drivers/cam_utils/cam_common_util.c | 34 +++++ drivers/cam_utils/cam_common_util.h | 18 +++ 3 files changed, 115 insertions(+), 67 deletions(-) diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 45a63a9eb9cb..d8766a225046 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -493,11 +493,13 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) size_t pkt_len; size_t remain_len = 0; struct cam_packet *csl_packet = NULL; + struct cam_packet *csl_packet_u = NULL; size_t len_of_buff = 0; uint32_t *offset = NULL, *cmd_buf; struct cam_ois_soc_private *soc_private = (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + size_t packet_size = 0; ioctl_ctrl = (struct cam_control *)arg; if (copy_from_user(&dev_config, @@ -519,22 +521,36 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_ERR(CAM_OIS, "Inval cam_packet strut size: %zu, len_of_buff: %zu", sizeof(struct cam_packet), pkt_len); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return -EINVAL; + rc = -EINVAL; + goto put_ref; } remain_len -= (size_t)dev_config.offset; - csl_packet = (struct cam_packet *) + csl_packet_u = (struct cam_packet *) (generic_pkt_addr + (uint32_t)dev_config.offset); + packet_size = csl_packet_u->header.size; + if (packet_size <= remain_len) { + rc = cam_common_mem_kdup((void **)&csl_packet, + csl_packet_u, packet_size); + if (rc) { + CAM_ERR(CAM_OIS, "Alloc and copy request %lld packet fail", + csl_packet_u->header.request_id); + goto put_ref; + } + } else { + CAM_ERR(CAM_OIS, "Invalid packet header size %u", + packet_size); + rc = -EINVAL; + goto put_ref; + } if (cam_packet_util_validate_packet(csl_packet, remain_len)) { CAM_ERR(CAM_OIS, "Invalid packet params"); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return -EINVAL; + rc = -EINVAL; + goto end; } - switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_OIS_PACKET_OPCODE_INIT: offset = (uint32_t *)&csl_packet->payload; @@ -545,9 +561,10 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) for (i = 0; i < csl_packet->num_cmd_buf; i++) { rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); if (rc) { - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + CAM_ERR(CAM_OIS, "Invalid cmd desc"); + goto end; } + total_cmd_buf_in_bytes = cmd_desc[i].length; if (!total_cmd_buf_in_bytes) continue; @@ -557,15 +574,14 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "Failed to get cpu buf : 0x%x", cmd_desc[i].mem_handle); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } cmd_buf = (uint32_t *)generic_ptr; if (!cmd_buf) { CAM_ERR(CAM_OIS, "invalid cmd buf"); + rc = -EINVAL; cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return -EINVAL; + goto end; } if ((len_of_buff < sizeof(struct common_header)) || @@ -573,9 +589,9 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) sizeof(struct common_header)))) { CAM_ERR(CAM_OIS, "Invalid length for sensor cmd"); + rc = -EINVAL; cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return -EINVAL; + goto end; } remain_len = len_of_buff - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); @@ -588,9 +604,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "Failed in parsing slave info"); - cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + break; } break; case CAMERA_SENSOR_CMD_TYPE_PWR_UP: @@ -604,9 +618,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc) { CAM_ERR(CAM_OIS, "Failed: parse power settings"); - cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + break; } break; default: @@ -624,9 +636,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "init parsing failed: %d", rc); - cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + break; } } else if ((o_ctrl->is_ois_calib != 0) && (o_ctrl->i2c_calib_data.is_settings_valid == @@ -643,22 +653,22 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "Calib parsing failed: %d", rc); - cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + break; } } break; } cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); + + if (rc < 0) + goto end; } if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) { rc = cam_ois_power_up(o_ctrl); if (rc) { CAM_ERR(CAM_OIS, " OIS Power up failed"); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } o_ctrl->cam_ois_state = CAM_OIS_CONFIG; } @@ -715,8 +725,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_WARN(CAM_OIS, "Not in right state to control OIS: %d", o_ctrl->cam_ois_state); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } offset = (uint32_t *)&csl_packet->payload; offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); @@ -729,23 +738,20 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings); if (rc < 0) { CAM_ERR(CAM_OIS, "Cannot apply mode settings"); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } rc = delete_request(i2c_reg_settings); if (rc < 0) { CAM_ERR(CAM_OIS, "Fail deleting Mode data: rc: %d", rc); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } break; case CAM_OIS_PACKET_OPCODE_READ: { @@ -757,16 +763,14 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_WARN(CAM_OIS, "Not in right state to read OIS: %d", o_ctrl->cam_ois_state); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } CAM_DBG(CAM_OIS, "number of I/O configs: %d:", csl_packet->num_io_configs); if (csl_packet->num_io_configs == 0) { CAM_ERR(CAM_OIS, "No I/O configs to process"); rc = -EINVAL; - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } INIT_LIST_HEAD(&(i2c_read_settings.list_head)); @@ -779,8 +783,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (io_cfg == NULL) { CAM_ERR(CAM_OIS, "I/O config is invalid(NULL)"); rc = -EINVAL; - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } offset = (uint32_t *)&csl_packet->payload; @@ -793,8 +796,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) cmd_desc, 1, &io_cfg[0]); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS read pkt parsing failed: %d", rc); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } rc = cam_sensor_i2c_read_data( @@ -803,8 +805,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "cannot read data rc: %d", rc); delete_request(&i2c_read_settings); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } if (csl_packet->num_io_configs > 1) { @@ -814,8 +815,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_ERR(CAM_OIS, "write qtimer failed rc: %d", rc); delete_request(&i2c_read_settings); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } } @@ -823,8 +823,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "Failed in deleting the read settings"); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } break; } @@ -834,8 +833,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_ERR(CAM_OIS, "Not in right state to write time to OIS: %d", o_ctrl->cam_ois_state); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } offset = (uint32_t *)&csl_packet->payload; offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); @@ -848,47 +846,45 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) cmd_desc, 1, NULL); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } rc = cam_ois_update_time(i2c_reg_settings); if (rc < 0) { CAM_ERR(CAM_OIS, "Cannot update time"); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings); if (rc < 0) { CAM_ERR(CAM_OIS, "Cannot apply mode settings"); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } rc = delete_request(i2c_reg_settings); if (rc < 0) { CAM_ERR(CAM_OIS, "Fail deleting Mode data: rc: %d", rc); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; + goto end; } break; } default: CAM_ERR(CAM_OIS, "Invalid Opcode: %d", (csl_packet->header.op_code & 0xFFFFFF)); - cam_mem_put_cpu_buf(dev_config.packet_handle); - return -EINVAL; + rc = -EINVAL; + goto end; } - if (!rc) { - cam_mem_put_cpu_buf(dev_config.packet_handle); - return rc; - } + if (!rc) + goto end; + pwr_dwn: - cam_mem_put_cpu_buf(dev_config.packet_handle); cam_ois_power_down(o_ctrl); +end: + cam_common_mem_free(csl_packet); +put_ref: + cam_mem_put_cpu_buf(dev_config.packet_handle); return rc; } diff --git a/drivers/cam_utils/cam_common_util.c b/drivers/cam_utils/cam_common_util.c index 23681509f490..c221741bdeff 100644 --- a/drivers/cam_utils/cam_common_util.c +++ b/drivers/cam_utils/cam_common_util.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -72,3 +73,36 @@ void cam_common_util_thread_switch_delay_detect( } } + +int cam_common_mem_kdup(void **dst, + void *src, size_t size) +{ + gfp_t flag = GFP_KERNEL; + + if (!src || !dst || !size) { + CAM_ERR(CAM_UTIL, "Invalid params src: %pK dst: %pK size: %u", + src, dst, size); + return -EINVAL; + } + + if (!in_task()) + flag = GFP_ATOMIC; + + *dst = kzalloc(size, flag); + if (!*dst) { + CAM_ERR(CAM_UTIL, "Failed to allocate memory with size: %u", size); + return -ENOMEM; + } + + memcpy(*dst, src, size); + CAM_DBG(CAM_UTIL, "Allocate and copy memory with size: %u", size); + + return 0; +} +EXPORT_SYMBOL(cam_common_mem_kdup); + +void cam_common_mem_free(void *memory) +{ + kfree(memory); +} +EXPORT_SYMBOL(cam_common_mem_free); diff --git a/drivers/cam_utils/cam_common_util.h b/drivers/cam_utils/cam_common_util.h index 867aa5753f5a..8ef0c52f90d8 100644 --- a/drivers/cam_utils/cam_common_util.h +++ b/drivers/cam_utils/cam_common_util.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_COMMON_UTIL_H_ @@ -85,4 +86,21 @@ uint32_t cam_common_util_remove_duplicate_arr(int32_t *array, void cam_common_util_thread_switch_delay_detect(const char *token, ktime_t scheduled_time, uint32_t threshold); +/** + * @brief: Memory alloc and copy + * + * @dst: Address of destination address of memory + * @src: Source address of memory + * @size: Length of memory + * + * @return 0 if success in register non-zero if failes + */ +int cam_common_mem_kdup(void **dst, void *src, size_t size); + +/** + * @brief: Free the memory + * + * @memory: Address of memory + */ +void cam_common_mem_free(void *memory); #endif /* _CAM_COMMON_UTIL_H_ */ From 250ab26be0ae815efe9cf04606d29bfef927b6b8 Mon Sep 17 00:00:00 2001 From: Pranav Sanwal Date: Mon, 30 Sep 2024 16:04:04 +0530 Subject: [PATCH 4/4] msm: camera: isp: Copy the userdata in kernel to avoid TOCTOU condition Userspace is still able to access blob data after submitting to kmd and can alter it's contents. This change copy the information in kernel space and then perform relevant checks and actions if the data is unaltered. CRs-Fixed: 3923843 Change-Id: I9ec3c95a3e04770ab0b00bc07c8a0d133f779ed1 Signed-off-by: Pranav Sanwal --- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 48 +++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index c875fc67e0d7..829950936690 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -5993,7 +5993,9 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, break; case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: { struct cam_isp_bw_config *bw_config; + struct cam_isp_bw_config *bw_config_u; struct cam_isp_prepare_hw_update_data *prepare_hw_data; + size_t bw_config_size; CAM_WARN_RATE_LIMIT_CUSTOM(CAM_PERF, 300, 1, "Deprecated Blob TYPE_BW_CONFIG"); @@ -6002,10 +6004,24 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, return -EINVAL; } - bw_config = (struct cam_isp_bw_config *)blob_data; + bw_config_u = (struct cam_isp_bw_config *)blob_data; - if (bw_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { - CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config", + if (bw_config_u->num_rdi > CAM_IFE_RDI_NUM_MAX || !bw_config_u->num_rdi) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config, ctx_idx: %u", + bw_config_u->num_rdi, ife_mgr_ctx->ctx_index); + return -EINVAL; + } + + bw_config_size = sizeof(struct cam_isp_bw_config) + ((bw_config_u->num_rdi-1)* + sizeof(struct cam_isp_bw_vote)); + + rc = cam_common_mem_kdup((void **)&bw_config, bw_config_u, bw_config_size); + if (rc) { + CAM_ERR(CAM_ISP, "Alloc and copy request bw_config failed"); + return rc; + } + if (bw_config_u->num_rdi != bw_config->num_rdi) { + CAM_ERR(CAM_ISP, "num_rdi changed,userspace:%d, kernel:%d", bw_config_u->num_rdi, bw_config->num_rdi); return -EINVAL; } @@ -6053,6 +6069,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: { size_t bw_config_size = 0; struct cam_isp_bw_config_v2 *bw_config; + struct cam_isp_bw_config_v2 *bw_config_u; struct cam_isp_prepare_hw_update_data *prepare_hw_data; if (blob_size < sizeof(struct cam_isp_bw_config_v2)) { @@ -6060,12 +6077,27 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, return -EINVAL; } - bw_config = (struct cam_isp_bw_config_v2 *)blob_data; + bw_config_u = (struct cam_isp_bw_config_v2 *)blob_data; - if (bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES || - !bw_config->num_paths) { - CAM_ERR(CAM_ISP, "Invalid num paths %d", - bw_config->num_paths); + if (bw_config_u->num_paths > CAM_ISP_MAX_PER_PATH_VOTES || + !bw_config_u->num_paths) { + CAM_ERR(CAM_ISP, "Invalid num paths %d ctx_idx: %u", + bw_config_u->num_paths, ife_mgr_ctx->ctx_index); + return -EINVAL; + } + + bw_config_size = sizeof(struct cam_isp_bw_config_v2) + ((bw_config_u->num_paths-1)* + sizeof(struct cam_axi_per_path_bw_vote)); + + rc = cam_common_mem_kdup((void **)&bw_config, bw_config_u, bw_config_size); + if (rc) { + CAM_ERR(CAM_ISP, "Alloc and copy request bw_config failed"); + return rc; + } + + if (bw_config_u->num_paths != bw_config->num_paths) { + CAM_ERR(CAM_ISP, "num_paths changed,userspace:%d, kernel:%d", bw_config_u->num_paths, + bw_config->num_paths); return -EINVAL; }