DivestOS/Patches/Linux_CVEs/CVE-2016-5349/0.patch

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