Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ad55e64 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "qseecom: improve secure app session management"

parents 9fc5b27c 6ec904fb
Loading
Loading
Loading
Loading
+103 −30
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ struct qseecom_registered_app_list {
	struct list_head                 list;
	u32  app_id;
	u32  ref_cnt;
	char app_name[MAX_APP_NAME_SIZE];
};

struct qseecom_registered_kclient_list {
@@ -191,6 +192,7 @@ struct qseecom_client_handle {
	unsigned long user_virt_sb_base;
	size_t sb_length;
	struct ion_handle *ihandle;		/* Retrieve phy addr */
	char app_name[MAX_APP_NAME_SIZE];
};

struct qseecom_listener_handle {
@@ -654,7 +656,6 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
		return -EFAULT;

	data->listener.id = 0;
	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;
@@ -1308,7 +1309,9 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
		}
		entry->app_id = app_id;
		entry->ref_cnt = 1;

		memset((void *)entry->app_name, 0, MAX_APP_NAME_SIZE);
		memcpy((void *)entry->app_name,
			(void *)load_img_req.img_name, MAX_APP_NAME_SIZE);
		/* Deallocate the handle */
		if (!IS_ERR_OR_NULL(ihandle))
			ion_free(qseecom.ion_clnt, ihandle);
@@ -1322,6 +1325,9 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
		(char *)(load_img_req.img_name));
	}
	data->client.app_id = app_id;
	memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
	memcpy((void *)data->client.app_name,
		(void *)load_img_req.img_name, MAX_APP_NAME_SIZE);
	load_img_req.app_id = app_id;
	if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
		pr_err("copy_to_user failed\n");
@@ -1366,44 +1372,59 @@ static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
	return ret;
}

static int qseecom_unload_app(struct qseecom_dev_handle *data)
static int qseecom_unload_app(struct qseecom_dev_handle *data,
				bool app_crash)
{
	unsigned long flags;
	unsigned long flags1;
	int ret = 0;
	struct qseecom_command_scm_resp resp;
	struct qseecom_registered_app_list *ptr_app;
	struct qseecom_registered_app_list *ptr_app = NULL;
	bool unload = false;
	bool found_app = false;
	bool found_dead_app = false;

	if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
		pr_warn("Do not unload keymaster app from tz\n");
		return 0;
	}

	if (data->client.app_id > 0) {
		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
		list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
									list) {
			if (ptr_app->app_id == data->client.app_id) {
				if (!memcmp((void *)ptr_app->app_name,
					(void *)data->client.app_name,
					strlen(data->client.app_name))) {
					found_app = true;
				if (ptr_app->ref_cnt == 1) {
					if (app_crash || ptr_app->ref_cnt == 1)
						unload = true;
					break;
				} else {
					ptr_app->ref_cnt--;
					pr_debug("Can't unload app(%d) inuse\n",
							ptr_app->app_id);
					found_dead_app = true;
					break;
				}
			}
		}
		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
								flags);
		if (found_app == false) {
			pr_err("Cannot find app with id = %d\n",
						data->client.app_id);
		if (found_app == false && found_dead_app == false) {
			pr_err("Cannot find app with id = %d (%s)\n",
				data->client.app_id,
				(char *)data->client.app_name);
			return -EINVAL;
		}
	}

	if (found_dead_app) {
		pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
			(char *)data->client.app_name);
		__qseecom_cleanup_app(data);
	}

	if (unload) {
		struct qseecom_unload_app_ireq req;

		/* Populate the structure for sending scm call to load image */
		req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
		req.app_id = data->client.app_id;
@@ -1419,14 +1440,15 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data)
		} else {
			pr_warn("App id %d now unloaded\n", req.app_id);
		}

		if (resp.result == QSEOS_RESULT_FAILURE) {
			pr_err("app (%d) unload_failed!!\n",
					data->client.app_id);
			return -EFAULT;
		}
		if (resp.result == QSEOS_RESULT_SUCCESS)
			pr_debug("App (%d) is unloaded!!\n",
					data->client.app_id);
		__qseecom_cleanup_app(data);
		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
		list_del(&ptr_app->list);
		kzfree(ptr_app);
		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
								flags);

		if (resp.result == QSEOS_RESULT_INCOMPLETE) {
			ret = __qseecom_process_incomplete_cmd(data, &resp);
			if (ret) {
@@ -1436,6 +1458,29 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data)
			}
		}
	}

	if (found_app) {
		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
		if (app_crash) {
			ptr_app->ref_cnt = 0;
			pr_debug("app_crash: ref_count = 0\n");
		} else {
			if (ptr_app->ref_cnt == 1) {
				ptr_app->ref_cnt = 0;
				pr_debug("ref_count set to 0\n");
			} else {
				ptr_app->ref_cnt--;
				pr_debug("Can't unload app(%d) inuse\n",
					ptr_app->app_id);
			}
		}
		if (unload) {
			list_del(&ptr_app->list);
			kzfree(ptr_app);
		}
		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
								flags1);
	}
	qseecom_unmap_ion_allocated_memory(data);
	data->released = true;
	return ret;
