msm: camera: isp: Copy the userdata in kernel to avoid TOCTOU

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 <quic_psanwal@quicinc.com>
Signed-off-by: Shivakumar Malke <quic_smalke@quicinc.com>
This commit is contained in:
Shivakumar Malke
2024-11-05 17:44:05 +05:30
parent 23b51487f1
commit 5ab77bca44
3 changed files with 105 additions and 9 deletions

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/slab.h>
@@ -5663,7 +5663,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");
@@ -5672,11 +5674,26 @@ 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);
cam_common_mem_free(bw_config);
return -EINVAL;
}
@@ -5689,6 +5706,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
"Max size exceeded in bw config num_rdi:%u size per port:%lu",
bw_config->num_rdi,
sizeof(struct cam_isp_bw_vote));
cam_common_mem_free(bw_config);
return -EINVAL;
}
}
@@ -5701,12 +5719,14 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
blob_size, sizeof(struct cam_isp_bw_config) +
(bw_config->num_rdi - 1) *
sizeof(struct cam_isp_bw_vote));
cam_common_mem_free(bw_config);
return -EINVAL;
}
if (!prepare || !prepare->priv ||
(bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) {
CAM_ERR(CAM_ISP, "Invalid inputs");
cam_common_mem_free(bw_config);
return -EINVAL;
}
@@ -5717,11 +5737,13 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
bw_config, sizeof(prepare_hw_data->bw_config[0]));
prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V1;
prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
cam_common_mem_free(bw_config);
}
break;
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)) {
@@ -5729,12 +5751,28 @@ 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);
cam_common_mem_free(bw_config);
return -EINVAL;
}
@@ -5749,6 +5787,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
bw_config->num_paths - 1,
sizeof(
struct cam_axi_per_path_bw_vote));
cam_common_mem_free(bw_config);
return -EINVAL;
}
}
@@ -5762,12 +5801,14 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
blob_size, bw_config->num_paths,
sizeof(struct cam_isp_bw_config_v2),
sizeof(struct cam_axi_per_path_bw_vote));
cam_common_mem_free(bw_config);
return -EINVAL;
}
if (!prepare || !prepare->priv ||
(bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) {
CAM_ERR(CAM_ISP, "Invalid inputs");
cam_common_mem_free(bw_config);
return -EINVAL;
}
@@ -5785,6 +5826,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V2;
prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
cam_common_mem_free(bw_config);
}
break;
case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: {

View File

@@ -1,11 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/string.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include "cam_common_util.h"
#include "cam_debug_util.h"
@@ -48,3 +50,36 @@ uint32_t cam_common_util_remove_duplicate_arr(int32_t *arr, uint32_t num)
return wr_idx;
}
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 = kvzalloc(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)
{
kvfree(memory);
}
EXPORT_SYMBOL(cam_common_mem_free);

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_COMMON_UTIL_H_
@@ -64,4 +65,22 @@ int cam_common_util_get_string_index(const char **strings,
uint32_t cam_common_util_remove_duplicate_arr(int32_t *array,
uint32_t num);
/**
* @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_ */