DivestOS/Patches/Linux_CVEs/CVE-2017-0613/ANY/0001.patch
2017-11-07 17:32:46 -05:00

218 lines
7.2 KiB
Diff

From b108c651cae9913da1ab163cb4e5f7f2db87b747 Mon Sep 17 00:00:00 2001
From: Zhen Kong <zkong@codeaurora.org>
Date: Wed, 11 Jan 2017 12:12:31 -0800
Subject: 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>
---
drivers/misc/qseecom.c | 152 ++++++++++++++++++++++++++++---------------------
1 file changed, 88 insertions(+), 64 deletions(-)
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 20949487..5e37cd6 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -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) {
--
cgit v1.1