qseecom: Fix QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ kernel crash
Fixes the kernel crash occuring with IOCTL_UNLOAD_EXTERNAL_ELF_REQ
ioctl by adding unavailable client type to qseecom_client_handle_type
enum, which is required in the driver during qseecom_release().
Change-Id: I73b817255149ffc4a808852feb2954a0ba3c317f
CRs-fixed: 508253
Signed-off-by: AnilKumar Chimata <anilc@codeaurora.org>
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index ac67c9d..aec7bc5 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -136,6 +136,14 @@
unsigned int data;
};
+enum qseecom_client_handle_type {
+ QSEECOM_CLIENT_APP = 1,
+ QSEECOM_LISTENER_SERVICE,
+ QSEECOM_SECURE_SERVICE,
+ QSEECOM_GENERIC,
+ QSEECOM_UNAVAILABLE_CLIENT_APP,
+};
+
static struct class *driver_class;
static dev_t qseecom_device_no;
static struct cdev qseecom_cdev;
@@ -210,7 +218,7 @@
static struct qseecom_control qseecom;
struct qseecom_dev_handle {
- bool service;
+ enum qseecom_client_handle_type type;
union {
struct qseecom_client_handle client;
struct qseecom_listener_handle listener;
@@ -367,7 +375,7 @@
return ret;
}
data->listener.id = 0;
- data->service = true;
+ data->type = QSEECOM_LISTENER_SERVICE;
if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
pr_err("Service is not unique and is already registered\n");
data->released = true;
@@ -803,6 +811,17 @@
return 1;
}
+static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
+{
+ int ret = 0;
+ if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+ ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+ ion_free(qseecom.ion_clnt, data->client.ihandle);
+ data->client.ihandle = NULL;
+ }
+ return ret;
+}
+
static int qseecom_unload_app(struct qseecom_dev_handle *data)
{
unsigned long flags;
@@ -885,11 +904,7 @@
}
}
}
- if (!IS_ERR_OR_NULL(data->client.ihandle)) {
- ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
- ion_free(qseecom.ion_clnt, data->client.ihandle);
- data->client.ihandle = NULL;
- }
+ qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
}
@@ -1430,7 +1445,7 @@
return -ENOMEM;
}
data->abort = 0;
- data->service = false;
+ data->type = QSEECOM_CLIENT_APP;
data->released = false;
data->client.app_id = ret;
data->client.sb_length = size;
@@ -1866,6 +1881,9 @@
struct qseecom_unload_app_ireq req;
struct cpumask mask;
+ /* unavailable client app */
+ data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
+
/* Populate the structure for sending scm call to unload image */
req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
@@ -2152,7 +2170,7 @@
}
file->private_data = data;
data->abort = 0;
- data->service = false;
+ data->type = QSEECOM_GENERIC;
data->released = false;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
@@ -2183,13 +2201,26 @@
if (data->released == false) {
pr_warn("data->released == false\n");
- if (data->service)
+ switch (data->type) {
+ case QSEECOM_LISTENER_SERVICE:
ret = qseecom_unregister_listener(data);
- else
+ break;
+ case QSEECOM_CLIENT_APP:
ret = qseecom_unload_app(data);
- if (ret) {
- pr_err("Close failed\n");
- return ret;
+ break;
+ case QSEECOM_SECURE_SERVICE:
+ ret = qseecom_unmap_ion_allocated_memory(data);
+ if (ret) {
+ pr_err("Close failed\n");
+ return ret;
+ }
+ break;
+ case QSEECOM_UNAVAILABLE_CLIENT_APP:
+ break;
+ default:
+ pr_err("Unsupported clnt_handle_type %d",
+ data->type);
+ break;
}
}
if (qseecom.qseos_version == QSEOS_VERSION_13) {