aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMekala Natarajan <mekalan@codeaurora.org>2015-01-27 16:26:51 -0800
committerPat Tjin <pattjin@google.com>2015-01-28 22:02:30 +0000
commiteec2459384835d85318caddbd8245876afc1933b (patch)
treedb61dc25cf1468dfab49371f8398386a1be126d8
parentd37cf21b92d65aa2961b5b059e23551951c93737 (diff)
qseecom: Add checks for send_cmd inputsandroid-5.1.0_r0.7
Improve user input validation across send cmd APIs. Add new API __validate_send_cmd_inputs() to validate all user provided inputs. Bug: 19136582 Change-Id: Ibbb0c0e7e5483f653bd59b927562b63c1e43c365 Signed-off-by: Mona Hossain <mhossain@codeaurora.org> Signed-off-by: Mekala Natarajan <mekalan@codeaurora.org>
-rw-r--r--drivers/misc/qseecom.c163
1 files changed, 92 insertions, 71 deletions
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 4399140e227f..6caec4614d06 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -615,7 +615,7 @@ static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
}
if (req_mode > HIGH) {
pr_err("Invalid bandwidth mode (%d)\n", req_mode);
- return ret;
+ return -EINVAL;
}
mutex_lock(&qsee_bw_mutex);
ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
@@ -1343,19 +1343,15 @@ exit:
return ret;
}
-static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
+static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
struct qseecom_send_cmd_req *req)
{
- int ret = 0;
- u32 reqd_len_sb_in = 0;
- struct qseecom_client_send_data_ireq send_data_req;
- struct qseecom_command_scm_resp resp;
- unsigned long flags;
- struct qseecom_registered_app_list *ptr_app;
- bool found_app = false;
- int name_len = 0;
-
- if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+ if (!data || !data->client.ihandle) {
+ pr_err("Client or client handle is not initialized\n");
+ return -EINVAL;
+ }
+ if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
+ (req->cmd_req_buf == NULL)) {
pr_err("cmd buffer or response buffer is null\n");
return -EINVAL;
}
@@ -1365,36 +1361,68 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
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))){
+ 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 buffer length or "
- "response buffer length not valid\n");
+ if ((req->cmd_req_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, exiting now\n");
+ pr_err("Integer overflow detected in req_len & rsp_len\n");
return -EINVAL;
}
-
- reqd_len_sb_in = req->cmd_req_len + req->resp_len;
- if (reqd_len_sb_in > data->client.sb_length) {
- pr_debug("Not enough memory to fit cmd_buf and "
- "resp_buf. Required: %u, Available: %u\n",
- reqd_len_sb_in, data->client.sb_length);
+ 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_cmd(struct qseecom_dev_handle *data,
+ struct qseecom_send_cmd_req *req)
+{
+ int ret = 0;
+ u32 reqd_len_sb_in = 0;
+ struct qseecom_client_send_data_ireq send_data_req;
+ struct qseecom_command_scm_resp resp;
+ unsigned long flags;
+ struct qseecom_registered_app_list *ptr_app;
+ bool found_app = false;
+ int name_len = 0;
+
+ reqd_len_sb_in = req->cmd_req_len + req->resp_len;
/* find app_id & img_name from list */
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
@@ -1468,6 +1496,10 @@ static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
pr_err("copy_from_user failed\n");
return ret;
}
+
+ if (__validate_send_cmd_inputs(data, &req))
+ return -EINVAL;
+
ret = __qseecom_send_cmd(data, &req);
if (ret)
@@ -1476,30 +1508,33 @@ static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
return ret;
}
-int boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
+int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
struct qseecom_send_modfd_listener_resp *lstnr_resp,
struct qseecom_dev_handle *data, bool listener_svc,
int i) {
- int ret = 0;
if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
- if (cmd_req->ifd_data[i].cmd_buf_offset >
- cmd_req->cmd_req_len - sizeof(uint32_t)) {
+ if ((cmd_req->cmd_req_len < sizeof(uint32_t)) ||
+ (cmd_req->ifd_data[i].cmd_buf_offset >
+ cmd_req->cmd_req_len - sizeof(uint32_t))) {
pr_err("Invalid offset 0x%x\n",
cmd_req->ifd_data[i].cmd_buf_offset);
- return ++ret;
+ return -EINVAL;
}
} else if ((listener_svc) && (lstnr_resp->ifd_data[i].fd > 0)) {
- if (lstnr_resp->ifd_data[i].cmd_buf_offset >
- lstnr_resp->resp_len - sizeof(uint32_t)) {
+ if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - sizeof(uint32_t))) {
pr_err("Invalid offset 0x%x\n",
lstnr_resp->ifd_data[i].cmd_buf_offset);
- return ++ret;
+ return -EINVAL;
}
}
- return ret;
+ return 0;
}
+#define SG_ENTRY_SZ sizeof(struct qseecom_sg_entry)
+
static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
struct qseecom_dev_handle *data,
bool listener_svc)
@@ -1574,7 +1609,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
uint32_t *update;
update = (uint32_t *) field;
- if (boundary_checks_offset(cmd_req, lstnr_resp, data,
+ if (__boundary_checks_offset(cmd_req, lstnr_resp, data,
listener_svc, i))
goto err;
if (cleanup)
@@ -1588,9 +1623,11 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
int j = 0;
if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
- if (cmd_req->ifd_data[i].cmd_buf_offset >
- cmd_req->cmd_req_len -
- sizeof(struct qseecom_sg_entry)) {
+ if ((cmd_req->cmd_req_len <
+ SG_ENTRY_SZ * sg_ptr->nents) ||
+ (cmd_req->ifd_data[i].cmd_buf_offset >
+ (cmd_req->cmd_req_len -
+ SG_ENTRY_SZ * sg_ptr->nents))) {
pr_err("Invalid offset = 0x%x\n",
cmd_req->ifd_data[i].
cmd_buf_offset);
@@ -1598,9 +1635,11 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
}
} else if ((listener_svc) &&
(lstnr_resp->ifd_data[i].fd > 0)) {
- if (lstnr_resp->ifd_data[i].cmd_buf_offset >
- lstnr_resp->resp_len -
- sizeof(struct qseecom_sg_entry)) {
+ if ((lstnr_resp->resp_len <
+ SG_ENTRY_SZ * sg_ptr->nents) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ (lstnr_resp->resp_len -
+ SG_ENTRY_SZ * sg_ptr->nents))) {
pr_err("Invalid offset = 0x%x\n",
lstnr_resp->ifd_data[i].
cmd_buf_offset);
@@ -1655,35 +1694,14 @@ static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
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;
- }
-
- if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
- req.resp_len > data->client.sb_length) {
- pr_err("cmd or response buffer length not valid\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;
send_cmd_req.resp_len = req.resp_len;
+ if (__validate_send_cmd_inputs(data, &send_cmd_req))
+ return -EINVAL;
+
/* validate offsets */
for (i = 0; i < MAX_ION_FD; i++) {
if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
@@ -2331,6 +2349,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
req.cmd_req_buf = send_buf;
req.resp_buf = resp_buf;
+ if (__validate_send_cmd_inputs(data, &req))
+ return -EINVAL;
+
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
if (qseecom.support_bus_scaling) {