forked from rubenslte/android_kernel_samsung_msm8226
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. CAF-Change-Id: I047e3264333d767541e43b7dadd1727232fd48ef Signed-off-by: Zhen Kong <zkong@codeaurora.org> [haggertk]: Backport to 3.4/msm8974 CVE-2017-0613 Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org> Change-Id: Ida2babcd9d0ad6308f39b1b8389352b45d179664
This commit is contained in:
committed by
Francescodario Cuzzocrea
parent
24538e44a9
commit
a9cfcae516
+85
-29
@@ -1,6 +1,6 @@
|
||||
/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
|
||||
*
|
||||
* Copyright (c) 2012-2014, 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
|
||||
@@ -1256,11 +1256,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 ((uint32_t)req_ptr->cmd_req_buf !=
|
||||
data_ptr->client.user_virt_sb_base) {
|
||||
@@ -1277,14 +1272,11 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
|
||||
|| ((uint32_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;
|
||||
@@ -1298,24 +1290,11 @@ int __qseecom_process_rpmb_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_command_scm_resp resp;
|
||||
struct qseecom_send_svc_cmd_req req;
|
||||
/*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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1334,6 +1313,83 @@ 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_command_scm_resp resp;
|
||||
struct qseecom_send_svc_cmd_req req;
|
||||
|
||||
/*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) {
|
||||
|
||||
Reference in New Issue
Block a user