From a064a44e03158dbf655a866ba21f5d1baa2dee9e Mon Sep 17 00:00:00 2001
From: Dennis Cagle <d-cagle@codeaurora.org>
Date: Fri, 6 Jan 2017 15:28:20 -0800
Subject: [PATCH] QBT1000: copy qseecom handle to user when loading/unloading
 app

QBT1000 provides IOCTLs for loading and unloading a QSEE app.
In the input structure for these IOCTLs there is a pointer
to a qseecom handle which serves as an output parameter for
the IOCTLs. That is, the given handle (in client address space)
should be set to a valid handle value on load, and should be set
to 0 on unload.

The driver was missing a proper copy_to_user() call for this handle,
which sometimes resulted in unload not setting the handle to 0.

Bug: 32372915
Bug: 32370896
CRs-fixed: 1059327
Change-Id: I31f205afb1f9bf0b6243e3f20f54022525c93b28
Signed-off-by: Lior Barenboim <liorb@codeaurora.org>
Signed-off-by: Dennis Cagle <d-cagle@codeaurora.org>
---
 drivers/soc/qcom/qbt1000.c | 59 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 55 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index 101fcedd1f2c0..961800e2f963f 100755
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -772,6 +772,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	case QBT1000_LOAD_APP:
 	{
 		struct qbt1000_app app;
+		struct qseecom_handle *app_handle;
 
 		if (copy_from_user(&app, priv_arg,
 			sizeof(app)) != 0) {
@@ -782,8 +783,15 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 			goto end;
 		}
 
+		if (!app.app_handle) {
+			dev_err(drvdata->dev, "%s: LOAD app_handle is null\n",
+				__func__);
+			rc = -EINVAL;
+			goto end;
+		}
+
 		/* start the TZ app */
-		rc = qseecom_start_app(app.app_handle, app.name, app.size);
+		rc = qseecom_start_app(&app_handle, app.name, app.size);
 		if (rc == 0) {
 			g_app_buf_size = app.size;
 		} else {
@@ -792,36 +800,79 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 			goto end;
 		}
 
+		/* copy the app handle to user */
+		rc = copy_to_user((void __user *)app.app_handle, &app_handle,
+			sizeof(*app.app_handle));
+
+		if (rc != 0) {
+			dev_err(drvdata->dev,
+				"%s: Failed copy 2us LOAD rc:%d\n",
+				 __func__, rc);
+			rc = -ENOMEM;
+			goto end;
+		}
+
 		break;
 	}
 	case QBT1000_UNLOAD_APP:
 	{
 		struct qbt1000_app app;
+		struct qseecom_handle *app_handle;
 
 		if (copy_from_user(&app, priv_arg,
 			sizeof(app)) != 0) {
 			rc = -ENOMEM;
 			dev_err(drvdata->dev,
-				"%s: Failed copy from user space-LOAD\n",
+				"%s: Failed copy from user space-UNLOAD\n",
 				 __func__);
 			goto end;
 		}
 
-		/* if the app hasn't been loaded already, return err */
 		if (!app.app_handle) {
+			dev_err(drvdata->dev, "%s: UNLOAD app_handle is null\n",
+				__func__);
+			rc = -EINVAL;
+			goto end;
+		}
+
+		rc = copy_from_user(&app_handle, app.app_handle,
+			sizeof(app_handle));
+
+		if (rc != 0) {
+			dev_err(drvdata->dev,
+				"%s: Failed copy from user space-UNLOAD handle rc:%d\n",
+				 __func__, rc);
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		/* if the app hasn't been loaded already, return err */
+		if (!app_handle) {
 			dev_err(drvdata->dev, "%s: App not loaded\n",
 				__func__);
 			rc = -EINVAL;
 			goto end;
 		}
 
-		rc = qseecom_shutdown_app(app.app_handle);
+		rc = qseecom_shutdown_app(&app_handle);
 		if (rc != 0) {
 			dev_err(drvdata->dev, "%s: App failed to shutdown\n",
 				__func__);
 			goto end;
 		}
 
+		/* copy the app handle (should be null) to user */
+		rc = copy_to_user((void __user *)app.app_handle, &app_handle,
+			sizeof(*app.app_handle));
+
+		if (rc != 0) {
+			dev_err(drvdata->dev,
+				"%s: Failed copy 2us UNLOAD rc:%d\n",
+				 __func__, rc);
+			rc = -ENOMEM;
+			goto end;
+		}
+
 		break;
 	}
 	case QBT1000_SEND_TZCMD: