qseecom: improve input validatation for qseecom_send_service_cmd
Make change to improve input validation on request and response buffers' address and length for qseecom_send_service_cmd. Change-Id: I047e3264333d767541e43b7dadd1727232fd48ef Signed-off-by: Zhen Kong <zkong@codeaurora.org>
This commit is contained in:
parent
0a8e939a4e
commit
b108c651ca
1 changed files with 88 additions and 64 deletions
|
@ -1,6 +1,6 @@
|
|||
/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
|
||||
*
|
||||
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -2634,11 +2634,6 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
|
||||
pr_err("Invalid req/resp buffer, exiting\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clients need to ensure req_buf is at base offset of shared buffer */
|
||||
if ((uintptr_t)req_ptr->cmd_req_buf !=
|
||||
data_ptr->client.user_virt_sb_base) {
|
||||
|
@ -2646,15 +2641,11 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((uintptr_t)req_ptr->resp_buf <
|
||||
data_ptr->client.user_virt_sb_base) ||
|
||||
((uintptr_t)req_ptr->resp_buf >=
|
||||
(data_ptr->client.user_virt_sb_base +
|
||||
data_ptr->client.sb_length))){
|
||||
pr_err("response buffer address not within shared bufffer\n");
|
||||
if (data_ptr->client.sb_length <
|
||||
sizeof(struct qseecom_rpmb_provision_key)) {
|
||||
pr_err("shared buffer is too small to hold key type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
req_buf = data_ptr->client.sb_virt;
|
||||
|
||||
send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
|
||||
|
@ -2681,36 +2672,6 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((uintptr_t)req_ptr->cmd_req_buf <
|
||||
data_ptr->client.user_virt_sb_base) ||
|
||||
((uintptr_t)req_ptr->cmd_req_buf >=
|
||||
(data_ptr->client.user_virt_sb_base +
|
||||
data_ptr->client.sb_length))) {
|
||||
pr_err("cmd buffer address not within shared bufffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((uintptr_t)req_ptr->resp_buf <
|
||||
data_ptr->client.user_virt_sb_base) ||
|
||||
((uintptr_t)req_ptr->resp_buf >=
|
||||
(data_ptr->client.user_virt_sb_base +
|
||||
data_ptr->client.sb_length))){
|
||||
pr_err("response buffer address not within shared bufffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((req_ptr->cmd_req_len == 0) || (req_ptr->resp_len == 0) ||
|
||||
req_ptr->cmd_req_len > data_ptr->client.sb_length ||
|
||||
req_ptr->resp_len > data_ptr->client.sb_length) {
|
||||
pr_err("cmd buffer length or response buffer length not valid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (req_ptr->cmd_req_len > UINT_MAX - req_ptr->resp_len) {
|
||||
pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reqd_len_sb_in = req_ptr->cmd_req_len + req_ptr->resp_len;
|
||||
if (reqd_len_sb_in > data_ptr->client.sb_length) {
|
||||
pr_err("Not enough memory to fit cmd_buf and resp_buf. ");
|
||||
|
@ -2732,28 +2693,11 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
|
||||
void __user *argp)
|
||||
static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
|
||||
struct qseecom_send_svc_cmd_req *req)
|
||||
{
|
||||
int ret = 0;
|
||||
struct qseecom_client_send_service_ireq send_svc_ireq;
|
||||
struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
|
||||
struct qseecom_command_scm_resp resp;
|
||||
struct qseecom_send_svc_cmd_req req;
|
||||
void *send_req_ptr;
|
||||
size_t req_buf_size;
|
||||
|
||||
/*struct qseecom_command_scm_resp resp;*/
|
||||
|
||||
if (copy_from_user(&req,
|
||||
(void __user *)argp,
|
||||
sizeof(req))) {
|
||||
pr_err("copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if ((req.resp_buf == NULL) || (req.cmd_req_buf == NULL)) {
|
||||
pr_err("cmd buffer or response buffer is null\n");
|
||||
if (!req || !req->resp_buf || !req->cmd_req_buf) {
|
||||
pr_err("req or cmd buffer or response buffer is null\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2777,6 +2721,86 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((uintptr_t)req->cmd_req_buf <
|
||||
data->client.user_virt_sb_base) ||
|
||||
((uintptr_t)req->cmd_req_buf >=
|
||||
(data->client.user_virt_sb_base + data->client.sb_length))) {
|
||||
pr_err("cmd buffer address not within shared bufffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (((uintptr_t)req->resp_buf <
|
||||
data->client.user_virt_sb_base) ||
|
||||
((uintptr_t)req->resp_buf >=
|
||||
(data->client.user_virt_sb_base + data->client.sb_length))) {
|
||||
pr_err("response buffer address not within shared bufffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
|
||||
(req->cmd_req_len > data->client.sb_length) ||
|
||||
(req->resp_len > data->client.sb_length)) {
|
||||
pr_err("cmd buf length or response buf length not valid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (req->cmd_req_len > UINT_MAX - req->resp_len) {
|
||||
pr_err("Integer overflow detected in req_len & rsp_len\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
|
||||
pr_debug("Not enough memory to fit cmd_buf.\n");
|
||||
pr_debug("resp_buf. Required: %u, Available: %zu\n",
|
||||
(req->cmd_req_len + req->resp_len),
|
||||
data->client.sb_length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
|
||||
pr_err("Integer overflow in req_len & cmd_req_buf\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
|
||||
pr_err("Integer overflow in resp_len & resp_buf\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (data->client.user_virt_sb_base >
|
||||
(ULONG_MAX - data->client.sb_length)) {
|
||||
pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
|
||||
((uintptr_t)data->client.user_virt_sb_base +
|
||||
data->client.sb_length)) ||
|
||||
(((uintptr_t)req->resp_buf + req->resp_len) >
|
||||
((uintptr_t)data->client.user_virt_sb_base +
|
||||
data->client.sb_length))) {
|
||||
pr_err("cmd buf or resp buf is out of shared buffer region\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
|
||||
void __user *argp)
|
||||
{
|
||||
int ret = 0;
|
||||
struct qseecom_client_send_service_ireq send_svc_ireq;
|
||||
struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
|
||||
struct qseecom_command_scm_resp resp;
|
||||
struct qseecom_send_svc_cmd_req req;
|
||||
void *send_req_ptr;
|
||||
size_t req_buf_size;
|
||||
|
||||
/*struct qseecom_command_scm_resp resp;*/
|
||||
|
||||
if (copy_from_user(&req,
|
||||
(void __user *)argp,
|
||||
sizeof(req))) {
|
||||
pr_err("copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (__validate_send_service_cmd_inputs(data, &req))
|
||||
return -EINVAL;
|
||||
|
||||
data->type = QSEECOM_SECURE_SERVICE;
|
||||
|
||||
switch (req.cmd_id) {
|
||||
|
|
Loading…
Add table
Reference in a new issue