mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
218 lines
7.2 KiB
Diff
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
|
||
|
|