summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2013-04-18 12:32:05 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:17:06 -0700
commit4fbaffe1f604192741d71a38916a653c99f5853a (patch)
tree248b22d28507b788d49014c9824291e53738b709 /security
parentb5ffbaa76ff2a9fc2dcae047403cb583c54d37f7 (diff)
security: nv_tee_driver: file storage apis
- Add a new FS ioctl handler to service ioctls from the storage daemon. - Add read/write handler to help the secure world to get its data across to the storage daemon. - A read request with NULL input params will return the size of the file. The client then can allocate memory accordingly and proceed with the actual read. The general sequence of events from the daemon would be: - TEE_IOCTL_FILE_NEW_REQ to get the file name, size and type (read/write) - TEE_IOCTL_FILE_FILL_BUF to get data in case of writes - TEE_IOCTL_FILE_REQ_COMPLETE to signal completion to the secure world Change-Id: I52450af8d79164338773c1575417a863978de3d6 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/220982 GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'security')
-rw-r--r--security/nv_tee_driver/Makefile2
-rw-r--r--security/nv_tee_driver/tee_client_api.h24
-rw-r--r--security/nv_tee_driver/tee_comms.c17
-rw-r--r--security/nv_tee_driver/tee_device.c32
-rw-r--r--security/nv_tee_driver/tee_fs.c235
-rw-r--r--security/nv_tee_driver/tee_protocol.h11
6 files changed, 312 insertions, 9 deletions
diff --git a/security/nv_tee_driver/Makefile b/security/nv_tee_driver/Makefile
index 96761c6bd50a..00b65f1eb0de 100644
--- a/security/nv_tee_driver/Makefile
+++ b/security/nv_tee_driver/Makefile
@@ -19,9 +19,11 @@
plus_sec := $(call as-instr,.arch_extension sec,+sec)
AFLAGS_tee_irq.o :=-Wa,-march=armv7-a$(plus_sec)
CFLAGS_tee_comms.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
+CFLAGS_tee_fs.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
nv_tee_driver-objs += tee_device.o
nv_tee_driver-objs += tee_comms.o
+nv_tee_driver-objs += tee_fs.o
nv_tee_driver-objs += tee_irq.o
obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += nv_tee_driver.o
diff --git a/security/nv_tee_driver/tee_client_api.h b/security/nv_tee_driver/tee_client_api.h
index d7b00e1f4516..0f0eed2275db 100644
--- a/security/nv_tee_driver/tee_client_api.h
+++ b/security/nv_tee_driver/tee_client_api.h
@@ -88,4 +88,28 @@ struct TEEC_UUID {
uint8_t clock_seq_and_node[8];
};
+#define TEEC_MAX_FILE_NAME_LEN 64
+
+typedef enum {
+ TEEC_FILE_REQ_READ = 0,
+ TEEC_FILE_REQ_WRITE = 1,
+ TEEC_FILE_REQ_DELETE = 2,
+ TEEC_FILE_REQ_SIZE = 3,
+} TEEC_FileReqType;
+
+typedef struct {
+ char name[TEEC_MAX_FILE_NAME_LEN];
+ TEEC_FileReqType type;
+ void *user_data_buf;
+ void *kern_data_buf;
+ unsigned long data_len;
+ unsigned long result;
+ int error;
+} TEEC_FileReq;
+
+struct tee_file_req_node {
+ struct list_head node;
+ TEEC_FileReq *req;
+};
+
#endif
diff --git a/security/nv_tee_driver/tee_comms.c b/security/nv_tee_driver/tee_comms.c
index e60f1fd485de..81013894028d 100644
--- a/security/nv_tee_driver/tee_comms.c
+++ b/security/nv_tee_driver/tee_comms.c
@@ -273,6 +273,7 @@ static void tee_unpin_temp_buffers(struct TEEC_Operation *oper,
static void do_smc(struct tee_request *request)
{
phys_addr_t smc_args = virt_to_phys(request);
+ unsigned long regs[15];
#ifdef CONFIG_SMP
long ret;
@@ -287,15 +288,17 @@ static void do_smc(struct tee_request *request)
#endif
asm volatile (
- "stmdb sp!, {r4-r12}\n"
- "mov r0, %0\n"
- "mov r1, %1\n"
+ "mov r0, %0 \n"
+ "stmia r0, {r4-r12} \n"
+ "mov r0, %1 \n"
+ "mov r1, %2 \n"
#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
+ ".arch_extension sec \n"
#endif
- "smc #0\n"
- "ldmia sp!, {r4-r12}\n"
- : : "r" (request->type), "r" (smc_args)
+ "smc #0 \n"
+ "mov r1, %0 \n"
+ "ldmia r1, {r4-r12} \n"
+ : : "r" (regs), "r" (request->type), "r" (smc_args)
: "r0", "r1"
);
diff --git a/security/nv_tee_driver/tee_device.c b/security/nv_tee_driver/tee_device.c
index 3015a12a9ee7..57a5f5fa0c3e 100644
--- a/security/nv_tee_driver/tee_device.c
+++ b/security/nv_tee_driver/tee_device.c
@@ -172,7 +172,7 @@ static int tee_device_release(struct inode *inode, struct file *file)
return 0;
}
-static long tee_device_ioctl(struct file *file, unsigned int ioctl_num,
+static long tee_handle_trustedapp_ioctl(struct file *file, unsigned int ioctl_num,
unsigned long ioctl_param)
{
long err = 0;
@@ -301,6 +301,36 @@ error:
return err;
}
+static long tee_device_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+{
+ int err;
+
+ switch (ioctl_num) {
+ case TEE_IOCTL_OPEN_CLIENT_SESSION:
+ case TEE_IOCTL_CLOSE_CLIENT_SESSION:
+ case TEE_IOCTL_REGISTER_MEMORY:
+ case TEE_IOCTL_RELEASE_SHARED_MEM:
+ case TEE_IOCTL_INVOKE_COMMAND:
+ err = tee_handle_trustedapp_ioctl(file, ioctl_num, ioctl_param);
+ break;
+
+ case TEE_IOCTL_FILE_NEW_REQ:
+ case TEE_IOCTL_FILE_FILL_BUF:
+ case TEE_IOCTL_FILE_REQ_COMPLETE:
+ err = tee_handle_fs_ioctl(file, ioctl_num, ioctl_param);
+ break;
+
+ default:
+ pr_err("%s: Invalid IOCTL (0x%lx) 0x%lx, %d\n", __func__,
+ ioctl_num, TEE_IOCTL_FILE_NEW_REQ,
+ sizeof(TEEC_FileReq));
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
/*
* tee_driver function definitions.
*/
diff --git a/security/nv_tee_driver/tee_fs.c b/security/nv_tee_driver/tee_fs.c
new file mode 100644
index 000000000000..192bc2d3c3c2
--- /dev/null
+++ b/security/nv_tee_driver/tee_fs.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+
+#include <asm/uaccess.h>
+
+#include "tee_protocol.h"
+
+#define TEE_SHMEM_FNAME_SZ SZ_64
+#define TEE_SHMEM_DATA_SZ SZ_128K
+
+struct tee_shmem {
+ char file_name[TEE_SHMEM_FNAME_SZ];
+ char file_data[TEE_SHMEM_DATA_SZ];
+};
+
+struct list_head req_list;
+DECLARE_COMPLETION(req_ready);
+DECLARE_COMPLETION(req_complete);
+static unsigned long secure_error;
+
+static void indicate_complete(unsigned long ret)
+{
+ asm volatile (
+ "mov r1, %0 \n"
+ "movw r0, #0x1FFF \n"
+ "movt r0, #0xFFFF \n"
+#ifdef REQUIRES_SEC
+ ".arch_extension sec \n"
+#endif
+ "smc #0 \n"
+ : : "r" (ret)
+ : "r0", "r1"
+ );
+}
+
+int tee_handle_fs_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+{
+ TEEC_FileReq new_req, *ptr_user_req = NULL;
+ struct tee_file_req_node *req_node;
+
+ switch (ioctl_num) {
+ case TEE_IOCTL_FILE_NEW_REQ: /* new request */
+
+ ptr_user_req = (TEEC_FileReq *)ioctl_param;
+
+ /* wait for a new request */
+ wait_for_completion(&req_ready);
+
+ /* dequeue new request from the secure world */
+ req_node = list_first_entry(&req_list, struct tee_file_req_node,
+ node);
+
+ /* populate request for the non-secure client */
+ if (req_node) {
+ if (copy_to_user(ptr_user_req, req_node->req,
+ sizeof(TEEC_FileReq))) {
+ pr_err("copy_to_user failed for new request\n");
+ return -EFAULT;
+ }
+
+ list_del(&req_node->node);
+ kfree(req_node);
+ } else {
+ pr_err("no request available\n");
+ return -ENOMEM;
+ }
+
+ break;
+
+ case TEE_IOCTL_FILE_FILL_BUF: /* pass data to be written to the file */
+
+ if (copy_from_user(&new_req, (void __user *)ioctl_param,
+ sizeof(TEEC_FileReq))) {
+ pr_err("copy_from_user failed for request\n");
+ return -EFAULT;
+ }
+
+ if (new_req.type != TEEC_FILE_REQ_WRITE)
+ return -EINVAL;
+
+ if (!new_req.kern_data_buf || !new_req.user_data_buf)
+ return -EINVAL;
+
+ if (copy_to_user(new_req.user_data_buf, new_req.kern_data_buf,
+ new_req.data_len)) {
+ pr_err("copy_to_user failed for fill buffer\n");
+ return -EFAULT;
+ }
+ break;
+
+ case TEE_IOCTL_FILE_REQ_COMPLETE: /* request complete */
+
+ if (copy_from_user(&new_req, (void __user *)ioctl_param,
+ sizeof(TEEC_FileReq))) {
+ pr_err("copy_from_user failed for request\n");
+ return -EFAULT;
+ }
+
+ if (new_req.type == TEEC_FILE_REQ_READ && !new_req.error) {
+ if (copy_from_user(new_req.kern_data_buf,
+ (void __user *)new_req.user_data_buf,
+ new_req.data_len)) {
+ pr_err("copy_from_user failed for request\n");
+ return -EFAULT;
+ }
+ }
+
+ /* get error code */
+ secure_error = (new_req.error) ? TEEC_ERROR_NO_DATA : new_req.result;
+
+ /* signal the producer */
+ complete(&req_complete);
+ break;
+ }
+
+ return 0;
+}
+
+static void _tee_fs_file_operation(const char *name, void *buf, int len,
+ TEEC_FileReqType type)
+{
+ TEEC_FileReq *new_req;
+ struct tee_file_req_node *req_node;
+
+ BUG_ON(!name);
+
+ if (type == TEEC_FILE_REQ_READ || type == TEEC_FILE_REQ_WRITE)
+ BUG_ON(!buf);
+
+ /* allocate TEEC_FileReq structure */
+ new_req = kzalloc(sizeof(TEEC_FileReq), GFP_KERNEL);
+ BUG_ON(!new_req);
+
+ /* prepare a new request */
+ strncpy(new_req->name, name, strlen(name));
+ new_req->type = type;
+ new_req->data_len = len;
+ new_req->result = 0;
+ new_req->kern_data_buf = buf;
+ new_req->error = 0;
+
+ req_node = kzalloc(sizeof(struct tee_file_req_node), GFP_KERNEL);
+ BUG_ON(!req_node);
+
+ req_node->req = new_req;
+ INIT_LIST_HEAD(&req_node->node);
+
+ /* add it to the pending queue and signal the consumer */
+ list_add_tail(&req_list, &req_node->node);
+ complete(&req_ready);
+
+ /* wait for the consumer's signal */
+ wait_for_completion(&req_complete);
+
+ kfree(new_req);
+
+ /* signal completion to the secure world */
+ indicate_complete(secure_error);
+}
+
+void nv_tee_fread(const char *name, void *buf, int len)
+{
+ if (!buf)
+ _tee_fs_file_operation(name, buf, len, TEEC_FILE_REQ_SIZE);
+ else
+ _tee_fs_file_operation(name, buf, len, TEEC_FILE_REQ_READ);
+}
+
+void nv_tee_fwrite(const char *name, void *buf, int len)
+{
+ _tee_fs_file_operation(name, buf, len, TEEC_FILE_REQ_WRITE);
+}
+
+void nv_tee_fdelete(const char *name)
+{
+ _tee_fs_file_operation(name, NULL, 0, TEEC_FILE_REQ_DELETE);
+}
+
+static int __init nv_tee_fs_register_handlers(void)
+{
+ struct tee_shmem *shmem_ptr;
+
+ shmem_ptr = kzalloc(sizeof(struct tee_shmem), GFP_KERNEL);
+ if (!shmem_ptr) {
+ pr_err("%s: no memory available for fs operations\n", __func__);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&req_list);
+ init_completion(&req_ready);
+ init_completion(&req_complete);
+
+ asm volatile (
+ "movw r0, #0x1FF2 \n"
+ "movt r0, #0xFFFF \n"
+ "mov r1, %0 \n"
+ "mov r2, %1 \n"
+ "mov r3, %2 \n"
+ "mov r4, %3 \n"
+ "mov r5, %4 \n"
+#ifdef REQUIRES_SEC
+ ".arch_extension sec \n"
+#endif
+ "smc #0 \n"
+ : : "r" (nv_tee_fread), "r" (nv_tee_fwrite), "r" (nv_tee_fdelete),
+ "r" (shmem_ptr->file_name), "r" (shmem_ptr->file_data)
+ : "r0", "r1", "r2", "r3", "r4", "r13", "r14"
+ );
+
+ return 0;
+}
+
+arch_initcall(nv_tee_fs_register_handlers);
diff --git a/security/nv_tee_driver/tee_protocol.h b/security/nv_tee_driver/tee_protocol.h
index c953efe53d9b..2c6e71e3d7f3 100644
--- a/security/nv_tee_driver/tee_protocol.h
+++ b/security/nv_tee_driver/tee_protocol.h
@@ -35,9 +35,15 @@
_IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x14, union tee_cmd)
#define TEE_IOCTL_REQ_CANCELLATION \
_IOR(TEE_IOCTL_MAGIC_NUMBER, 0x15, union tee_cmd)
+#define TEE_IOCTL_FILE_NEW_REQ \
+ _IOR(TEE_IOCTL_MAGIC_NUMBER, 0x16, TEEC_FileReq)
+#define TEE_IOCTL_FILE_FILL_BUF \
+ _IOR(TEE_IOCTL_MAGIC_NUMBER, 0x17, TEEC_FileReq)
+#define TEE_IOCTL_FILE_REQ_COMPLETE \
+ _IOWR(TEE_IOCTL_MAGIC_NUMBER, 0x18, TEEC_FileReq)
#define TEE_IOCTL_MIN_NR _IOC_NR(TEE_IOCTL_OPEN_CLIENT_SESSION)
-#define TEE_IOCTL_MAX_NR _IOC_NR(TEE_IOCTL_REQ_CANCELLATION)
+#define TEE_IOCTL_MAX_NR _IOC_NR(TEE_IOCTL_FILE_REQ_COMPLETE)
#define NV_CMD_DESC_MAX 120
@@ -204,4 +210,7 @@ void tee_invoke_command(struct tee_invokecmd *cmd,
void tee_unregister_memory(void *buffer,
struct nv_tee_context *context);
+int tee_handle_fs_ioctl(struct file * file, unsigned int ioctl_num,
+ unsigned long ioctl_param);
+
#endif