@@ -1724,6 +1769,10 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
	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) {
		pr_err("cmd buffer or response buffer is null\n");
@@ -1771,6 +1820,27 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
		return -EINVAL;
	}

	/* 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,
							list) {
		name_len = min(strlen(data->client.app_name),
				strlen(ptr_app->app_name));
		if ((ptr_app->app_id == data->client.app_id) &&
			 (!memcmp((void *)ptr_app->app_name,
				(void *)data->client.app_name, name_len))) {
			found_app = true;
			break;
		}
	}
	spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags);

	if (!found_app) {
		pr_err("app_id %d (%s) is not found\n", data->client.app_id,
			(char *)data->client.app_name);
		return -EINVAL;
	}

	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,
@@ -2637,7 +2707,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
	if (!found_handle)
		pr_err("Unable to find the handle, exiting\n");
	else
		ret = qseecom_unload_app(data);
		ret = qseecom_unload_app(data, false);

	if (qseecom.support_bus_scaling) {
		mutex_lock(&qsee_bw_mutex);
@@ -3302,7 +3372,9 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
				&qseecom.registered_app_list_lock, flags);
		data->client.app_id = ret;
		query_req.app_id = ret;

		memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
		memcpy((void *)data->client.app_name,
				(void *)query_req.app_name, MAX_APP_NAME_SIZE);
		if (copy_to_user(argp, &query_req, sizeof(query_req))) {
			pr_err("copy_to_user failed\n");
			return -EFAULT;
@@ -4279,7 +4351,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
		pr_debug("UNLOAD_APP: qseecom_addr = 0x%p\n", data);
		mutex_lock(&app_access_lock);
		atomic_inc(&data->ioctl_count);
		ret = qseecom_unload_app(data);
		ret = qseecom_unload_app(data, false);
		atomic_dec(&data->ioctl_count);
		mutex_unlock(&app_access_lock);
		if (ret)
@@ -4638,6 +4710,7 @@ static int qseecom_open(struct inode *inode, struct file *file)
	data->abort = 0;
	data->type = QSEECOM_GENERIC;
	data->released = false;
	memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
	data->mode = INACTIVE;
	init_waitqueue_head(&data->abort_wq);
	atomic_set(&data->ioctl_count, 0);
@@ -4658,13 +4731,13 @@ static int qseecom_release(struct inode *inode, struct file *file)
			ret = qseecom_unregister_listener(data);
			break;
		case QSEECOM_CLIENT_APP:
			ret = qseecom_unload_app(data);
			ret = qseecom_unload_app(data, true);
			break;
		case QSEECOM_SECURE_SERVICE:
		case QSEECOM_GENERIC:
			ret = qseecom_unmap_ion_allocated_memory(data);
			if (ret)
				pr_err("Close failed\n");
				pr_err("Ion Unmap failed\n");
			break;
		case QSEECOM_UNAVAILABLE_CLIENT_APP:
			break;
@@ -5139,7 +5212,7 @@ static int qseecom_remove(struct platform_device *pdev)
			goto exit_free_kc_handle;

		list_del(&kclient->list);
		ret = qseecom_unload_app(kclient->handle->dev);
		ret = qseecom_unload_app(kclient->handle->dev, false);
		if (!ret) {
			kzfree(kclient->handle->dev);
			kzfree(kclient->handle);