DivestOS/Patches/Linux_CVEs/CVE-2014-9884/0.patch

152 lines
5.2 KiB
Diff

From f4948193c46f75e16d4382c4472485ab12b7bd17 Mon Sep 17 00:00:00 2001
From: Zhen Kong <zkong@codeaurora.org>
Date: Mon, 25 Nov 2013 13:05:35 -0800
Subject: qseecom: Add checks for user space buffer pointers
Validate pointers send from user space and pointers
embedded within the mesasge sent from user space.
Change-Id: I1be54924ef3d301908af6e8d4e6506f2aa7f6428
Signed-off-by: Mona Hossain <mhossain@codeaurora.org>
Signed-off-by: Zhen Kong <zkong@codeaurora.org>
---
drivers/misc/qseecom.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 60 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 0bc18fb..c5c0ce8 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -99,7 +99,7 @@ static DEFINE_MUTEX(clk_access_lock);
struct qseecom_registered_listener_list {
struct list_head list;
struct qseecom_register_listener_req svc;
- u8 *sb_reg_req;
+ uint32_t user_virt_sb_base;
u8 *sb_virt;
s32 sb_phys;
size_t sb_length;
@@ -319,6 +319,10 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
pr_err("copy_from_user failed\n");
return ret;
}
+ if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
+ rcvd_lstnr.sb_size))
+ return -EFAULT;
+
data->listener.id = 0;
if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
pr_err("Service is not unique and is already registered\n");
@@ -336,6 +340,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
new_entry->svc.listener_id = rcvd_lstnr.listener_id;
new_entry->sb_length = rcvd_lstnr.sb_size;
+ new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
pr_err("qseecom_set_sb_memoryfailed\n");
kzfree(new_entry);
@@ -446,6 +451,10 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
req.ifd_data_fd, req.sb_len, req.virt_sb_base);
return -EFAULT;
}
+ if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
+ req.sb_len))
+ return -EFAULT;
+
/* Get the handle of the shared fd */
data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
req.ifd_data_fd);
@@ -861,6 +870,13 @@ static uint32_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
}
+static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
+ uint32_t virt)
+{
+ return (uint32_t)data->client.sb_virt +
+ (virt - data->client.user_virt_sb_base);
+}
+
int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
struct qseecom_send_svc_cmd_req *req_ptr,
struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
@@ -1269,6 +1285,24 @@ static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
pr_err("copy_from_user failed\n");
return ret;
}
+
+ if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
+ pr_err("cmd buffer or response buffer is null\n");
+ return -EINVAL;
+ }
+ if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
+ ((uint32_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 (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
+ ((uint32_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;
+ }
send_cmd_req.cmd_req_buf = req.cmd_req_buf;
send_cmd_req.cmd_req_len = req.cmd_req_len;
send_cmd_req.resp_buf = req.resp_buf;
@@ -1282,6 +1316,11 @@ static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
return -EINVAL;
}
}
+ req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uint32_t)req.cmd_req_buf);
+ req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uint32_t)req.resp_buf);
+
ret = __qseecom_update_cmd_buf(&req, false, data, false);
if (ret)
return ret;
@@ -1877,11 +1916,20 @@ static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
{
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");
return -EINVAL;
}
+ this_lstnr = __qseecom_find_svc(data->listener.id);
+ if (this_lstnr == NULL)
+ return -EINVAL;
+
+ if (resp.resp_buf_ptr == NULL) {
+ pr_err("Invalid resp_buf_ptr\n");
+ return -EINVAL;
+ }
/* validate offsets */
for (i = 0; i < MAX_ION_FD; i++) {
if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
@@ -1890,6 +1938,17 @@ static int qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
return -EINVAL;
}
}
+
+ if (((uint32_t)resp.resp_buf_ptr <
+ this_lstnr->user_virt_sb_base)
+ || ((uint32_t)resp.resp_buf_ptr >=
+ (this_lstnr->user_virt_sb_base +
+ this_lstnr->sb_length))) {
+ pr_err("resp_buf_ptr address not within shared buffer\n");
+ return -EINVAL;
+ }
+ resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
+ (resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
__qseecom_update_cmd_buf(&resp, false, data, true);
qseecom.send_resp_flag = 1;
wake_up_interruptible(&qseecom.send_resp_wq);
--
cgit v1.1