summaryrefslogtreecommitdiff
path: root/security/tlk_driver/ote_device.c
diff options
context:
space:
mode:
authorChris Johnson <cwj@nvidia.com>2014-02-05 23:29:18 -0800
committerChris Johnson <cwj@nvidia.com>2014-02-07 19:00:37 -0800
commit89f9aa1d0a4d530e98f1f8e32e562cdb0b0ea6fb (patch)
tree6cc91080cbd5ea51ffbf2c89eb66a4d665ec6c83 /security/tlk_driver/ote_device.c
parentd5fbff4d8458329ccdb22799eff0f3a18bc3c527 (diff)
security: tlk_driver: stage new interface structs
The current structs passed between the client lib and kernel aren't sized to allow 64bit pointers to work. This code stages ioctls based on structs that can handle 32bit or 64bit references. Once the supporting TLK library and kernel changes are checked in, we'll flip over to using these code paths. Bug 1432005 Change-Id: I7fd1b479c6ddf436ea4e380607cbb5dcfce1b2c2 Signed-off-by: Chris Johnson <cwj@nvidia.com> Reviewed-on: http://git-master/r/364252 Reviewed-by: Scott Long <scottl@nvidia.com>
Diffstat (limited to 'security/tlk_driver/ote_device.c')
-rw-r--r--security/tlk_driver/ote_device.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/security/tlk_driver/ote_device.c b/security/tlk_driver/ote_device.c
index 03fa1acc2129..170f46c06e14 100644
--- a/security/tlk_driver/ote_device.c
+++ b/security/tlk_driver/ote_device.c
@@ -41,6 +41,7 @@ static int te_create_free_cmd_list(struct tlk_device *dev)
{
int cmd_desc_count, ret = 0;
struct te_cmd_req_desc *req_desc;
+ struct te_cmd_req_desc_compat *req_desc_compat;
int bitmap_size;
bool use_reqbuf;
@@ -80,6 +81,12 @@ static int te_create_free_cmd_list(struct tlk_device *dev)
goto error;
}
+ /* requests in the first page, params in the second */
+ dev->req_addr_compat = (struct te_request_compat *)
+ dev->req_param_buf;
+ dev->param_addr_compat = (struct te_oper_param_compat *)
+ (dev->req_param_buf + PAGE_SIZE);
+
/* alloc param bitmap allocator */
bitmap_size = BITS_TO_LONGS(TE_PARAM_MAX) * sizeof(long);
dev->param_bitmap = kzalloc(bitmap_size, GFP_KERNEL);
@@ -99,6 +106,25 @@ static int te_create_free_cmd_list(struct tlk_device *dev)
/* Add the cmd param descriptor to free list */
list_add_tail(&req_desc->list, &(dev->free_cmd_list));
}
+
+ for (cmd_desc_count = 0;
+ cmd_desc_count < TE_CMD_DESC_MAX_COMPAT; cmd_desc_count++) {
+
+ req_desc_compat = kzalloc(sizeof(struct te_cmd_req_desc_compat),
+ GFP_KERNEL);
+ if (req_desc_compat == NULL) {
+ pr_err("Failed to allocate cmd req descriptor\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+ req_desc_compat->req_addr =
+ dev->req_addr_compat + cmd_desc_count;
+ INIT_LIST_HEAD(&(req_desc_compat->list));
+
+ /* Add the cmd param descriptor to free list */
+ list_add_tail(&req_desc_compat->list, &(dev->free_cmd_list));
+ }
+
error:
return ret;
}
@@ -129,6 +155,32 @@ static void te_put_free_params(struct tlk_device *dev,
bitmap_release_region(dev->param_bitmap, idx, nbits);
}
+static struct te_oper_param_compat *
+ te_get_free_params_compat(struct tlk_device *dev, unsigned int nparams)
+{
+ struct te_oper_param_compat *params = NULL;
+ int idx, nbits;
+
+ if (nparams) {
+ nbits = get_count_order(nparams);
+ idx = bitmap_find_free_region(dev->param_bitmap,
+ TE_PARAM_MAX, nbits);
+ if (idx >= 0)
+ params = dev->param_addr_compat + idx;
+ }
+ return params;
+}
+
+static void te_put_free_params_compat(struct tlk_device *dev,
+ struct te_oper_param_compat *params, uint32_t nparams)
+{
+ int idx, nbits;
+
+ idx = (params - dev->param_addr_compat);
+ nbits = get_count_order(nparams);
+ bitmap_release_region(dev->param_bitmap, idx, nbits);
+}
+
static struct te_cmd_req_desc *te_get_free_cmd_desc(struct tlk_device *dev)
{
struct te_cmd_req_desc *cmd_desc = NULL;
@@ -159,6 +211,37 @@ static void te_put_used_cmd_desc(struct tlk_device *dev,
}
}
+static struct te_cmd_req_desc_compat *
+te_get_free_cmd_desc_compat(struct tlk_device *dev)
+{
+ struct te_cmd_req_desc_compat *cmd_desc = NULL;
+
+ if (!(list_empty(&(dev->free_cmd_list)))) {
+ cmd_desc = list_first_entry(&(dev->free_cmd_list),
+ struct te_cmd_req_desc_compat, list);
+ list_del(&(cmd_desc->list));
+ list_add_tail(&cmd_desc->list, &(dev->used_cmd_list));
+ }
+ return cmd_desc;
+}
+
+static void te_put_used_cmd_desc_compat(struct tlk_device *dev,
+ struct te_cmd_req_desc_compat *cmd_desc)
+{
+ struct te_cmd_req_desc_compat *param_desc, *tmp_param_desc;
+
+ if (cmd_desc) {
+ list_for_each_entry_safe(param_desc, tmp_param_desc,
+ &(dev->used_cmd_list), list) {
+ if (cmd_desc->req_addr == param_desc->req_addr) {
+ list_del(&param_desc->list);
+ list_add_tail(&param_desc->list,
+ &(dev->free_cmd_list));
+ }
+ }
+ }
+}
+
static void __attribute__((unused)) te_print_cmd_list(
struct tlk_device *dev, int used_list)
{
@@ -403,6 +486,209 @@ error:
return err;
}
+static int copy_params_from_user_compat(struct te_request_compat *req,
+ struct te_operation_compat *operation)
+{
+ struct te_oper_param_compat *param_array;
+ struct te_oper_param_compat *user_param;
+ uint32_t i;
+
+ if (operation->list_count == 0)
+ return 0;
+
+ param_array = (struct te_oper_param_compat *)(uintptr_t)req->params;
+ if (param_array == NULL) {
+ pr_err("param_array empty\n");
+ return 1;
+ }
+
+ user_param = (struct te_oper_param_compat *)(uintptr_t)
+ operation->list_head;
+ for (i = 0; i < operation->list_count && user_param != NULL; i++) {
+ if (copy_from_user(param_array + i, user_param,
+ sizeof(struct te_oper_param_compat))) {
+ pr_err("Failed to copy operation parameter:%d, %p, " \
+ "list_count: %d\n",
+ i, user_param, operation->list_count);
+ return 1;
+ }
+ user_param = (struct te_oper_param_compat *)(uintptr_t)
+ param_array[i].next_ptr_user;
+ }
+ return 0;
+}
+
+static int copy_params_to_user_compat(struct te_request_compat *req,
+ struct te_operation_compat *operation)
+{
+ struct te_oper_param_compat *param_array;
+ struct te_oper_param_compat *user_param;
+ uint32_t i;
+
+ if (operation->list_count == 0)
+ return 0;
+
+ param_array =
+ (struct te_oper_param_compat *)(uintptr_t)req->params;
+ if (param_array == NULL) {
+ pr_err("param_array empty\n");
+ return 1;
+ }
+
+ user_param =
+ (struct te_oper_param_compat *)(uintptr_t)operation->list_head;
+ for (i = 0; i < req->params_size; i++) {
+ if (copy_to_user(user_param, param_array + i,
+ sizeof(struct te_oper_param_compat))) {
+ pr_err("Failed to copy back parameter:%d %p\n", i,
+ user_param);
+ return 1;
+ }
+ user_param = (struct te_oper_param_compat *)(uintptr_t)
+ param_array[i].next_ptr_user;
+ }
+ return 0;
+}
+
+static long te_handle_trustedapp_ioctl_compat(struct file *file,
+ unsigned int ioctl_num, unsigned long ioctl_param)
+{
+ long err = 0;
+ union te_cmd_compat cmd_compat;
+ struct te_operation_compat *operation = NULL;
+ struct te_oper_param_compat *params = NULL;
+ struct te_request_compat *request;
+ void __user *ptr_user_answer = NULL;
+ struct te_answer answer;
+ struct te_cmd_req_desc_compat *cmd_desc = NULL;
+ struct tlk_context *context = file->private_data;
+ struct tlk_device *dev = context->dev;
+
+ if (copy_from_user(&cmd_compat, (void __user *)ioctl_param,
+ sizeof(union te_cmd_compat))) {
+ pr_err("Failed to copy command request\n");
+ err = -EFAULT;
+ goto error;
+ }
+
+ memset(&answer, 0, sizeof(struct te_answer));
+
+ switch (ioctl_num) {
+ case TE_IOCTL_OPEN_CLIENT_SESSION_COMPAT:
+ operation = &cmd_compat.opensession.operation;
+ ptr_user_answer = (void *)(uintptr_t)
+ cmd_compat.opensession.answer;
+
+ cmd_desc = te_get_free_cmd_desc_compat(dev);
+ params = te_get_free_params_compat(dev, operation->list_count);
+
+ if (!cmd_desc || (operation->list_count && !params)) {
+ SET_ANSWER(answer,
+ OTE_ERROR_OUT_OF_MEMORY,
+ OTE_RESULT_ORIGIN_COMMS);
+ pr_err("failed to get cmd_desc/params\n");
+ goto error;
+ }
+
+ request = cmd_desc->req_addr;
+ memset(request, 0, sizeof(struct te_request_compat));
+
+ request->params = (uintptr_t)params;
+ request->params_size = operation->list_count;
+
+ if (copy_params_from_user_compat(request, operation)) {
+ err = -EFAULT;
+ pr_info("failed to copy params from user\n");
+ goto error;
+ }
+
+ te_open_session_compat(&cmd_compat.opensession,
+ request, context);
+
+ SET_ANSWER(answer, request->result, request->result_origin);
+ answer.session_id = request->session_id;
+ break;
+
+ case TE_IOCTL_CLOSE_CLIENT_SESSION_COMPAT:
+ ptr_user_answer = (void *)(uintptr_t)
+ cmd_compat.closesession.answer;
+ cmd_desc = te_get_free_cmd_desc_compat(dev);
+ if (!cmd_desc) {
+ SET_ANSWER(answer,
+ OTE_ERROR_OUT_OF_MEMORY,
+ OTE_RESULT_ORIGIN_COMMS);
+ pr_err("failed to get cmd_desc\n");
+ goto error;
+ }
+
+ request = cmd_desc->req_addr;
+ memset(request, 0, sizeof(struct te_request_compat));
+
+ /* close session cannot fail */
+ te_close_session_compat(&cmd_compat.closesession,
+ request, context);
+ break;
+
+ case TE_IOCTL_LAUNCH_OPERATION_COMPAT:
+ operation = &cmd_compat.launchop.operation;
+ ptr_user_answer = (void *)(uintptr_t)cmd_compat.launchop.answer;
+
+ cmd_desc = te_get_free_cmd_desc_compat(dev);
+ params = te_get_free_params_compat(dev, operation->list_count);
+
+ if (!cmd_desc || (operation->list_count && !params)) {
+ SET_ANSWER(answer,
+ OTE_ERROR_OUT_OF_MEMORY,
+ OTE_RESULT_ORIGIN_COMMS);
+ pr_err("failed to get cmd_desc/params\n");
+ goto error;
+ }
+
+ request = cmd_desc->req_addr;
+ memset(request, 0, sizeof(struct te_request_compat));
+
+ request->params = (uintptr_t)params;
+ request->params_size = operation->list_count;
+
+ if (copy_params_from_user_compat(request, operation)) {
+ err = -EFAULT;
+ pr_info("failed to copy params from user\n");
+ goto error;
+ }
+
+ te_launch_operation_compat(&cmd_compat.launchop,
+ request, context);
+
+ SET_ANSWER(answer, request->result, request->result_origin);
+ break;
+
+ default:
+ pr_err("Invalid IOCTL Cmd\n");
+ err = -EINVAL;
+ goto error;
+ }
+ if (ptr_user_answer && !err) {
+ if (copy_to_user(ptr_user_answer, &answer,
+ sizeof(struct te_answer))) {
+ pr_err("Failed to copy answer\n");
+ err = -EFAULT;
+ }
+ }
+ if (request->params && !err) {
+ if (copy_params_to_user_compat(request, operation)) {
+ pr_err("Failed to copy return params\n");
+ err = -EFAULT;
+ }
+ }
+
+error:
+ if (cmd_desc)
+ te_put_used_cmd_desc_compat(dev, cmd_desc);
+ if (params)
+ te_put_free_params_compat(dev, params, operation->list_count);
+ return err;
+}
+
static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num,
unsigned long ioctl_param)
{
@@ -417,6 +703,15 @@ static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num,
mutex_unlock(&smc_lock);
break;
+ case TE_IOCTL_OPEN_CLIENT_SESSION_COMPAT:
+ case TE_IOCTL_CLOSE_CLIENT_SESSION_COMPAT:
+ case TE_IOCTL_LAUNCH_OPERATION_COMPAT:
+ mutex_lock(&smc_lock);
+ err = te_handle_trustedapp_ioctl_compat(file, ioctl_num,
+ ioctl_param);
+ mutex_unlock(&smc_lock);
+ break;
+
case TE_IOCTL_FILE_NEW_REQ:
case TE_IOCTL_FILE_FILL_BUF:
case TE_IOCTL_FILE_REQ_COMPLETE:
@@ -446,6 +741,9 @@ static const struct file_operations tlk_device_fops = {
.open = tlk_device_open,
.release = tlk_device_release,
.unlocked_ioctl = tlk_device_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = tlk_device_ioctl,
+#endif
};
struct miscdevice tlk_misc_device = {