From f4948193c46f75e16d4382c4472485ab12b7bd17 Mon Sep 17 00:00:00 2001 From: Zhen Kong 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 Signed-off-by: Zhen Kong --- 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