mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-10 08:24:20 -05:00
135 lines
4.3 KiB
Diff
135 lines
4.3 KiB
Diff
From e80b88323f9ff0bb0e545f209eec08ec56fca816 Mon Sep 17 00:00:00 2001
|
|
From: Zhen Kong <zkong@codeaurora.org>
|
|
Date: Mon, 18 Jul 2016 13:20:18 -0700
|
|
Subject: qseecom: validate the inputs of __qseecom_send_modfd_resp
|
|
|
|
The resp_len and resp_buf_ptr of qseecom_send_modfd_listener_resp
|
|
are not checked, then an userspace application that manipulates
|
|
resp_len can corrupt the kernel memory. Thus make changes to
|
|
validate these parameters.
|
|
|
|
CRs-fixed: 1036418
|
|
Change-Id: Id43ec6b55b332d0dac09a9abb998a410f49b44f7
|
|
Signed-off-by: Zhen Kong <zkong@codeaurora.org>
|
|
---
|
|
drivers/misc/qseecom.c | 78 +++++++++++++++++++++++++++++++++++++++-----------
|
|
1 file changed, 61 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
|
|
index b175965c..1168181 100644
|
|
--- a/drivers/misc/qseecom.c
|
|
+++ b/drivers/misc/qseecom.c
|
|
@@ -3065,41 +3065,80 @@ static int qseecom_send_resp(void)
|
|
}
|
|
|
|
|
|
-static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
|
|
- void __user *argp)
|
|
+static int __validate_send_modfd_resp_inputs(struct qseecom_dev_handle *data,
|
|
+ struct qseecom_send_modfd_listener_resp *resp,
|
|
+ struct qseecom_registered_listener_list *this_lstnr)
|
|
{
|
|
- struct qseecom_send_modfd_listener_resp resp;
|
|
int i;
|
|
- struct qseecom_registered_listener_list *this_lstnr = NULL;
|
|
|
|
- if (copy_from_user(&resp, argp, sizeof(resp))) {
|
|
- pr_err("copy_from_user failed");
|
|
+ if (!data || !resp || !this_lstnr) {
|
|
+ pr_err("listener handle or resp msg is null\n");
|
|
return -EINVAL;
|
|
}
|
|
- this_lstnr = __qseecom_find_svc(data->listener.id);
|
|
- if (this_lstnr == NULL)
|
|
+
|
|
+ if (resp->resp_buf_ptr == NULL) {
|
|
+ pr_err("resp buffer is null\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ /* validate resp buf length */
|
|
+ if ((resp->resp_len == 0) ||
|
|
+ (resp->resp_len > this_lstnr->sb_length)) {
|
|
+ pr_err("resp buf length %d not valid\n", resp->resp_len);
|
|
return -EINVAL;
|
|
+ }
|
|
|
|
- if (resp.resp_buf_ptr == NULL) {
|
|
- pr_err("Invalid resp_buf_ptr\n");
|
|
+ if ((uintptr_t)resp->resp_buf_ptr > (ULONG_MAX - resp->resp_len)) {
|
|
+ pr_err("Integer overflow in resp_len & resp_buf\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if ((uintptr_t)this_lstnr->user_virt_sb_base >
|
|
+ (ULONG_MAX - this_lstnr->sb_length)) {
|
|
+ pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
|
|
return -EINVAL;
|
|
}
|
|
+ /* validate resp buf */
|
|
+ if (((uintptr_t)resp->resp_buf_ptr <
|
|
+ (uintptr_t)this_lstnr->user_virt_sb_base) ||
|
|
+ ((uintptr_t)resp->resp_buf_ptr >=
|
|
+ ((uintptr_t)this_lstnr->user_virt_sb_base +
|
|
+ this_lstnr->sb_length)) ||
|
|
+ (((uintptr_t)resp->resp_buf_ptr + resp->resp_len) >
|
|
+ ((uintptr_t)this_lstnr->user_virt_sb_base +
|
|
+ this_lstnr->sb_length))) {
|
|
+ pr_err("resp buf is out of shared buffer region\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
/* validate offsets */
|
|
for (i = 0; i < MAX_ION_FD; i++) {
|
|
- if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
|
|
+ if (resp->ifd_data[i].cmd_buf_offset >= resp->resp_len) {
|
|
pr_err("Invalid offset %d = 0x%x\n",
|
|
- i, resp.ifd_data[i].cmd_buf_offset);
|
|
+ i, resp->ifd_data[i].cmd_buf_offset);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
- if ((resp.resp_buf_ptr < this_lstnr->user_virt_sb_base) ||
|
|
- ((uintptr_t)resp.resp_buf_ptr >=
|
|
- ((uintptr_t)this_lstnr->user_virt_sb_base +
|
|
- this_lstnr->sb_length))) {
|
|
- pr_err("resp_buf_ptr address not within shared buffer\n");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
|
|
+ void __user *argp, bool is_64bit_addr)
|
|
+{
|
|
+ struct qseecom_send_modfd_listener_resp resp;
|
|
+ struct qseecom_registered_listener_list *this_lstnr = NULL;
|
|
+
|
|
+ if (copy_from_user(&resp, argp, sizeof(resp))) {
|
|
+ pr_err("copy_from_user failed");
|
|
return -EINVAL;
|
|
}
|
|
+
|
|
+ this_lstnr = __qseecom_find_svc(data->listener.id);
|
|
+ if (this_lstnr == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (__validate_send_modfd_resp_inputs(data, &resp, this_lstnr))
|
|
+ return -EINVAL;
|
|
+
|
|
resp.resp_buf_ptr = this_lstnr->sb_virt +
|
|
(uintptr_t)(resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
|
|
__qseecom_update_cmd_buf(&resp, false, data, true);
|
|
@@ -3108,6 +3147,11 @@ static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
|
|
return 0;
|
|
}
|
|
|
|
+static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
|
|
+ void __user *argp)
|
|
+{
|
|
+ return __qseecom_send_modfd_resp(data, argp, false);
|
|
+}
|
|
|
|
static int qseecom_get_qseos_version(struct qseecom_dev_handle *data,
|
|
void __user *argp)
|
|
--
|
|
cgit v1.1
|
|
|