mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-30 01:46:30 -05:00
775 lines
26 KiB
Diff
775 lines
26 KiB
Diff
From 7c3bf6557c62d904b15507eb451fda8fd7ef750c Mon Sep 17 00:00:00 2001
|
|
From: Zhen Kong <zkong@codeaurora.org>
|
|
Date: Fri, 8 Jul 2016 14:40:45 -0700
|
|
Subject: qseecom: support whitelist memory for qseecom_send_modfd_cmd
|
|
|
|
qseecom_send_modfd_cmd converts ION buffer's virtual address to
|
|
scatter gather(SG) list and then sends them to TA by populating
|
|
SG list into message buffer. As the physical memory address in
|
|
SG list is used directly by TA, this allows a malicious TA to
|
|
access/corrupt arbitrary physical memory and may lead to the
|
|
process gaining kernel/root privileges. Thus, make changes to
|
|
have the QSEEComm driver passing a list of whitelist buffers
|
|
that is allowed to be mapped by TA, and the QSEE kernel, in turn,
|
|
should add checks to the register_shared_buffer syscall to make
|
|
sure the shared buffers an application is mapping falls within
|
|
one of these whitelist buffers.
|
|
|
|
CRs-fixed: 1021945
|
|
Change-Id: I776ead0030cad167afcf41ab985db7151a42d126
|
|
Signed-off-by: Zhen Kong <zkong@codeaurora.org>
|
|
---
|
|
drivers/misc/qseecom.c | 370 +++++++++++++++++++++++++++++++++++++++-----
|
|
include/soc/qcom/qseecomi.h | 47 +++++-
|
|
2 files changed, 375 insertions(+), 42 deletions(-)
|
|
|
|
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
|
|
index 8117be74..7e6a179 100644
|
|
--- a/drivers/misc/qseecom.c
|
|
+++ b/drivers/misc/qseecom.c
|
|
@@ -181,6 +181,7 @@ struct qseecom_control {
|
|
uint32_t qseos_version;
|
|
uint32_t qsee_version;
|
|
struct device *pdev;
|
|
+ bool whitelist_support;
|
|
bool commonlib_loaded;
|
|
bool commonlib64_loaded;
|
|
struct ion_handle *cmnlib_ion_handle;
|
|
@@ -242,6 +243,30 @@ struct qseecom_listener_handle {
|
|
|
|
static struct qseecom_control qseecom;
|
|
|
|
+struct sglist_info {
|
|
+ uint32_t indexAndFlags;
|
|
+ uint32_t sizeOrCount;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * The 31th bit indicates only one or multiple physical address inside
|
|
+ * the request buffer. If it is set, the index locates a single physical addr
|
|
+ * inside the request buffer, and `sizeOrCount` is the size of the memory being
|
|
+ * shared at that physical address.
|
|
+ * Otherwise, the index locates an array of {start, len} pairs (a
|
|
+ * "scatter/gather list"), and `sizeOrCount` gives the number of entries in
|
|
+ * that array.
|
|
+ *
|
|
+ * The 30th bit indicates 64 or 32bit address; when it is set, physical addr
|
|
+ * and scatter gather entry sizes are 64-bit values. Otherwise, 32-bit values.
|
|
+ *
|
|
+ * The bits [0:29] of `indexAndFlags` hold an offset into the request buffer.
|
|
+ */
|
|
+#define SGLISTINFO_SET_INDEX_FLAG(c, s, i) \
|
|
+ ((uint32_t)(((c & 1) << 31) | ((s & 1) << 30) | (i & 0x3fffffff)))
|
|
+
|
|
+#define SGLISTINFO_TABLE_SIZE (sizeof(struct sglist_info) * MAX_ION_FD)
|
|
+
|
|
struct qseecom_dev_handle {
|
|
enum qseecom_client_handle_type type;
|
|
union {
|
|
@@ -255,6 +280,8 @@ struct qseecom_dev_handle {
|
|
bool perf_enabled;
|
|
bool fast_load_enabled;
|
|
enum qseecom_bandwidth_request_mode mode;
|
|
+ struct sglist_info *sglistinfo_ptr;
|
|
+ uint32_t sglist_cnt;
|
|
};
|
|
|
|
struct qseecom_key_id_usage_desc {
|
|
@@ -565,6 +592,38 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
|
|
ret = scm_call2(smc_id, &desc);
|
|
break;
|
|
}
|
|
+ case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
|
|
+ struct qseecom_client_send_data_ireq *req;
|
|
+ struct qseecom_client_send_data_64bit_ireq *req_64bit;
|
|
+
|
|
+ smc_id = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID;
|
|
+ desc.arginfo =
|
|
+ TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID;
|
|
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
|
|
+ req = (struct qseecom_client_send_data_ireq *)
|
|
+ req_buf;
|
|
+ desc.args[0] = req->app_id;
|
|
+ desc.args[1] = req->req_ptr;
|
|
+ desc.args[2] = req->req_len;
|
|
+ desc.args[3] = req->rsp_ptr;
|
|
+ desc.args[4] = req->rsp_len;
|
|
+ desc.args[5] = req->sglistinfo_ptr;
|
|
+ desc.args[6] = req->sglistinfo_len;
|
|
+ } else {
|
|
+ req_64bit =
|
|
+ (struct qseecom_client_send_data_64bit_ireq *)
|
|
+ req_buf;
|
|
+ desc.args[0] = req_64bit->app_id;
|
|
+ desc.args[1] = req_64bit->req_ptr;
|
|
+ desc.args[2] = req_64bit->req_len;
|
|
+ desc.args[3] = req_64bit->rsp_ptr;
|
|
+ desc.args[4] = req_64bit->rsp_len;
|
|
+ desc.args[5] = req_64bit->sglistinfo_ptr;
|
|
+ desc.args[6] = req_64bit->sglistinfo_len;
|
|
+ }
|
|
+ ret = scm_call2(smc_id, &desc);
|
|
+ break;
|
|
+ }
|
|
case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
|
|
struct qseecom_client_send_service_ireq *req;
|
|
req = (struct qseecom_client_send_service_ireq *)
|
|
@@ -686,6 +745,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
|
|
ret = scm_call2(smc_id, &desc);
|
|
break;
|
|
}
|
|
+ case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
|
|
+ struct qseecom_qteec_ireq *req;
|
|
+ struct qseecom_qteec_64bit_ireq *req_64bit;
|
|
+
|
|
+ smc_id = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID;
|
|
+ desc.arginfo =
|
|
+ TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID;
|
|
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
|
|
+ req = (struct qseecom_qteec_ireq *)req_buf;
|
|
+ desc.args[0] = req->app_id;
|
|
+ desc.args[1] = req->req_ptr;
|
|
+ desc.args[2] = req->req_len;
|
|
+ desc.args[3] = req->resp_ptr;
|
|
+ desc.args[4] = req->resp_len;
|
|
+ desc.args[5] = req->sglistinfo_ptr;
|
|
+ desc.args[6] = req->sglistinfo_len;
|
|
+ } else {
|
|
+ req_64bit = (struct qseecom_qteec_64bit_ireq *)
|
|
+ req_buf;
|
|
+ desc.args[0] = req_64bit->app_id;
|
|
+ desc.args[1] = req_64bit->req_ptr;
|
|
+ desc.args[2] = req_64bit->req_len;
|
|
+ desc.args[3] = req_64bit->resp_ptr;
|
|
+ desc.args[4] = req_64bit->resp_len;
|
|
+ desc.args[5] = req_64bit->sglistinfo_ptr;
|
|
+ desc.args[6] = req_64bit->sglistinfo_len;
|
|
+ }
|
|
+ ret = scm_call2(smc_id, &desc);
|
|
+ break;
|
|
+ }
|
|
case QSEOS_TEE_INVOKE_COMMAND: {
|
|
struct qseecom_qteec_ireq *req;
|
|
struct qseecom_qteec_64bit_ireq *req_64bit;
|
|
@@ -710,6 +799,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
|
|
ret = scm_call2(smc_id, &desc);
|
|
break;
|
|
}
|
|
+ case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
|
|
+ struct qseecom_qteec_ireq *req;
|
|
+ struct qseecom_qteec_64bit_ireq *req_64bit;
|
|
+
|
|
+ smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID;
|
|
+ desc.arginfo =
|
|
+ TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID;
|
|
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
|
|
+ req = (struct qseecom_qteec_ireq *)req_buf;
|
|
+ desc.args[0] = req->app_id;
|
|
+ desc.args[1] = req->req_ptr;
|
|
+ desc.args[2] = req->req_len;
|
|
+ desc.args[3] = req->resp_ptr;
|
|
+ desc.args[4] = req->resp_len;
|
|
+ desc.args[5] = req->sglistinfo_ptr;
|
|
+ desc.args[6] = req->sglistinfo_len;
|
|
+ } else {
|
|
+ req_64bit = (struct qseecom_qteec_64bit_ireq *)
|
|
+ req_buf;
|
|
+ desc.args[0] = req_64bit->app_id;
|
|
+ desc.args[1] = req_64bit->req_ptr;
|
|
+ desc.args[2] = req_64bit->req_len;
|
|
+ desc.args[3] = req_64bit->resp_ptr;
|
|
+ desc.args[4] = req_64bit->resp_len;
|
|
+ desc.args[5] = req_64bit->sglistinfo_ptr;
|
|
+ desc.args[6] = req_64bit->sglistinfo_len;
|
|
+ }
|
|
+ ret = scm_call2(smc_id, &desc);
|
|
+ break;
|
|
+ }
|
|
case QSEOS_TEE_CLOSE_SESSION: {
|
|
struct qseecom_qteec_ireq *req;
|
|
struct qseecom_qteec_64bit_ireq *req_64bit;
|
|
@@ -2490,8 +2609,8 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
|
|
{
|
|
int ret = 0;
|
|
u32 reqd_len_sb_in = 0;
|
|
- struct qseecom_client_send_data_ireq send_data_req;
|
|
- struct qseecom_client_send_data_64bit_ireq send_data_req_64bit;
|
|
+ struct qseecom_client_send_data_ireq send_data_req = {0};
|
|
+ struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0};
|
|
struct qseecom_command_scm_resp resp;
|
|
unsigned long flags;
|
|
struct qseecom_registered_app_list *ptr_app;
|
|
@@ -2499,6 +2618,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
|
|
int name_len = 0;
|
|
void *cmd_buf = NULL;
|
|
size_t cmd_len;
|
|
+ struct sglist_info *table = data->sglistinfo_ptr;
|
|
|
|
reqd_len_sb_in = req->cmd_req_len + req->resp_len;
|
|
/* find app_id & img_name from list */
|
|
@@ -2523,7 +2643,6 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
|
|
}
|
|
|
|
if (qseecom.qsee_version < QSEE_VERSION_40) {
|
|
- send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
|
|
send_data_req.app_id = data->client.app_id;
|
|
send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
|
|
data, (uintptr_t)req->cmd_req_buf));
|
|
@@ -2531,11 +2650,14 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
|
|
send_data_req.rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
|
|
data, (uintptr_t)req->resp_buf));
|
|
send_data_req.rsp_len = req->resp_len;
|
|
+ send_data_req.sglistinfo_ptr =
|
|
+ (uint32_t)virt_to_phys(table);
|
|
+ send_data_req.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
|
|
+ dmac_flush_range((void *)table,
|
|
+ (void *)table + SGLISTINFO_TABLE_SIZE);
|
|
cmd_buf = (void *)&send_data_req;
|
|
cmd_len = sizeof(struct qseecom_client_send_data_ireq);
|
|
} else {
|
|
- send_data_req_64bit.qsee_cmd_id =
|
|
- QSEOS_CLIENT_SEND_DATA_COMMAND;
|
|
send_data_req_64bit.app_id = data->client.app_id;
|
|
send_data_req_64bit.req_ptr = __qseecom_uvirt_to_kphys(data,
|
|
(uintptr_t)req->cmd_req_buf);
|
|
@@ -2557,10 +2679,20 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
|
|
send_data_req_64bit.rsp_len);
|
|
return -EFAULT;
|
|
}
|
|
+ send_data_req_64bit.sglistinfo_ptr =
|
|
+ (uint64_t)virt_to_phys(table);
|
|
+ send_data_req_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
|
|
+ dmac_flush_range((void *)table,
|
|
+ (void *)table + SGLISTINFO_TABLE_SIZE);
|
|
cmd_buf = (void *)&send_data_req_64bit;
|
|
cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
|
|
}
|
|
|
|
+ if (qseecom.whitelist_support == false)
|
|
+ *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND;
|
|
+ else
|
|
+ *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
|
|
+
|
|
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
|
|
data->client.sb_virt,
|
|
reqd_len_sb_in,
|
|
@@ -2814,14 +2946,26 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
|
|
goto err;
|
|
}
|
|
}
|
|
- if (cleanup)
|
|
+
|
|
+ if (cleanup) {
|
|
msm_ion_do_cache_op(qseecom.ion_clnt,
|
|
ihandle, NULL, len,
|
|
ION_IOC_INV_CACHES);
|
|
- else
|
|
+ } else {
|
|
msm_ion_do_cache_op(qseecom.ion_clnt,
|
|
ihandle, NULL, len,
|
|
ION_IOC_CLEAN_INV_CACHES);
|
|
+ if (data->type == QSEECOM_CLIENT_APP) {
|
|
+ data->sglistinfo_ptr[i].indexAndFlags =
|
|
+ SGLISTINFO_SET_INDEX_FLAG(
|
|
+ (sg_ptr->nents == 1), 0,
|
|
+ req->ifd_data[i].cmd_buf_offset);
|
|
+ data->sglistinfo_ptr[i].sizeOrCount =
|
|
+ (sg_ptr->nents == 1) ?
|
|
+ sg->length : sg_ptr->nents;
|
|
+ data->sglist_cnt = i + 1;
|
|
+ }
|
|
+ }
|
|
/* Deallocate the handle */
|
|
if (!IS_ERR_OR_NULL(ihandle))
|
|
ion_free(qseecom.ion_clnt, ihandle);
|
|
@@ -2904,7 +3048,8 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
|
|
pr_err("Num of scattered entries");
|
|
pr_err(" (%d) is greater than max supported %d\n",
|
|
sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
|
|
- goto err;
|
|
+ sg = sg_ptr->sgl;
|
|
+ goto cleanup;
|
|
}
|
|
sg = sg_ptr->sgl;
|
|
if (sg_ptr->nents == 1) {
|
|
@@ -2956,14 +3101,26 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
|
|
sg = sg_next(sg);
|
|
}
|
|
}
|
|
- if (cleanup)
|
|
+cleanup:
|
|
+ if (cleanup) {
|
|
msm_ion_do_cache_op(qseecom.ion_clnt,
|
|
ihandle, NULL, len,
|
|
ION_IOC_INV_CACHES);
|
|
- else
|
|
+ } else {
|
|
msm_ion_do_cache_op(qseecom.ion_clnt,
|
|
ihandle, NULL, len,
|
|
ION_IOC_CLEAN_INV_CACHES);
|
|
+ if (data->type == QSEECOM_CLIENT_APP) {
|
|
+ data->sglistinfo_ptr[i].indexAndFlags =
|
|
+ SGLISTINFO_SET_INDEX_FLAG(
|
|
+ (sg_ptr->nents == 1), 1,
|
|
+ req->ifd_data[i].cmd_buf_offset);
|
|
+ data->sglistinfo_ptr[i].sizeOrCount =
|
|
+ (sg_ptr->nents == 1) ?
|
|
+ sg->length : sg_ptr->nents;
|
|
+ data->sglist_cnt = i + 1;
|
|
+ }
|
|
+ }
|
|
/* Deallocate the handle */
|
|
if (!IS_ERR_OR_NULL(ihandle))
|
|
ion_free(qseecom.ion_clnt, ihandle);
|
|
@@ -5544,14 +5701,23 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req,
|
|
*update = (uint32_t)sg_dma_address(sg_ptr->sgl);
|
|
}
|
|
clean:
|
|
- if (cleanup)
|
|
+ if (cleanup) {
|
|
msm_ion_do_cache_op(qseecom.ion_clnt,
|
|
ihandle, NULL, sg->length,
|
|
ION_IOC_INV_CACHES);
|
|
- else
|
|
+ } else {
|
|
msm_ion_do_cache_op(qseecom.ion_clnt,
|
|
ihandle, NULL, sg->length,
|
|
ION_IOC_CLEAN_INV_CACHES);
|
|
+ data->sglistinfo_ptr[i].indexAndFlags =
|
|
+ SGLISTINFO_SET_INDEX_FLAG(
|
|
+ (sg_ptr->nents == 1), 0,
|
|
+ req->ifd_data[i].cmd_buf_offset);
|
|
+ data->sglistinfo_ptr[i].sizeOrCount =
|
|
+ (sg_ptr->nents == 1) ?
|
|
+ sg->length : sg_ptr->nents;
|
|
+ data->sglist_cnt = i + 1;
|
|
+ }
|
|
/* Deallocate the handle */
|
|
if (!IS_ERR_OR_NULL(ihandle))
|
|
ion_free(qseecom.ion_clnt, ihandle);
|
|
@@ -5576,6 +5742,7 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
|
|
uint32_t reqd_len_sb_in = 0;
|
|
void *cmd_buf = NULL;
|
|
size_t cmd_len;
|
|
+ struct sglist_info *table = data->sglistinfo_ptr;
|
|
|
|
ret = __qseecom_qteec_validate_msg(data, req);
|
|
if (ret)
|
|
@@ -5600,8 +5767,15 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
|
|
return -ENOENT;
|
|
}
|
|
|
|
+ if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
|
|
+ (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
|
|
+ ret = __qseecom_update_qteec_req_buf(
|
|
+ (struct qseecom_qteec_modfd_req *)req, data, false);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
if (qseecom.qsee_version < QSEE_VERSION_40) {
|
|
- ireq.qsee_cmd_id = cmd_id;
|
|
ireq.app_id = data->client.app_id;
|
|
ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
|
|
(uintptr_t)req->req_ptr);
|
|
@@ -5609,10 +5783,13 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
|
|
ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
|
|
(uintptr_t)req->resp_ptr);
|
|
ireq.resp_len = req->resp_len;
|
|
+ ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
|
|
+ ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
|
|
+ dmac_flush_range((void *)table,
|
|
+ (void *)table + SGLISTINFO_TABLE_SIZE);
|
|
cmd_buf = (void *)&ireq;
|
|
cmd_len = sizeof(struct qseecom_qteec_ireq);
|
|
} else {
|
|
- ireq_64bit.qsee_cmd_id = cmd_id;
|
|
ireq_64bit.app_id = data->client.app_id;
|
|
ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
|
|
(uintptr_t)req->req_ptr);
|
|
@@ -5632,17 +5809,19 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
|
|
ireq_64bit.resp_ptr, ireq_64bit.resp_len);
|
|
return -EFAULT;
|
|
}
|
|
+ ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
|
|
+ ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
|
|
+ dmac_flush_range((void *)table,
|
|
+ (void *)table + SGLISTINFO_TABLE_SIZE);
|
|
cmd_buf = (void *)&ireq_64bit;
|
|
cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
|
|
}
|
|
+ if (qseecom.whitelist_support == true
|
|
+ && cmd_id == QSEOS_TEE_OPEN_SESSION)
|
|
+ *(uint32_t *)cmd_buf = QSEOS_TEE_OPEN_SESSION_WHITELIST;
|
|
+ else
|
|
+ *(uint32_t *)cmd_buf = cmd_id;
|
|
|
|
- if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
|
|
- (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
|
|
- ret = __qseecom_update_qteec_req_buf(
|
|
- (struct qseecom_qteec_modfd_req *)req, data, false);
|
|
- if (ret)
|
|
- return ret;
|
|
- }
|
|
reqd_len_sb_in = req->req_len + req->resp_len;
|
|
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
|
|
data->client.sb_virt,
|
|
@@ -5740,6 +5919,9 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
|
|
uint32_t reqd_len_sb_in = 0;
|
|
void *cmd_buf = NULL;
|
|
size_t cmd_len;
|
|
+ struct sglist_info *table = data->sglistinfo_ptr;
|
|
+ void *req_ptr = NULL;
|
|
+ void *resp_ptr = NULL;
|
|
|
|
ret = copy_from_user(&req, argp,
|
|
sizeof(struct qseecom_qteec_modfd_req));
|
|
@@ -5751,6 +5933,8 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
|
|
(struct qseecom_qteec_req *)(&req));
|
|
if (ret)
|
|
return ret;
|
|
+ req_ptr = req.req_ptr;
|
|
+ resp_ptr = req.resp_ptr;
|
|
|
|
/* find app_id & img_name from list */
|
|
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
|
|
@@ -5771,45 +5955,56 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
|
|
return -ENOENT;
|
|
}
|
|
|
|
+ /* validate offsets */
|
|
+ for (i = 0; i < MAX_ION_FD; i++) {
|
|
+ if (req.ifd_data[i].fd) {
|
|
+ if (req.ifd_data[i].cmd_buf_offset >= req.req_len)
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+ req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
|
|
+ (uintptr_t)req.req_ptr);
|
|
+ req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
|
|
+ (uintptr_t)req.resp_ptr);
|
|
+ ret = __qseecom_update_qteec_req_buf(&req, data, false);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
if (qseecom.qsee_version < QSEE_VERSION_40) {
|
|
- ireq.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
|
|
ireq.app_id = data->client.app_id;
|
|
ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
|
|
- (uintptr_t)req.req_ptr);
|
|
+ (uintptr_t)req_ptr);
|
|
ireq.req_len = req.req_len;
|
|
ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
|
|
- (uintptr_t)req.resp_ptr);
|
|
+ (uintptr_t)resp_ptr);
|
|
ireq.resp_len = req.resp_len;
|
|
cmd_buf = (void *)&ireq;
|
|
cmd_len = sizeof(struct qseecom_qteec_ireq);
|
|
+ ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
|
|
+ ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
|
|
+ dmac_flush_range((void *)table,
|
|
+ (void *)table + SGLISTINFO_TABLE_SIZE);
|
|
} else {
|
|
- ireq_64bit.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
|
|
ireq_64bit.app_id = data->client.app_id;
|
|
ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
|
|
- (uintptr_t)req.req_ptr);
|
|
+ (uintptr_t)req_ptr);
|
|
ireq_64bit.req_len = req.req_len;
|
|
ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
|
|
- (uintptr_t)req.resp_ptr);
|
|
+ (uintptr_t)resp_ptr);
|
|
ireq_64bit.resp_len = req.resp_len;
|
|
cmd_buf = (void *)&ireq_64bit;
|
|
cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
|
|
+ ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
|
|
+ ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
|
|
+ dmac_flush_range((void *)table,
|
|
+ (void *)table + SGLISTINFO_TABLE_SIZE);
|
|
}
|
|
reqd_len_sb_in = req.req_len + req.resp_len;
|
|
+ if (qseecom.whitelist_support == true)
|
|
+ *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND_WHITELIST;
|
|
+ else
|
|
+ *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND;
|
|
|
|
- /* validate offsets */
|
|
- for (i = 0; i < MAX_ION_FD; i++) {
|
|
- if (req.ifd_data[i].fd) {
|
|
- if (req.ifd_data[i].cmd_buf_offset >= req.req_len)
|
|
- return -EINVAL;
|
|
- }
|
|
- }
|
|
- req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
|
|
- (uintptr_t)req.req_ptr);
|
|
- req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
|
|
- (uintptr_t)req.resp_ptr);
|
|
- ret = __qseecom_update_qteec_req_buf(&req, data, false);
|
|
- if (ret)
|
|
- return ret;
|
|
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
|
|
data->client.sb_virt,
|
|
reqd_len_sb_in,
|
|
@@ -5872,6 +6067,15 @@ static int qseecom_qteec_request_cancellation(struct qseecom_dev_handle *data,
|
|
return ret;
|
|
}
|
|
|
|
+static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data)
|
|
+{
|
|
+ if (data->sglist_cnt) {
|
|
+ memset(data->sglistinfo_ptr, 0,
|
|
+ SGLISTINFO_TABLE_SIZE);
|
|
+ data->sglist_cnt = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
|
{
|
|
int ret = 0;
|
|
@@ -6047,6 +6251,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
|
mutex_unlock(&app_access_lock);
|
|
if (ret)
|
|
pr_err("failed qseecom_send_cmd: %d\n", ret);
|
|
+ __qseecom_clean_data_sglistinfo(data);
|
|
break;
|
|
}
|
|
case QSEECOM_IOCTL_RECEIVE_REQ: {
|
|
@@ -6439,6 +6644,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
|
mutex_unlock(&app_access_lock);
|
|
if (ret)
|
|
pr_err("failed open_session_cmd: %d\n", ret);
|
|
+ __qseecom_clean_data_sglistinfo(data);
|
|
break;
|
|
}
|
|
case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ: {
|
|
@@ -6487,6 +6693,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
|
mutex_unlock(&app_access_lock);
|
|
if (ret)
|
|
pr_err("failed Invoke cmd: %d\n", ret);
|
|
+ __qseecom_clean_data_sglistinfo(data);
|
|
break;
|
|
}
|
|
case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ: {
|
|
@@ -6539,6 +6746,9 @@ static int qseecom_open(struct inode *inode, struct file *file)
|
|
init_waitqueue_head(&data->abort_wq);
|
|
atomic_set(&data->ioctl_count, 0);
|
|
|
|
+ data->sglistinfo_ptr = kzalloc(SGLISTINFO_TABLE_SIZE, GFP_KERNEL);
|
|
+ if (!(data->sglistinfo_ptr))
|
|
+ return -ENOMEM;
|
|
return ret;
|
|
}
|
|
|
|
@@ -6591,6 +6801,7 @@ static int qseecom_release(struct inode *inode, struct file *file)
|
|
if (data->perf_enabled == true)
|
|
qsee_disable_clock_vote(data, CLK_DFAB);
|
|
}
|
|
+ kfree(data->sglistinfo_ptr);
|
|
kfree(data);
|
|
|
|
return ret;
|
|
@@ -6731,6 +6942,74 @@ static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
|
|
qclk->instance = CLK_INVALID;
|
|
}
|
|
|
|
+/*
|
|
+ * Check if whitelist feature is supported by making a test scm_call
|
|
+ * to send a whitelist command to an invalid app ID 0
|
|
+ */
|
|
+static int qseecom_check_whitelist_feature(void)
|
|
+{
|
|
+ struct qseecom_client_send_data_ireq send_data_req = {0};
|
|
+ struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0};
|
|
+ struct qseecom_command_scm_resp resp;
|
|
+ uint32_t buf_size = 128;
|
|
+ void *buf = NULL;
|
|
+ void *cmd_buf = NULL;
|
|
+ size_t cmd_len;
|
|
+ int ret = 0;
|
|
+ phys_addr_t pa;
|
|
+
|
|
+ buf = kzalloc(buf_size, GFP_KERNEL);
|
|
+ if (!buf)
|
|
+ return -ENOMEM;
|
|
+ pa = virt_to_phys(buf);
|
|
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
|
|
+ send_data_req.qsee_cmd_id =
|
|
+ QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
|
|
+ send_data_req.app_id = 0;
|
|
+ send_data_req.req_ptr = (uint32_t)pa;
|
|
+ send_data_req.req_len = buf_size;
|
|
+ send_data_req.rsp_ptr = (uint32_t)pa;
|
|
+ send_data_req.rsp_len = buf_size;
|
|
+ send_data_req.sglistinfo_ptr = (uint32_t)pa;
|
|
+ send_data_req.sglistinfo_len = buf_size;
|
|
+ cmd_buf = (void *)&send_data_req;
|
|
+ cmd_len = sizeof(struct qseecom_client_send_data_ireq);
|
|
+ } else {
|
|
+ send_data_req_64bit.qsee_cmd_id =
|
|
+ QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
|
|
+ send_data_req_64bit.app_id = 0;
|
|
+ send_data_req_64bit.req_ptr = (uint64_t)pa;
|
|
+ send_data_req_64bit.req_len = buf_size;
|
|
+ send_data_req_64bit.rsp_ptr = (uint64_t)pa;
|
|
+ send_data_req_64bit.rsp_len = buf_size;
|
|
+ send_data_req_64bit.sglistinfo_ptr = (uint64_t)pa;
|
|
+ send_data_req_64bit.sglistinfo_len = buf_size;
|
|
+ cmd_buf = (void *)&send_data_req_64bit;
|
|
+ cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
|
|
+ }
|
|
+ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
|
|
+ cmd_buf, cmd_len,
|
|
+ &resp, sizeof(resp));
|
|
+/*
|
|
+ * If this cmd exists and whitelist is supported, scm_call return -2 (scm
|
|
+ * driver remap it to -EINVAL) and resp.result 0xFFFFFFED(-19); Otherwise,
|
|
+ * scm_call return -1 (remap to -EIO).
|
|
+ */
|
|
+ if (ret == -EIO) {
|
|
+ qseecom.whitelist_support = false;
|
|
+ ret = 0;
|
|
+ } else if (ret == -EINVAL &&
|
|
+ resp.result == QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD) {
|
|
+ qseecom.whitelist_support = true;
|
|
+ ret = 0;
|
|
+ } else {
|
|
+ pr_err("Failed to check whitelist: ret = %d, result = 0x%x\n",
|
|
+ ret, resp.result);
|
|
+ }
|
|
+ kfree(buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static int qseecom_probe(struct platform_device *pdev)
|
|
{
|
|
int rc;
|
|
@@ -6762,6 +7041,7 @@ static int qseecom_probe(struct platform_device *pdev)
|
|
|
|
qseecom.app_block_ref_cnt = 0;
|
|
init_waitqueue_head(&qseecom.app_block_wq);
|
|
+ qseecom.whitelist_support = true;
|
|
|
|
rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
|
|
if (rc < 0) {
|
|
@@ -7056,6 +7336,14 @@ static int qseecom_probe(struct platform_device *pdev)
|
|
qseecom.qsee_perf_client = msm_bus_scale_register_client(
|
|
qseecom_platform_support);
|
|
|
|
+ rc = qseecom_check_whitelist_feature();
|
|
+ if (rc) {
|
|
+ rc = -EINVAL;
|
|
+ goto exit_destroy_ion_client;
|
|
+ }
|
|
+ pr_warn("qseecom.whitelist_support = %d\n",
|
|
+ qseecom.whitelist_support);
|
|
+
|
|
if (!qseecom.qsee_perf_client)
|
|
pr_err("Unable to register bus client\n");
|
|
return 0;
|
|
diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h
|
|
index ad135e8..50b10f9 100644
|
|
--- a/include/soc/qcom/qseecomi.h
|
|
+++ b/include/soc/qcom/qseecomi.h
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
|
|
+ * Copyright (c) 2013-2016, 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
|
|
@@ -18,6 +18,7 @@
|
|
|
|
#define QSEECOM_KEY_ID_SIZE 32
|
|
|
|
+#define QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD -19 /*0xFFFFFFED*/
|
|
#define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63
|
|
#define QSEOS_RESULT_FAIL_KS_OP -64
|
|
#define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65
|
|
@@ -74,6 +75,9 @@ enum qseecom_qceos_cmd_id {
|
|
QSEOS_FSM_IKE_CMD_SIGN = 0x200,
|
|
QSEOS_FSM_IKE_CMD_PROV_KEY = 0x201,
|
|
QSEOS_FSM_IKE_CMD_ENCRYPT_PRIVATE_KEY = 0x202,
|
|
+ QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST = 0x1C,
|
|
+ QSEOS_TEE_OPEN_SESSION_WHITELIST = 0x1D,
|
|
+ QSEOS_TEE_INVOKE_COMMAND_WHITELIST = 0x1E,
|
|
QSEOS_FSM_OEM_FUSE_WRITE_ROW = 0x301,
|
|
QSEOS_FSM_OEM_FUSE_READ_ROW = 0x302,
|
|
QSEOS_CMD_MAX = 0xEFFFFFFF
|
|
@@ -175,6 +179,8 @@ __packed struct qseecom_client_send_data_ireq {
|
|
uint32_t req_len;
|
|
uint32_t rsp_ptr;/* First 4 bytes should be the return status */
|
|
uint32_t rsp_len;
|
|
+ uint32_t sglistinfo_ptr;
|
|
+ uint32_t sglistinfo_len;
|
|
};
|
|
|
|
__packed struct qseecom_client_send_data_64bit_ireq {
|
|
@@ -184,6 +190,8 @@ __packed struct qseecom_client_send_data_64bit_ireq {
|
|
uint32_t req_len;
|
|
uint64_t rsp_ptr;
|
|
uint32_t rsp_len;
|
|
+ uint64_t sglistinfo_ptr;
|
|
+ uint32_t sglistinfo_len;
|
|
};
|
|
|
|
__packed struct qseecom_reg_log_buf_ireq {
|
|
@@ -286,6 +294,8 @@ __packed struct qseecom_qteec_ireq {
|
|
uint32_t req_len;
|
|
uint32_t resp_ptr;
|
|
uint32_t resp_len;
|
|
+ uint32_t sglistinfo_ptr;
|
|
+ uint32_t sglistinfo_len;
|
|
};
|
|
|
|
__packed struct qseecom_qteec_64bit_ireq {
|
|
@@ -295,6 +305,8 @@ __packed struct qseecom_qteec_64bit_ireq {
|
|
uint32_t req_len;
|
|
uint64_t resp_ptr;
|
|
uint32_t resp_len;
|
|
+ uint64_t sglistinfo_ptr;
|
|
+ uint32_t sglistinfo_len;
|
|
};
|
|
|
|
__packed struct qseecom_client_send_fsm_key_req {
|
|
@@ -634,4 +646,37 @@ __packed struct qseecom_client_send_fsm_key_req {
|
|
#define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID \
|
|
TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
|
|
|
|
+#define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID \
|
|
+ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \
|
|
+ TZ_SVC_APP_ID_PLACEHOLDER, 0x06)
|
|
+
|
|
+#define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID \
|
|
+ TZ_SYSCALL_CREATE_PARAM_ID_7( \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL)
|
|
+
|
|
+#define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID \
|
|
+ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \
|
|
+ TZ_SVC_APP_ID_PLACEHOLDER, 0x07)
|
|
+
|
|
+#define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID \
|
|
+ TZ_SYSCALL_CREATE_PARAM_ID_7( \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL)
|
|
+
|
|
+#define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID \
|
|
+ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \
|
|
+ TZ_SVC_APP_ID_PLACEHOLDER, 0x09)
|
|
+
|
|
+#define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID \
|
|
+ TZ_SYSCALL_CREATE_PARAM_ID_7( \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
|
|
+ TZ_SYSCALL_PARAM_TYPE_VAL)
|
|
+
|
|
#endif /* __QSEECOMI_H_ */
|
|
--
|
|
cgit v1.1
|
|
|