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 <quic_chengxue@quicinc.com>
This commit is contained in:
chengxue 2024-10-08 15:38:01 +08:00 • committed by Prateek Pallav
commit 3b061e5b70
3 changed files with 115 additions and 67 deletions

View file

@ -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;
}

View file

@ -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 <linux/string.h>
@ -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);

View file

@ -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_ */