From a2e9a83066c0810060c222999b0004aedfa18fff Mon Sep 17 00:00:00 2001 From: Cedric Chaumont Date: Wed, 16 Sep 2015 09:47:41 +0200 Subject: [PATCH] GP11 : trusted storage verify (block enc fs) Signed-off-by: Cedric Chaumont Reviewed-by: Pascal Brand Tested-by: Cedric Chaumont (STM boards) Tested-by: Cedric Chaumont (ARM Juno board) --- core/include/tee/tee_fs.h | 15 +- core/include/tee/tee_fs_defs.h | 2 + core/include/tee/tee_obj.h | 2 + core/include/tee/tee_svc_storage.h | 8 + core/tee/tee_fs.c | 17 +- core/tee/tee_fs_common.c | 599 +++++++++++++++++------------ core/tee/tee_fs_private.h | 12 +- core/tee/tee_obj.c | 51 +++ core/tee/tee_svc_cryp.c | 38 +- core/tee/tee_svc_storage.c | 548 ++++++++++++++++---------- lib/libutee/tee_api_objects.c | 81 ++-- ta/ta.mk | 2 + 12 files changed, 851 insertions(+), 524 deletions(-) diff --git a/core/include/tee/tee_fs.h b/core/include/tee/tee_fs.h index ae775c1f03c..bc8163f96fc 100644 --- a/core/include/tee/tee_fs.h +++ b/core/include/tee/tee_fs.h @@ -30,6 +30,7 @@ #include #include +#include #define TEE_FS_NAME_MAX 350 @@ -66,18 +67,20 @@ struct tee_fs_dirent { char *d_name; }; + /* - * tee_fs implemets a POSIX like secure file system + * tee_fs implemets a POSIX like secure file system with GP extension */ struct tee_file_operations { - int (*open)(const char *file, int flags, ...); + int (*open)(TEE_Result *errno, const char *file, int flags, ...); int (*close)(int fd); - int (*read)(int fd, void *buf, size_t len); - int (*write)(int fd, const void *buf, size_t len); - tee_fs_off_t (*lseek)(int fd, tee_fs_off_t offset, int whence); + int (*read)(TEE_Result *errno, int fd, void *buf, size_t len); + int (*write)(TEE_Result *errno, int fd, const void *buf, size_t len); + tee_fs_off_t (*lseek)(TEE_Result *errno, + int fd, tee_fs_off_t offset, int whence); int (*rename)(const char *old, const char *new); int (*unlink)(const char *file); - int (*ftruncate)(int fd, tee_fs_off_t length); + int (*ftruncate)(TEE_Result *errno, int fd, tee_fs_off_t length); int (*mkdir)(const char *path, tee_fs_mode_t mode); tee_fs_dir *(*opendir)(const char *name); int (*closedir)(tee_fs_dir *d); diff --git a/core/include/tee/tee_fs_defs.h b/core/include/tee/tee_fs_defs.h index c07f04db736..2700a869642 100644 --- a/core/include/tee/tee_fs_defs.h +++ b/core/include/tee/tee_fs_defs.h @@ -36,6 +36,8 @@ #define TEE_FS_O_RDWR 0x4 #define TEE_FS_O_CREATE 0x8 #define TEE_FS_O_EXCL 0x10 +#define TEE_FS_O_APPEND 0x20 +#define TEE_FS_O_TRUNC 0x40 /* * tee_fs_lseek diff --git a/core/include/tee/tee_obj.h b/core/include/tee/tee_obj.h index eeb84331b29..f16dd489f91 100644 --- a/core/include/tee/tee_obj.h +++ b/core/include/tee/tee_obj.h @@ -57,4 +57,6 @@ void tee_obj_close(struct tee_ta_ctx *ctx, struct tee_obj *o); void tee_obj_close_all(struct tee_ta_ctx *ctx); +TEE_Result tee_obj_verify(struct tee_ta_session *sess, struct tee_obj *o); + #endif diff --git a/core/include/tee/tee_svc_storage.h b/core/include/tee/tee_svc_storage.h index 8441764d735..98e79337d2c 100644 --- a/core/include/tee/tee_svc_storage.h +++ b/core/include/tee/tee_svc_storage.h @@ -30,6 +30,7 @@ #include #include +#include /* * Persistant Object Functions @@ -79,4 +80,11 @@ void tee_svc_storage_close_all_enum(struct tee_ta_ctx *ctx); void tee_svc_storage_init(void); +char *tee_svc_storage_create_filename(struct tee_ta_session *sess, + void *object_id, + uint32_t object_id_len, + bool transient); + +char *tee_svc_storage_create_dirname(struct tee_ta_session *sess); + #endif /* TEE_SVC_STORAGE_H */ diff --git a/core/tee/tee_fs.c b/core/tee/tee_fs.c index eb4038a55fc..20e63131216 100644 --- a/core/tee/tee_fs.c +++ b/core/tee/tee_fs.c @@ -46,32 +46,33 @@ static int tee_fs_close(int fd) return tee_fs_common_close(fdp); } -static int tee_fs_read(int fd, void *buf, size_t len) +static int tee_fs_read(TEE_Result *errno, int fd, void *buf, size_t len) { struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); - return tee_fs_common_read(fdp, buf, len); + return tee_fs_common_read(errno, fdp, buf, len); } -static int tee_fs_write(int fd, const void *buf, size_t len) +static int tee_fs_write(TEE_Result *errno, int fd, const void *buf, size_t len) { struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); - return tee_fs_common_write(fdp, buf, len); + return tee_fs_common_write(errno, fdp, buf, len); } -static tee_fs_off_t tee_fs_lseek(int fd, tee_fs_off_t offset, int whence) +static tee_fs_off_t tee_fs_lseek(TEE_Result *errno, + int fd, tee_fs_off_t offset, int whence) { struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); - return tee_fs_common_lseek(fdp, offset, whence); + return tee_fs_common_lseek(errno, fdp, offset, whence); } -static int tee_fs_ftruncate(int fd, tee_fs_off_t length) +static int tee_fs_ftruncate(TEE_Result *errno, int fd, tee_fs_off_t length) { struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd); - return tee_fs_common_ftruncate(fdp, length); + return tee_fs_common_ftruncate(errno, fdp, length); } struct tee_file_operations tee_file_ops = { diff --git a/core/tee/tee_fs_common.c b/core/tee/tee_fs_common.c index 611809d4447..7a6d64fa6f2 100644 --- a/core/tee/tee_fs_common.c +++ b/core/tee/tee_fs_common.c @@ -25,6 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -179,6 +180,9 @@ static int ree_fs_mkdir(const char *path, tee_fs_mode_t mode) struct tee_fs_rpc head = { 0 }; uint32_t len; + if (!path) + return -1; + len = strlen(path) + 1; if (len > REE_FS_NAME_MAX) goto exit; @@ -194,6 +198,102 @@ static int ree_fs_mkdir(const char *path, tee_fs_mode_t mode) return res; } +static tee_fs_dir *ree_fs_opendir(const char *name) +{ + struct tee_fs_rpc head = { 0 }; + uint32_t len; + struct tee_fs_dir *dir = NULL; + + if (!name) + goto exit; + + len = strlen(name) + 1; + if (len > TEE_FS_NAME_MAX) + goto exit; + + head.op = TEE_FS_OPENDIR; + + if (tee_fs_send_cmd(&head, (void *)name, len, TEE_FS_MODE_IN)) + goto exit; + + if (head.res < 0) + goto exit; + + dir = malloc(sizeof(struct tee_fs_dir)); + if (!dir) { + int nw_dir = head.res; + + memset(&head, 0, sizeof(head)); + head.op = TEE_FS_CLOSEDIR; + head.arg = nw_dir; + tee_fs_send_cmd(&head, NULL, 0, TEE_FS_MODE_NONE); + goto exit; + } + + dir->nw_dir = head.res; + dir->d.d_name = NULL; + +exit: + return dir; +} + +static int ree_fs_closedir(tee_fs_dir *d) +{ + int res = -1; + struct tee_fs_rpc head = { 0 }; + + if (!d) { + res = 0; + goto exit; + } + + head.op = TEE_FS_CLOSEDIR; + head.arg = (int)d->nw_dir; + + res = tee_fs_send_cmd(&head, NULL, 0, TEE_FS_MODE_NONE); + if (!res) + res = head.res; + +exit: + if (d) + free(d->d.d_name); + free(d); + + return res; +} + +static struct tee_fs_dirent *ree_fs_readdir(tee_fs_dir *d) +{ + struct tee_fs_dirent *res = NULL; + struct tee_fs_rpc head = { 0 }; + char fname[TEE_FS_NAME_MAX + 1]; + + if (!d) + goto exit; + + head.op = TEE_FS_READDIR; + head.arg = (int)d->nw_dir; + + if (tee_fs_send_cmd(&head, fname, sizeof(fname), TEE_FS_MODE_OUT)) + goto exit; + + if (head.res < 0) + goto exit; + + if (!head.len || head.len > sizeof(fname)) + goto exit; + + fname[head.len - 1] = '\0'; /* make sure it's zero terminated */ + free(d->d.d_name); + d->d.d_name = strdup(fname); + if (!d->d.d_name) + goto exit; + + res = &d->d; +exit: + return res; +} + static int ree_fs_rmdir(const char *name) { int res = -1; @@ -261,6 +361,30 @@ static int ree_fs_unlink(const char *file) return res; } +static int ree_fs_access(const char *name, int mode) +{ + int res = -1; + struct tee_fs_rpc head = { 0 }; + uint32_t len; + + if (!name) + goto exit; + + len = strlen(name) + 1; + if (len > TEE_FS_NAME_MAX) + goto exit; + + head.op = TEE_FS_ACCESS; + head.flags = mode; + + res = tee_fs_send_cmd(&head, (void *)name, len, TEE_FS_MODE_IN); + if (!res) + res = head.res; + +exit: + return res; +} + static int get_file_length(int fd, size_t *length) { size_t file_len; @@ -417,88 +541,87 @@ static int read_and_decrypt_file(int fd, return (res < 0) ? res : 0; } +static struct tee_fs_file_meta *duplicate_meta( + struct tee_fs_fd *fdp) +{ + struct tee_fs_file_meta *new_meta = NULL; + + new_meta = malloc(sizeof(*new_meta)); + if (!new_meta) { + EMSG("Failed to allocate memory for new meta"); + goto exit; + } + + memcpy(new_meta, fdp->meta, sizeof(*new_meta)); + +exit: + return new_meta; +} + static int write_meta_file(const char *filename, - struct tee_fs_file_meta *new_meta, int version) + struct tee_fs_file_meta *meta) { int res, fd = -1; char meta_path[REE_FS_NAME_MAX]; - get_meta_filepath(filename, version, meta_path); + get_meta_filepath(filename, meta->backup_version, meta_path); - fd = ree_fs_open(meta_path, TEE_FS_O_CREATE | TEE_FS_O_WRONLY); + fd = ree_fs_open(meta_path, TEE_FS_O_CREATE | + TEE_FS_O_TRUNC | TEE_FS_O_WRONLY); if (fd < 0) return -1; res = encrypt_and_write_file(fd, META_FILE, - (void *)&new_meta->info, sizeof(new_meta->info), - new_meta->encrypted_fek); + (void *)&meta->info, sizeof(meta->info), + meta->encrypted_fek); ree_fs_close(fd); return res; } -static struct tee_fs_file_meta *tee_fs_create_meta_file(const char *file, - int meta_version) +static struct tee_fs_file_meta *create_meta_file(const char *file) { TEE_Result tee_res; struct tee_fs_file_meta *meta = NULL; - int res = ree_fs_mkdir(file, - TEE_FS_S_IRUSR | TEE_FS_S_IWUSR); - if (res) - goto exit; + int res; + const uint8_t default_backup_version = 0; meta = malloc(sizeof(struct tee_fs_file_meta)); if (!meta) { EMSG("Failed to allocate memory"); - goto exit_rmdir; + goto exit; } memset(&meta->info, 0, sizeof(meta->info)); tee_res = tee_fs_generate_fek(meta->encrypted_fek, TEE_FS_KM_FEK_SIZE); if (tee_res != TEE_SUCCESS) - goto exit_rmdir; + goto exit; + + meta->backup_version = default_backup_version; - res = write_meta_file(file, meta, meta_version); + res = write_meta_file(file, meta); if (res < 0) - goto exit_rmdir; + goto exit; return meta; -exit_rmdir: - free(meta); - ree_fs_rmdir(file); exit: - return NULL; -} - -static struct tee_fs_file_meta *duplicate_meta( - struct tee_fs_fd *fdp) -{ - struct tee_fs_file_meta *new_meta = NULL; - - new_meta = malloc(sizeof(*new_meta)); - if (!new_meta) { - EMSG("Failed to allocate memory for new meta"); - goto exit; - } - - memcpy(new_meta, fdp->meta, sizeof(*new_meta)); + free(meta); -exit: - return new_meta; + return NULL; } -static int tee_fs_commit_meta_file(struct tee_fs_fd *fdp, +static int commit_meta_file(struct tee_fs_fd *fdp, struct tee_fs_file_meta *new_meta) { int res; - uint8_t new_version, old_version; + uint8_t old_version; char meta_path[REE_FS_NAME_MAX]; - old_version = fdp->meta_version; - new_version = !old_version; + old_version = new_meta->backup_version; + new_meta->backup_version = !new_meta->backup_version; - res = write_meta_file(fdp->filename, new_meta, new_version); + res = write_meta_file(fdp->filename, new_meta); if (res < 0) return res; @@ -508,10 +631,9 @@ static int tee_fs_commit_meta_file(struct tee_fs_fd *fdp, * change tee_fs_fd accordingly */ memcpy(fdp->meta, new_meta, sizeof(*new_meta)); - fdp->meta_version = new_version; /* - * Remove outdated file meta, there is nothing we can + * Remove old meta file, there is nothing we can * do if we fail here, but that is OK because both * new & old version of block files are kept. The context * of the file is still consistent. @@ -543,7 +665,7 @@ static int read_meta_file(const char *meta_path, return res; } -static struct tee_fs_file_meta *tee_fs_open_meta_file( +static struct tee_fs_file_meta *open_meta_file( const char *file, int version) { int res; @@ -962,7 +1084,6 @@ static inline int create_hard_link(const char *old_dir, return ree_fs_link(old_path, new_path); } - static int unlink_tee_file(const char *file) { int res = -1; @@ -1003,68 +1124,142 @@ static int unlink_tee_file(const char *file) return res; } +static bool is_tee_file_exist(const char *file) +{ + return !ree_fs_access(file, TEE_FS_F_OK); +} + +static struct tee_fs_file_meta *create_tee_file(const char *file) +{ + struct tee_fs_file_meta *meta = NULL; + int res; + + DMSG("Creating TEE file=%s", file); + + /* create TEE file directory */ + res = ree_fs_mkdir(file, + TEE_FS_S_IRUSR | TEE_FS_S_IWUSR); + if (res) { + EMSG("Failed to create TEE file directory, filename=%s", + file); + goto exit; + } + + /* create meta file in TEE file directory */ + meta = create_meta_file(file); + if (!meta) + EMSG("Failed to create new meta file"); + +exit: + return meta; +} + +static struct tee_fs_file_meta *open_tee_file(const char *file) +{ + struct tee_fs_file_meta *meta = NULL; + int backup_version = 0; + + DMSG("Opening TEE file=%s", file); + + meta = open_meta_file(file, backup_version); + if (!meta) { + meta = open_meta_file(file, !backup_version); + if (!meta) { + /* + * cannot open meta file, assumed the TEE file + * is corrupted + */ + EMSG("Can not open meta file"); + } + } + + return meta; +} struct tee_fs_fd *tee_fs_fd_lookup(int fd) { return handle_lookup(&fs_handle_db, fd); } -int tee_fs_common_open(const char *file, int flags, ...) +int tee_fs_common_open(TEE_Result *errno, const char *file, int flags, ...) { int res = -1; - int meta_version; size_t len; struct tee_fs_file_meta *meta = NULL; struct tee_fs_fd *fdp = NULL; + bool file_exist; - if (!file) + assert(errno != NULL); + *errno = TEE_SUCCESS; + + if (!file) { + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; + } len = strlen(file) + 1; - if (len > TEE_FS_NAME_MAX) + if (len > TEE_FS_NAME_MAX) { + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; + } - meta_version = 0; - meta = tee_fs_open_meta_file(file, meta_version); - if (!meta) { - meta_version = 1; - meta = tee_fs_open_meta_file(file, meta_version); + file_exist = is_tee_file_exist(file); + if (flags & TEE_FS_O_CREATE) { + if ((flags & TEE_FS_O_EXCL) && file_exist) { + EMSG("tee file already exists"); + *errno = TEE_ERROR_ACCESS_CONFLICT; + goto exit; + } - /* cannot find meta file, assumed file not existed */ - if (!meta) { - if (flags & TEE_FS_O_CREATE) { - meta_version = 0; - meta = tee_fs_create_meta_file(file, - meta_version); - if (!meta) { - EMSG("Fail to create new meta file"); - return -1; - } - } else { - EMSG("Meta file not found"); - return -1; - } + if (!file_exist) + meta = create_tee_file(file); + else + meta = open_tee_file(file); + + } else { + if (!file_exist) { + EMSG("tee file not exists"); + *errno = TEE_ERROR_ITEM_NOT_FOUND; + goto exit; } + + meta = open_tee_file(file); + } + + if (!meta) { + EMSG("Failed to open TEE file"); + *errno = TEE_ERROR_CORRUPT_OBJECT; + goto exit; } - DMSG("Open file=%s, meta version=%d", file, meta_version); fdp = (struct tee_fs_fd *)malloc(sizeof(struct tee_fs_fd)); - if (!fdp) + if (!fdp) { + *errno = TEE_ERROR_OUT_OF_MEMORY; goto exit_free_fd; + } /* init internal status */ fdp->flags = flags; fdp->private = NULL; fdp->meta = meta; - fdp->meta_version = meta_version; fdp->pos = 0; fdp->filename = malloc(len); if (!fdp->filename) { res = -1; + *errno = TEE_ERROR_OUT_OF_MEMORY; goto exit_free_fd; } memcpy(fdp->filename, file, len); + if ((flags & TEE_FS_O_TRUNC) && + (flags & TEE_FS_O_WRONLY || flags & TEE_FS_O_RDWR)) { + res = tee_fs_common_ftruncate(errno, fdp, 0); + if (res < 0) { + EMSG("Unable to truncate file"); + goto exit_free_fd; + } + } + /* return fd */ res = handle_get(&fs_handle_db, fdp); fdp->fd = res; @@ -1098,15 +1293,20 @@ int tee_fs_common_close(struct tee_fs_fd *fdp) return res; } -tee_fs_off_t tee_fs_common_lseek(struct tee_fs_fd *fdp, +tee_fs_off_t tee_fs_common_lseek(TEE_Result *errno, struct tee_fs_fd *fdp, tee_fs_off_t offset, int whence) { tee_fs_off_t res = -1; tee_fs_off_t new_pos; size_t filelen; - if (!fdp) + assert(errno != NULL); + *errno = TEE_SUCCESS; + + if (!fdp) { + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; + } DMSG("offset=%d, whence=%d", (int)offset, whence); @@ -1126,6 +1326,7 @@ tee_fs_off_t tee_fs_common_lseek(struct tee_fs_fd *fdp, break; default: + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; } @@ -1134,6 +1335,7 @@ tee_fs_off_t tee_fs_common_lseek(struct tee_fs_fd *fdp, if (new_pos > TEE_DATA_MAX_POSITION) { EMSG("Position is beyond TEE_DATA_MAX_POSITION"); + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; } @@ -1159,7 +1361,7 @@ tee_fs_off_t tee_fs_common_lseek(struct tee_fs_fd *fdp, * update failed, and the file content will not be updated * */ -int tee_fs_common_ftruncate(struct tee_fs_fd *fdp, +int tee_fs_common_ftruncate(TEE_Result *errno, struct tee_fs_fd *fdp, tee_fs_off_t new_file_len) { int res = -1; @@ -1167,27 +1369,41 @@ int tee_fs_common_ftruncate(struct tee_fs_fd *fdp, struct tee_fs_file_meta *new_meta = NULL; uint8_t *buf = NULL; - if (!fdp) - return -1; + assert(errno != NULL); + *errno = TEE_SUCCESS; + + if (!fdp) { + *errno = TEE_ERROR_BAD_PARAMETERS; + res = -1; + goto exit; + } if (fdp->flags & TEE_FS_O_RDONLY) { + *errno = TEE_ERROR_BAD_PARAMETERS; EMSG("Read only"); - return -1; + res = -1; + goto exit; } if ((size_t)new_file_len == old_file_len) { DMSG("Ignore due to file length does not changed"); - return 0; + res = 0; + goto exit; } if (new_file_len > MAX_FILE_SIZE) { + *errno = TEE_ERROR_BAD_PARAMETERS; EMSG("Over maximum file size(%d)", MAX_FILE_SIZE); - return -1; + res = -1; + goto exit; } new_meta = duplicate_meta(fdp); - if (!new_meta) - goto exit; + if (!new_meta) { + *errno = TEE_ERROR_OUT_OF_MEMORY; + res = -1; + goto free; + } new_meta->info.length = new_file_len; @@ -1197,10 +1413,11 @@ int tee_fs_common_ftruncate(struct tee_fs_fd *fdp, DMSG("Truncate file length to %zu", (size_t)new_file_len); - res = tee_fs_commit_meta_file(fdp, new_meta); + res = commit_meta_file(fdp, new_meta); if (res < 0) { + *errno = TEE_ERROR_CORRUPT_OBJECT; EMSG("Failed to commit meta file"); - goto exit; + goto free; } /* now we are safe to free unused blocks */ @@ -1219,10 +1436,11 @@ int tee_fs_common_ftruncate(struct tee_fs_fd *fdp, buf = malloc(FILE_BLOCK_SIZE); if (!buf) { + *errno = TEE_ERROR_OUT_OF_MEMORY; EMSG("Failed to allocate buffer, size=%d", FILE_BLOCK_SIZE); res = -1; - goto exit; + goto free; } memset(buf, 0x0, FILE_BLOCK_SIZE); @@ -1241,6 +1459,7 @@ int tee_fs_common_ftruncate(struct tee_fs_fd *fdp, write_one_block, (void *)buf, data_len, new_meta); if (res < 0) { + *errno = TEE_ERROR_CORRUPT_OBJECT; EMSG("Failed to fill data"); break; } @@ -1251,36 +1470,49 @@ int tee_fs_common_ftruncate(struct tee_fs_fd *fdp, fdp->pos = orig_pos; if (res == 0) { - res = tee_fs_commit_meta_file(fdp, new_meta); - if (res < 0) + res = commit_meta_file(fdp, new_meta); + if (res < 0) { + *errno = TEE_ERROR_CORRUPT_OBJECT; EMSG("Failed to commit meta file"); + } } } -exit: +free: free(new_meta); free(buf); +exit: return res; } -int tee_fs_common_read(struct tee_fs_fd *fdp, void *buf, size_t len) +int tee_fs_common_read(TEE_Result *errno, struct tee_fs_fd *fdp, + void *buf, size_t len) { int res = -1; - if (!fdp) + assert(errno != NULL); + *errno = TEE_SUCCESS; + + if (!fdp) { + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; + } if (!len) { res = 0; goto exit; } - if (!buf) + if (!buf) { + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; + } - if (fdp->flags & TEE_FS_O_WRONLY) + if (fdp->flags & TEE_FS_O_WRONLY) { + *errno = TEE_ERROR_ACCESS_CONFLICT; goto exit; + } DMSG("len=%zu", len); @@ -1291,6 +1523,8 @@ int tee_fs_common_read(struct tee_fs_fd *fdp, void *buf, size_t len) res = tee_fs_do_multi_blocks_transfer(fdp, read_one_block, buf, len, NULL); + if (res < 0) + *errno = TEE_ERROR_CORRUPT_OBJECT; exit: return (res < 0) ? res : (int)len; } @@ -1319,29 +1553,40 @@ int tee_fs_common_read(struct tee_fs_fd *fdp, void *buf, size_t len) * (Any failure in above steps is considered as a successfully * update) */ -int tee_fs_common_write(struct tee_fs_fd *fdp, +int tee_fs_common_write(TEE_Result *errno, struct tee_fs_fd *fdp, const void *buf, size_t len) { int res = -1; struct tee_fs_file_meta *new_meta; size_t file_size = fdp->meta->info.length; - if (!fdp) + assert(errno != NULL); + *errno = TEE_SUCCESS; + + if (!fdp) { + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; + } if (!len) { res = 0; goto exit; } - if (!buf) + if (!buf) { + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; + } - if (fdp->flags & TEE_FS_O_RDONLY) + if (fdp->flags & TEE_FS_O_RDONLY) { + EMSG("Write to a read-only file, denied"); + *errno = TEE_ERROR_ACCESS_CONFLICT; goto exit; + } if ((fdp->pos + len) > MAX_FILE_SIZE) { EMSG("Over maximum file size(%d)", MAX_FILE_SIZE); + *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; } @@ -1349,28 +1594,35 @@ int tee_fs_common_write(struct tee_fs_fd *fdp, if (file_size < (size_t)fdp->pos) { DMSG("File hole detected, try to extend file size"); - res = tee_fs_common_ftruncate(fdp, fdp->pos); + res = tee_fs_common_ftruncate(errno, fdp, fdp->pos); if (res < 0) goto exit; } new_meta = duplicate_meta(fdp); - if (!new_meta) + if (!new_meta) { + *errno = TEE_ERROR_OUT_OF_MEMORY; goto exit; + } res = tee_fs_do_multi_blocks_transfer(fdp, write_one_block, (void *)buf, len, new_meta); - if (res == 0) { + if (res < 0) { + *errno = TEE_ERROR_CORRUPT_OBJECT; + goto exit; + } else { int r; /* update file length if necessary */ if (fdp->pos > (tee_fs_off_t)new_meta->info.length) new_meta->info.length = fdp->pos; - r = tee_fs_commit_meta_file(fdp, new_meta); - if (r < 0) + r = commit_meta_file(fdp, new_meta); + if (r < 0) { + *errno = TEE_ERROR_CORRUPT_OBJECT; res = -1; + } } free(new_meta); @@ -1497,167 +1749,30 @@ int tee_fs_common_unlink(const char *file) int tee_fs_common_mkdir(const char *path, tee_fs_mode_t mode) { - int res = -1; - struct tee_fs_rpc head = { 0 }; - uint32_t len; - - if (!path) - return -1; - - len = strlen(path) + 1; - if (len > TEE_FS_NAME_MAX) - goto exit; - - head.op = TEE_FS_MKDIR; - head.flags = mode; - - res = tee_fs_send_cmd(&head, (void *)path, len, TEE_FS_MODE_IN); - if (!res) - res = head.res; - -exit: - return res; + return ree_fs_mkdir(path, mode); } tee_fs_dir *tee_fs_common_opendir(const char *name) { - struct tee_fs_rpc head = { 0 }; - uint32_t len; - struct tee_fs_dir *dir = NULL; - - if (!name) - goto exit; - - len = strlen(name) + 1; - if (len > TEE_FS_NAME_MAX) - goto exit; - - head.op = TEE_FS_OPENDIR; - - if (tee_fs_send_cmd(&head, (void *)name, len, TEE_FS_MODE_IN)) - goto exit; - - if (head.res < 0) - goto exit; - - dir = malloc(sizeof(struct tee_fs_dir)); - if (!dir) { - int nw_dir = head.res; - - memset(&head, 0, sizeof(head)); - head.op = TEE_FS_CLOSEDIR; - head.arg = nw_dir; - tee_fs_send_cmd(&head, NULL, 0, TEE_FS_MODE_NONE); - goto exit; - } - - dir->nw_dir = head.res; - dir->d.d_name = NULL; - -exit: - return dir; + return ree_fs_opendir(name); } int tee_fs_common_closedir(tee_fs_dir *d) { - int res = -1; - struct tee_fs_rpc head = { 0 }; - - if (!d) { - res = 0; - goto exit; - } - - head.op = TEE_FS_CLOSEDIR; - head.arg = (int)d->nw_dir; - - res = tee_fs_send_cmd(&head, NULL, 0, TEE_FS_MODE_NONE); - if (!res) - res = head.res; - -exit: - if (d) - free(d->d.d_name); - free(d); - - return res; + return ree_fs_closedir(d); } struct tee_fs_dirent *tee_fs_common_readdir(tee_fs_dir *d) { - struct tee_fs_dirent *res = NULL; - struct tee_fs_rpc head = { 0 }; - char fname[TEE_FS_NAME_MAX + 1]; - - if (!d) - goto exit; - - head.op = TEE_FS_READDIR; - head.arg = (int)d->nw_dir; - - if (tee_fs_send_cmd(&head, fname, sizeof(fname), TEE_FS_MODE_OUT)) - goto exit; - - if (head.res < 0) - goto exit; - - if (!head.len || head.len > sizeof(fname)) - goto exit; - - fname[head.len - 1] = '\0'; /* make sure it's zero terminated */ - free(d->d.d_name); - d->d.d_name = strdup(fname); - if (!d->d.d_name) - goto exit; - - res = &d->d; -exit: - return res; + return ree_fs_readdir(d); } int tee_fs_common_rmdir(const char *name) { - int res = -1; - struct tee_fs_rpc head = { 0 }; - uint32_t len; - - if (!name) - goto exit; - - len = strlen(name) + 1; - if (len > TEE_FS_NAME_MAX) - goto exit; - - head.op = TEE_FS_RMDIR; - - res = tee_fs_send_cmd(&head, (void *)name, len, TEE_FS_MODE_IN); - if (!res) - res = head.res; - -exit: - return res; + return ree_fs_rmdir(name); } int tee_fs_common_access(const char *name, int mode) { - int res = -1; - struct tee_fs_rpc head = { 0 }; - uint32_t len; - - if (!name) - goto exit; - - len = strlen(name) + 1; - if (len > TEE_FS_NAME_MAX) - goto exit; - - head.op = TEE_FS_ACCESS; - head.flags = mode; - - res = tee_fs_send_cmd(&head, (void *)name, len, TEE_FS_MODE_IN); - if (!res) - res = head.res; - -exit: - return res; + return ree_fs_access(name, mode); } diff --git a/core/tee/tee_fs_private.h b/core/tee/tee_fs_private.h index fb71925c22e..7f65f8b3f30 100644 --- a/core/tee/tee_fs_private.h +++ b/core/tee/tee_fs_private.h @@ -68,11 +68,11 @@ struct tee_fs_file_info { struct tee_fs_file_meta { struct tee_fs_file_info info; uint8_t encrypted_fek[TEE_FS_KM_FEK_SIZE]; + uint8_t backup_version; }; struct tee_fs_fd { struct tee_fs_file_meta *meta; - uint8_t meta_version; int pos; uint32_t flags; int fd; @@ -119,20 +119,20 @@ static inline void toggle_backup_version_of_block( struct tee_fs_fd *tee_fs_fd_lookup(int fd); -int tee_fs_common_open(const char *file, int flags, ...); +int tee_fs_common_open(TEE_Result *errno, const char *file, int flags, ...); int tee_fs_common_close(struct tee_fs_fd *fdp); -tee_fs_off_t tee_fs_common_lseek(struct tee_fs_fd *fdp, +tee_fs_off_t tee_fs_common_lseek(TEE_Result *errno, struct tee_fs_fd *fdp, tee_fs_off_t offset, int whence); -int tee_fs_common_ftruncate(struct tee_fs_fd *fdp, +int tee_fs_common_ftruncate(TEE_Result *errno, struct tee_fs_fd *fdp, tee_fs_off_t length); -int tee_fs_common_read(struct tee_fs_fd *fdp, +int tee_fs_common_read(TEE_Result *errno, struct tee_fs_fd *fdp, void *buf, size_t len); -int tee_fs_common_write(struct tee_fs_fd *fdp, +int tee_fs_common_write(TEE_Result *errno, struct tee_fs_fd *fdp, const void *buf, size_t len); int tee_fs_common_rename(const char *old, const char *new); diff --git a/core/tee/tee_obj.c b/core/tee/tee_obj.c index 9709966161d..b8f70203f47 100644 --- a/core/tee/tee_obj.c +++ b/core/tee/tee_obj.c @@ -31,8 +31,10 @@ #include #include #include +#include #include #include +#include void tee_obj_add(struct tee_ta_ctx *ctx, struct tee_obj *o) { @@ -75,3 +77,52 @@ void tee_obj_close_all(struct tee_ta_ctx *ctx) while (!TAILQ_EMPTY(objects)) tee_obj_close(ctx, TAILQ_FIRST(objects)); } + +TEE_Result tee_obj_verify(struct tee_ta_session *sess, struct tee_obj *o) +{ + TEE_Result res; + char *file = NULL; + char *dir = NULL; + int fd = -1; + int err = -1; + + file = tee_svc_storage_create_filename(sess, + o->pobj->obj_id, + o->pobj->obj_id_len, + false); + if (file == NULL) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto exit; + } + + err = tee_file_ops.access(file, TEE_FS_F_OK); + if (err) { + /* file not found */ + res = TEE_ERROR_STORAGE_NOT_AVAILABLE; + goto err; + } + + fd = tee_file_ops.open(&res, file, TEE_FS_O_RDONLY); + if (fd < 0) { + if (res == TEE_ERROR_CORRUPT_OBJECT) { + EMSG("Object corrupt\n"); + tee_obj_close(sess->ctx, o); + tee_file_ops.unlink(file); + dir = tee_svc_storage_create_dirname(sess); + if (dir != NULL) { + tee_file_ops.rmdir(dir); + free(dir); + } + } + goto err; + } + + res = TEE_SUCCESS; + +err: + free(file); + if (fd >= 0) + tee_file_ops.close(fd); +exit: + return res; +} diff --git a/core/tee/tee_svc_cryp.c b/core/tee/tee_svc_cryp.c index 4eebb135913..540cc121d4c 100644 --- a/core/tee/tee_svc_cryp.c +++ b/core/tee/tee_svc_cryp.c @@ -517,15 +517,22 @@ TEE_Result tee_svc_cryp_obj_get_info(uint32_t obj, TEE_ObjectInfo *info) res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - return res; + goto exit; res = tee_obj_get(sess->ctx, obj, &o); if (res != TEE_SUCCESS) - return res; + goto exit; + + if (o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT) { + res = tee_obj_verify(sess, o); + if (res != TEE_SUCCESS) + goto exit; + } - /* TODO add TEE_ERROR_STORAGE_NOT_AVAILABLE implementation */ + res = tee_svc_copy_to_user(sess, info, &o->info, sizeof(o->info)); - return tee_svc_copy_to_user(sess, info, &o->info, sizeof(o->info)); +exit: + return res; } TEE_Result tee_svc_cryp_obj_restrict_usage(uint32_t obj, uint32_t usage) @@ -536,17 +543,22 @@ TEE_Result tee_svc_cryp_obj_restrict_usage(uint32_t obj, uint32_t usage) res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - return res; + goto exit; res = tee_obj_get(sess->ctx, obj, &o); if (res != TEE_SUCCESS) - return res; + goto exit; - /* TODO add TEE_ERROR_STORAGE_NOT_AVAILABLE implementation */ + if (o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT) { + res = tee_obj_verify(sess, o); + if (res != TEE_SUCCESS) + goto exit; + } o->info.objectUsage &= usage; - return TEE_SUCCESS; +exit: + return res; } static TEE_Result tee_svc_cryp_obj_get_raw_data( @@ -713,13 +725,13 @@ TEE_Result tee_svc_cryp_obj_get_attr(uint32_t obj, uint32_t attr_id, return TEE_ERROR_ITEM_NOT_FOUND; /* Check that the object is initialized */ - if ((o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) == 0) - return TEE_ERROR_ITEM_NOT_FOUND; + if (!(o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) + return TEE_ERROR_BAD_PARAMETERS; /* Check that getting the attribute is allowed */ - if ((attr_id & TEE_ATTR_BIT_PROTECTED) == 0 && - (o->info.objectUsage & TEE_USAGE_EXTRACTABLE) == 0) - return TEE_ERROR_ACCESS_DENIED; + if (!(attr_id & TEE_ATTR_BIT_PROTECTED) && + !(o->info.objectUsage & TEE_USAGE_EXTRACTABLE)) + return TEE_ERROR_BAD_PARAMETERS; type_props = tee_svc_find_type_props(o->info.objectType); if (!type_props) { diff --git a/core/tee/tee_svc_storage.c b/core/tee/tee_svc_storage.c index 5633e5173dd..9c6cb358139 100644 --- a/core/tee/tee_svc_storage.c +++ b/core/tee/tee_svc_storage.c @@ -90,10 +90,10 @@ static TEE_Result tee_svc_close_enum(struct tee_ta_ctx *ctx, return TEE_SUCCESS; } -static char *tee_svc_storage_create_filename(struct tee_ta_session *sess, - void *object_id, - uint32_t object_id_len, - bool transient) +char *tee_svc_storage_create_filename(struct tee_ta_session *sess, + void *object_id, + uint32_t object_id_len, + bool transient) { uint8_t *file = NULL; /* +1 for the '/' (default) */ @@ -126,7 +126,7 @@ static char *tee_svc_storage_create_filename(struct tee_ta_session *sess, return (char *)file; } -static char *tee_svc_storage_create_dirname(struct tee_ta_session *sess) +char *tee_svc_storage_create_dirname(struct tee_ta_session *sess) { uint8_t *dir = NULL; uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)); @@ -142,6 +142,38 @@ static char *tee_svc_storage_create_dirname(struct tee_ta_session *sess) return (char *)dir; } +static TEE_Result tee_svc_storage_remove_corrupt_obj( + struct tee_ta_session *sess, + struct tee_obj *o) +{ + TEE_Result res; + char *file = NULL; + char *dir = NULL; + + file = tee_svc_storage_create_filename(sess, + o->pobj->obj_id, + o->pobj->obj_id_len, + false); + if (file == NULL) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto exit; + } + + tee_obj_close(sess->ctx, o); + tee_file_ops.unlink(file); + free(file); + dir = tee_svc_storage_create_dirname(sess); + if (dir != NULL) { + tee_file_ops.rmdir(dir); + free(dir); + } + + res = TEE_SUCCESS; + +exit: + return res; +} + static uint32_t tee_svc_storage_conv_oflags(uint32_t flags) { uint32_t out = 0; @@ -183,44 +215,40 @@ static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess, TEE_Result res = TEE_SUCCESS; char *dir = NULL; int tmp; - uint32_t cflags = TEE_FS_O_WRONLY | TEE_FS_O_CREATE; - - *fd = tee_file_ops.open(file, cflags); + int err; + uint32_t cflags = TEE_FS_O_WRONLY | + TEE_FS_O_CREATE | TEE_FS_O_TRUNC; - if (*fd < 0) { - /* try and make directory */ - dir = tee_svc_storage_create_dirname(sess); - if (dir == NULL) { - res = TEE_ERROR_OUT_OF_MEMORY; - goto exit; - } + dir = tee_svc_storage_create_dirname(sess); + if (dir == NULL) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto exit; + } + /* try and make directory */ + err = tee_file_ops.access(dir, TEE_FS_F_OK); + if (err) { + /* directory does not exists */ tmp = tee_file_ops.mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR); - free(dir); if (tmp < 0) { /* error codes needs better granularity */ res = TEE_ERROR_GENERIC; goto exit; } - - /* try and open again */ - *fd = tee_file_ops.open(file, cflags); - - if (*fd < 0) { - /* error codes needs better granularity */ - res = TEE_ERROR_GENERIC; - goto exit; - } } + /* try and open again */ + *fd = tee_file_ops.open(&res, file, cflags); + exit: + free(dir); return res; } static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess, - struct tee_obj *o) + struct tee_obj *o) { TEE_Result res = TEE_SUCCESS; int fd = -1; @@ -240,15 +268,20 @@ static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess, goto exit; } - fd = tee_file_ops.open(file, TEE_FS_O_RDONLY); + fd = tee_file_ops.open(&res, file, TEE_FS_O_RDONLY); free(file); - - /* error codes needs better granularity */ if (fd < 0) - return TEE_ERROR_ITEM_NOT_FOUND; + goto exit; /* read head */ - err = tee_file_ops.read(fd, &head, sizeof(struct tee_svc_storage_head)); + err = tee_file_ops.read(&res, fd, &head, + sizeof(struct tee_svc_storage_head)); + if (err < 0) { + if (res == TEE_ERROR_CORRUPT_OBJECT) + EMSG("Head corrupt\n"); + goto exit; + } + if (err != sizeof(struct tee_svc_storage_head)) { res = TEE_ERROR_BAD_FORMAT; goto exit; @@ -264,15 +297,15 @@ static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess, } /* read meta */ - err = tee_file_ops.read(fd, o->data, o->data_size); + err = tee_file_ops.read(&res, fd, o->data, o->data_size); if (err != (int)o->data_size) { free(o->data); o->data = NULL; - res = TEE_ERROR_NO_DATA; } exit: - tee_file_ops.close(fd); + if (fd >= 0) + tee_file_ops.close(fd); return res; } @@ -335,34 +368,25 @@ static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess, head.ds_size = len; /* write head */ - err = tee_file_ops.write(fd, &head, + err = tee_file_ops.write(&res, fd, &head, sizeof(struct tee_svc_storage_head)); /* error codes needs better granularity */ - if (err != sizeof(struct tee_svc_storage_head)) { - res = TEE_ERROR_GENERIC; + if (err != sizeof(struct tee_svc_storage_head)) goto exit; - } /* write meta */ - err = tee_file_ops.write(fd, o->data, o->data_size); - /* error codes needs better granularity */ - if (err != (int)o->data_size) { - res = TEE_ERROR_GENERIC; + err = tee_file_ops.write(&res, fd, o->data, o->data_size); + if (err != (int)o->data_size) goto exit; - } /* write init data */ o->info.dataSize = len; /* write data to fs if needed */ if (data && len) { - err = tee_file_ops.write(fd, data, len); - - if (err != (int)len) { - /* error codes needs better granularity */ - res = TEE_ERROR_GENERIC; + err = tee_file_ops.write(&res, fd, data, len); + if (err != (int)len) goto exit; - } } exit: @@ -374,34 +398,6 @@ static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess, return res; } -static TEE_Result tee_svc_storage_remove(struct tee_ta_session *sess, - uint32_t storage_id, void *object_id, - uint32_t object_id_len) -{ - TEE_Result res = TEE_SUCCESS; - char *file = NULL; - int err; - - if (sess == NULL) - return TEE_ERROR_BAD_PARAMETERS; - - if (storage_id != TEE_STORAGE_PRIVATE) - return TEE_ERROR_ITEM_NOT_FOUND; - - file = tee_svc_storage_create_filename(sess, object_id, - object_id_len, false); - if (file == NULL) - return TEE_ERROR_OUT_OF_MEMORY; - - err = tee_file_ops.unlink(file); - free(file); - if (err != 0) - /* error codes needs better granularity */ - res = TEE_ERROR_GENERIC; - - return res; -} - TEE_Result tee_svc_storage_obj_open(uint32_t storage_id, void *object_id, uint32_t object_id_len, uint32_t flags, uint32_t *obj) @@ -415,36 +411,41 @@ TEE_Result tee_svc_storage_obj_open(uint32_t storage_id, void *object_id, tee_fs_off_t off; tee_fs_off_t e_off; struct tee_pobj *po = NULL; + int err = -1; - if (storage_id != TEE_STORAGE_PRIVATE) - return TEE_ERROR_ITEM_NOT_FOUND; + if (storage_id != TEE_STORAGE_PRIVATE) { + res = TEE_ERROR_ITEM_NOT_FOUND; + goto exit; + } - if (object_id_len > TEE_OBJECT_ID_MAX_LEN) - return TEE_ERROR_BAD_PARAMETERS; + if (object_id_len > TEE_OBJECT_ID_MAX_LEN) { + res = TEE_ERROR_BAD_PARAMETERS; + goto exit; + } res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - goto exit; + goto err; - res = - tee_mmu_check_access_rights(sess->ctx, - TEE_MEMORY_ACCESS_READ | - TEE_MEMORY_ACCESS_ANY_OWNER, - (tee_uaddr_t) object_id, object_id_len); + res = tee_mmu_check_access_rights(sess->ctx, + TEE_MEMORY_ACCESS_READ | + TEE_MEMORY_ACCESS_ANY_OWNER, + (tee_uaddr_t) object_id, + object_id_len); if (res != TEE_SUCCESS) - goto exit; + goto err; res = tee_pobj_get((void *)&sess->ctx->uuid, object_id, object_id_len, flags, &po); if (res != TEE_SUCCESS) - goto exit; + goto err; fs_flags = tee_svc_storage_conv_oflags(flags); o = calloc(1, sizeof(*o)); if (o == NULL) { res = TEE_ERROR_OUT_OF_MEMORY; - goto exit; + goto err; } o->info.handleFlags = @@ -455,22 +456,35 @@ TEE_Result tee_svc_storage_obj_open(uint32_t storage_id, void *object_id, res = tee_svc_storage_read_head(sess, o); if (res != TEE_SUCCESS) { - free(o); - goto exit; + tee_obj_add(sess->ctx, o); + if (res == TEE_ERROR_CORRUPT_OBJECT) { + EMSG("Object corrupt\n"); + res = tee_svc_storage_remove_corrupt_obj(sess, o); + if (res != TEE_SUCCESS) + goto exit; + res = TEE_ERROR_CORRUPT_OBJECT; + goto exit; + } + goto oclose; } file = tee_svc_storage_create_filename(sess, object_id, object_id_len, false); if (file == NULL) { res = TEE_ERROR_OUT_OF_MEMORY; - goto exit; + goto err; } - fd = tee_file_ops.open(file, fs_flags); - free(file); + err = tee_file_ops.access(file, TEE_FS_F_OK); + if (err) { + /* file not found */ + res = TEE_ERROR_STORAGE_NOT_AVAILABLE; + goto err; + } + + fd = tee_file_ops.open(&res, file, fs_flags); if (fd < 0) { - res = TEE_ERROR_ITEM_NOT_FOUND; - goto exit; + goto err; } o->fd = fd; @@ -478,32 +492,33 @@ TEE_Result tee_svc_storage_obj_open(uint32_t storage_id, void *object_id, res = tee_svc_copy_kaddr_to_user32(sess, obj, o); if (res != TEE_SUCCESS) - tee_obj_close(sess->ctx, o); + goto oclose; e_off = sizeof(struct tee_svc_storage_head) + o->data_size; - off = tee_file_ops.lseek(fd, e_off, TEE_FS_SEEK_SET); + off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET); if (off != e_off) { res = TEE_ERROR_NO_DATA; - goto exit; + goto oclose; } -exit: - if (res != TEE_SUCCESS) { - if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) { - /* the file is corrupt, delete */ - tee_svc_storage_remove(sess, storage_id, object_id, - object_id_len); + goto exit; - /* "greaceful" return */ - res = TEE_ERROR_ITEM_NOT_FOUND; - } +oclose: + tee_obj_close(sess->ctx, o); - if (fd >= 0) - tee_file_ops.close(fd); - if (po) - tee_pobj_release(po); - } +err: + if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) + res = TEE_ERROR_CORRUPT_OBJECT; + if (res == TEE_ERROR_CORRUPT_OBJECT) + tee_file_ops.unlink(file); + if (fd >= 0) + tee_file_ops.close(fd); + if (po) + tee_pobj_release(po); +exit: + free(file); + file = NULL; return res; } @@ -600,8 +615,8 @@ TEE_Result tee_svc_storage_obj_create(uint32_t storage_id, void *object_id, /* create temporary persistent object filename */ tmpfile = tee_svc_storage_create_filename(sess, object_id, - object_id_len, - true); + object_id_len, + true); if (tmpfile == NULL) { res = TEE_ERROR_OUT_OF_MEMORY; goto err; @@ -617,9 +632,8 @@ TEE_Result tee_svc_storage_obj_create(uint32_t storage_id, void *object_id, fs_flags = tee_svc_storage_conv_oflags(flags); - fd = tee_file_ops.open(file, fs_flags); + fd = tee_file_ops.open(&res, file, fs_flags); if (fd < 0) { - res = TEE_ERROR_ITEM_NOT_FOUND; goto err; } o->fd = fd; @@ -631,7 +645,7 @@ TEE_Result tee_svc_storage_obj_create(uint32_t storage_id, void *object_id, goto oclose; e_off = sizeof(struct tee_svc_storage_head) + o->data_size; - off = tee_file_ops.lseek(fd, e_off, TEE_FS_SEEK_SET); + off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET); if (off != e_off) { res = TEE_ERROR_NO_DATA; goto oclose; @@ -647,6 +661,10 @@ TEE_Result tee_svc_storage_obj_create(uint32_t storage_id, void *object_id, tee_file_ops.unlink(tmpfile); err: + if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) + res = TEE_ERROR_CORRUPT_OBJECT; + if (res == TEE_ERROR_CORRUPT_OBJECT) + tee_file_ops.unlink(file); if (fd >= 0) tee_file_ops.close(fd); if (po) @@ -693,11 +711,14 @@ TEE_Result tee_svc_storage_obj_del(uint32_t obj) tee_obj_close(sess->ctx, o); - /* TODO add TEE_ERROR_STORAGE_NOT_AVAILABLE implementation */ + err = tee_file_ops.access(file, TEE_FS_F_OK); + if (err) + /* file not found */ + return TEE_ERROR_STORAGE_NOT_AVAILABLE; err = tee_file_ops.unlink(file); free(file); - if (err != 0) + if (err) /* error codes needs better granularity */ return TEE_ERROR_GENERIC; @@ -734,22 +755,32 @@ TEE_Result tee_svc_storage_obj_rename(uint32_t obj, void *object_id, if (res != TEE_SUCCESS) return res; + if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { + res = TEE_ERROR_BAD_STATE; + goto exit; + } + if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) { res = TEE_ERROR_BAD_STATE; goto exit; } - if (o->pobj == NULL || o->pobj->obj_id == NULL) - return TEE_ERROR_BAD_STATE; + if (o->pobj == NULL || o->pobj->obj_id == NULL) { + res = TEE_ERROR_BAD_STATE; + goto exit; + } - res = - tee_mmu_check_access_rights(sess->ctx, + res = tee_mmu_check_access_rights(sess->ctx, TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER, (tee_uaddr_t) object_id, object_id_len); if (res != TEE_SUCCESS) goto exit; + res = tee_obj_verify(sess, o); + if (res != TEE_SUCCESS) + goto exit; + /* get new ds name */ new_file = tee_svc_storage_create_filename(sess, object_id, object_id_len, false); @@ -866,12 +897,41 @@ TEE_Result tee_svc_storage_reset_enum(uint32_t obj_enum) return TEE_SUCCESS; } +static TEE_Result tee_svc_storage_set_enum(char *d_name, struct tee_obj *o) +{ + TEE_Result res; + uint32_t blen; + uint32_t hslen; + + o->info.handleFlags = + TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; + o->info.objectUsage = TEE_USAGE_DEFAULT; + + hslen = strlen(d_name); + blen = TEE_HS2B_BBUF_SIZE(hslen); + o->pobj->obj_id = malloc(blen); + if (o->pobj->obj_id == NULL) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto exit; + } + tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen); + o->pobj->obj_id_len = blen; + + res = TEE_SUCCESS; + +exit: + return res; + +} + TEE_Result tee_svc_storage_start_enum(uint32_t obj_enum, uint32_t storage_id) { struct tee_storage_enum *e; char *dir; TEE_Result res; struct tee_ta_session *sess; + struct tee_fs_dirent *d = NULL; + struct tee_obj *o = NULL; if (obj_enum == TEE_HANDLE_NULL) return TEE_ERROR_BAD_PARAMETERS; @@ -898,7 +958,54 @@ TEE_Result tee_svc_storage_start_enum(uint32_t obj_enum, uint32_t storage_id) /* error codes needs better granularity */ return TEE_ERROR_ITEM_NOT_FOUND; - return TEE_SUCCESS; + /* verify object */ + o = calloc(1, sizeof(struct tee_obj)); + if (o == NULL) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto exit; + } + + o->pobj = calloc(1, sizeof(struct tee_pobj)); + if (!o->pobj) { + res = TEE_ERROR_OUT_OF_MEMORY; + goto exit; + } + + do { + d = tee_file_ops.readdir(e->dir); + if (d) { + res = tee_svc_storage_set_enum(d->d_name, o); + if (res != TEE_SUCCESS) + goto exit; + res = tee_obj_verify(sess, o); + if (res != TEE_SUCCESS) + goto exit; + } + } while (d); + + /* re-start */ + res = tee_file_ops.closedir(e->dir); + e->dir = NULL; + if (res != 0) + return TEE_ERROR_GENERIC; + + dir = tee_svc_storage_create_dirname(sess); + if (dir == NULL) + return TEE_ERROR_OUT_OF_MEMORY; + + e->dir = tee_file_ops.opendir(dir); + free(dir); + +exit: + if (o) { + if (o->pobj) + free(o->pobj->obj_id); + free(o->pobj); + free(o->data); + } + free(o); + + return res; } TEE_Result tee_svc_storage_next_enum(uint32_t obj_enum, TEE_ObjectInfo *info, @@ -909,42 +1016,42 @@ TEE_Result tee_svc_storage_next_enum(uint32_t obj_enum, TEE_ObjectInfo *info, TEE_Result res = TEE_SUCCESS; struct tee_ta_session *sess; struct tee_obj *o = NULL; - uint32_t blen; - uint32_t hslen; + + if (obj_enum == TEE_HANDLE_NULL) { + res = TEE_ERROR_BAD_PARAMETERS; + goto exit; + } res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - return res; - - if (obj_enum == TEE_HANDLE_NULL) - return TEE_ERROR_BAD_PARAMETERS; + goto exit; res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e); if (res != TEE_SUCCESS) - return res; + goto exit; /* check rights of the provided buffers */ - res = - tee_mmu_check_access_rights(sess->ctx, + res = tee_mmu_check_access_rights(sess->ctx, TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER, (tee_uaddr_t) info, sizeof(TEE_ObjectInfo)); if (res != TEE_SUCCESS) - return res; + goto exit; - res = - tee_mmu_check_access_rights(sess->ctx, + res = tee_mmu_check_access_rights(sess->ctx, TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER, (tee_uaddr_t) obj_id, TEE_OBJECT_ID_MAX_LEN); if (res != TEE_SUCCESS) - return res; + goto exit; d = tee_file_ops.readdir(e->dir); - if (d == NULL) - return TEE_ERROR_ITEM_NOT_FOUND; + if (d == NULL) { + res = TEE_ERROR_ITEM_NOT_FOUND; + goto exit; + } o = calloc(1, sizeof(struct tee_obj)); if (o == NULL) { @@ -958,33 +1065,22 @@ TEE_Result tee_svc_storage_next_enum(uint32_t obj_enum, TEE_ObjectInfo *info, goto exit; } - o->info.handleFlags = - TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED; - o->info.objectUsage = TEE_USAGE_DEFAULT; + res = tee_svc_storage_set_enum(d->d_name, o); + if (res != TEE_SUCCESS) + goto exit; - /* - * NOTE: Special usage of pobj due to not ref cnt should be inc - */ - hslen = strlen(d->d_name); - blen = TEE_HS2B_BBUF_SIZE(hslen); - o->pobj->obj_id = malloc(blen); - if (o->pobj->obj_id == NULL) { - res = TEE_ERROR_OUT_OF_MEMORY; + res = tee_obj_verify(sess, o); + if (res != TEE_SUCCESS) goto exit; - } - tee_hs2b((uint8_t *)d->d_name, o->pobj->obj_id, hslen, blen); - o->pobj->obj_id_len = blen; res = tee_svc_storage_read_head(sess, o); - if (res != TEE_SUCCESS) { - /* TODO: handle corrupt files in a greaceful way */ + if (res != TEE_SUCCESS) goto exit; - } + memcpy(info, &o->info, sizeof(TEE_ObjectInfo)); memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len); - res = - tee_svc_copy_to_user(sess, len, &o->pobj->obj_id_len, + res = tee_svc_copy_to_user(sess, len, &o->pobj->obj_id_len, sizeof(uint32_t)); exit: @@ -1010,32 +1106,49 @@ TEE_Result tee_svc_storage_obj_read(uint32_t obj, void *data, size_t len, res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - return res; + goto exit; res = tee_obj_get(sess->ctx, obj, &o); if (res != TEE_SUCCESS) - return res; + goto exit; - if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) - return TEE_ERROR_ACCESS_CONFLICT; + if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { + res = TEE_ERROR_BAD_STATE; + goto exit; + } + + if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) { + res = TEE_ERROR_ACCESS_CONFLICT; + goto exit; + } /* check rights of the provided buffer */ - res = - tee_mmu_check_access_rights(sess->ctx, + res = tee_mmu_check_access_rights(sess->ctx, TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER, (tee_uaddr_t) data, len); if (res != TEE_SUCCESS) - return res; + goto exit; - n_count = tee_file_ops.read(o->fd, data, len); + n_count = tee_file_ops.read(&res, o->fd, data, len); + if (n_count < 0) { + EMSG("Error code=%x\n", (uint32_t)res); + if (res == TEE_ERROR_CORRUPT_OBJECT) { + EMSG("Object corrupt\n"); + tee_svc_storage_remove_corrupt_obj(sess, o); + } + goto exit; + } u_count = (uint32_t) ((n_count < 0) ? 0 : n_count); res = tee_svc_copy_to_user(sess, count, &u_count, sizeof(uint32_t)); o->info.dataPosition += u_count; - return TEE_SUCCESS; + res = TEE_SUCCESS; + +exit: + return res; } TEE_Result tee_svc_storage_obj_write(uint32_t obj, void *data, size_t len) @@ -1047,35 +1160,40 @@ TEE_Result tee_svc_storage_obj_write(uint32_t obj, void *data, size_t len) res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - return res; + goto exit; res = tee_obj_get(sess->ctx, obj, &o); if (res != TEE_SUCCESS) - return res; + goto exit; - if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) - return TEE_ERROR_ACCESS_CONFLICT; + if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { + res = TEE_ERROR_BAD_STATE; + goto exit; + } + + if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { + res = TEE_ERROR_ACCESS_CONFLICT; + goto exit; + } /* check rights of the provided buffer */ - res = - tee_mmu_check_access_rights(sess->ctx, + res = tee_mmu_check_access_rights(sess->ctx, TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER, (tee_uaddr_t) data, len); - err = tee_file_ops.write(o->fd, data, len); + err = tee_file_ops.write(&res, o->fd, data, len); - if (err != (int)len) { - /* error codes needs better granularity */ - res = TEE_ERROR_GENERIC; - return res; - } + if (err != (int)len) + goto exit; o->info.dataPosition += len; if (o->info.dataPosition > o->info.dataSize) o->info.dataSize = o->info.dataPosition; - return TEE_SUCCESS; + res = TEE_SUCCESS; +exit: + return res; } TEE_Result tee_svc_storage_obj_trunc(uint32_t obj, size_t len) @@ -1088,23 +1206,42 @@ TEE_Result tee_svc_storage_obj_trunc(uint32_t obj, size_t len) res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - return res; + goto exit; res = tee_obj_get(sess->ctx, obj, &o); if (res != TEE_SUCCESS) - return res; + goto exit; - if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) - return TEE_ERROR_ACCESS_CONFLICT; + if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { + res = TEE_ERROR_BAD_STATE; + goto exit; + } - off = sizeof(struct tee_svc_storage_head) + o->data_size; - err = tee_file_ops.ftruncate(o->fd, len + off); + if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) { + res = TEE_ERROR_ACCESS_CONFLICT; + goto exit; + } - if (err != 0) - /* error codes needs better granularity */ - return TEE_ERROR_GENERIC; + res = tee_obj_verify(sess, o); + if (res != TEE_SUCCESS) + goto exit; - return TEE_SUCCESS; + off = sizeof(struct tee_svc_storage_head) + o->data_size; + err = tee_file_ops.ftruncate(&res, o->fd, len + off); + if (err) { + if (res == TEE_ERROR_CORRUPT_OBJECT) { + EMSG("Object corrupt\n"); + res = tee_svc_storage_remove_corrupt_obj(sess, o); + if (res != TEE_SUCCESS) + goto exit; + res = TEE_ERROR_CORRUPT_OBJECT; + goto exit; + } else + res = TEE_ERROR_GENERIC; + } + +exit: + return res; } TEE_Result tee_svc_storage_obj_seek(uint32_t obj, int32_t offset, @@ -1119,28 +1256,39 @@ TEE_Result tee_svc_storage_obj_seek(uint32_t obj, int32_t offset, res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) - return res; + goto exit; res = tee_obj_get(sess->ctx, obj, &o); if (res != TEE_SUCCESS) - return res; + goto exit; - if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) - return TEE_ERROR_BAD_STATE; + if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) { + res = TEE_ERROR_BAD_STATE; + goto exit; + } + + res = tee_obj_verify(sess, o); + if (res != TEE_SUCCESS) + goto exit; fw = tee_svc_storage_conv_whence(whence); if (whence == TEE_DATA_SEEK_SET) e_off = sizeof(struct tee_svc_storage_head) + o->data_size; - off = tee_file_ops.lseek(o->fd, e_off + offset, fw); + off = tee_file_ops.lseek(&res, o->fd, e_off + offset, fw); if (off > -1 && off >= e_off) o->info.dataPosition = off - (sizeof(struct tee_svc_storage_head) + o->data_size); - else - return TEE_ERROR_GENERIC; + else { + res = TEE_ERROR_GENERIC; + goto exit; + } - return TEE_SUCCESS; + res = TEE_SUCCESS; + +exit: + return res; } void tee_svc_storage_close_all_enum(struct tee_ta_ctx *ctx) diff --git a/lib/libutee/tee_api_objects.c b/lib/libutee/tee_api_objects.c index 86177ec0e0d..d647a5bece1 100644 --- a/lib/libutee/tee_api_objects.c +++ b/lib/libutee/tee_api_objects.c @@ -69,14 +69,9 @@ TEE_Result TEE_GetObjectInfo1(TEE_ObjectHandle object, TEE_ObjectInfo *objectInf res = utee_cryp_obj_get_info((uint32_t)object, objectInfo); - if (res == TEE_ERROR_CORRUPT_OBJECT) { - res = utee_storage_obj_del(object); - if (res != TEE_SUCCESS) - TEE_Panic(0); - return TEE_ERROR_CORRUPT_OBJECT; - } - - if (res != TEE_SUCCESS && res != TEE_ERROR_STORAGE_NOT_AVAILABLE) + if (res != TEE_SUCCESS && + res != TEE_ERROR_CORRUPT_OBJECT && + res != TEE_ERROR_STORAGE_NOT_AVAILABLE) TEE_Panic(res); return res; @@ -109,15 +104,10 @@ TEE_Result TEE_RestrictObjectUsage1(TEE_ObjectHandle object, uint32_t objectUsag res = utee_cryp_obj_restrict_usage((uint32_t)object, objectUsage); - if (res == TEE_ERROR_CORRUPT_OBJECT) { - res = utee_storage_obj_del(object); - if (res != TEE_SUCCESS) - TEE_Panic(0); - return TEE_ERROR_CORRUPT_OBJECT; - } - - if (res != TEE_SUCCESS && res != TEE_ERROR_STORAGE_NOT_AVAILABLE) - TEE_Panic(0); + if (res != TEE_SUCCESS && + res != TEE_ERROR_CORRUPT_OBJECT && + res != TEE_ERROR_STORAGE_NOT_AVAILABLE) + TEE_Panic(res); return res; } @@ -131,18 +121,18 @@ TEE_Result TEE_GetObjectBufferAttribute(TEE_ObjectHandle object, res = utee_cryp_obj_get_info((uint32_t)object, &info); if (res != TEE_SUCCESS) - TEE_Panic(0); - - if ((info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) == 0) - TEE_Panic(0); + goto exit; /* This function only supports reference attributes */ - if ((attributeID & TEE_ATTR_BIT_VALUE) != 0) - TEE_Panic(0); + if ((attributeID & TEE_ATTR_BIT_VALUE)) { + res = TEE_ERROR_BAD_PARAMETERS; + goto exit; + } res = utee_cryp_obj_get_attr((uint32_t)object, attributeID, buffer, size); +exit: if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND && res != TEE_ERROR_SHORT_BUFFER && @@ -164,18 +154,18 @@ TEE_Result TEE_GetObjectValueAttribute(TEE_ObjectHandle object, res = utee_cryp_obj_get_info((uint32_t)object, &info); if (res != TEE_SUCCESS) - TEE_Panic(0); - - if ((info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) == 0) - TEE_Panic(0); + goto exit; /* This function only supports value attributes */ - if ((attributeID & TEE_ATTR_BIT_VALUE) == 0) - TEE_Panic(0); + if (!(attributeID & TEE_ATTR_BIT_VALUE)) { + res = TEE_ERROR_BAD_PARAMETERS; + goto exit; + } res = utee_cryp_obj_get_attr((uint32_t)object, attributeID, buf, &size); +exit: if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND && res != TEE_ERROR_CORRUPT_OBJECT && @@ -344,37 +334,30 @@ TEE_Result TEE_CopyObjectAttributes1(TEE_ObjectHandle destObject, res = utee_cryp_obj_get_info((uint32_t)destObject, &dst_info); if (res != TEE_SUCCESS) - goto err; + goto exit; res = utee_cryp_obj_get_info((uint32_t)srcObject, &src_info); if (res != TEE_SUCCESS) - goto err; + goto exit; - if ((src_info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) == 0) + if (!(src_info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) TEE_Panic(0); - if ((dst_info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT) != 0) + + if ((dst_info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) TEE_Panic(0); - if ((dst_info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) != 0) + + if ((dst_info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) TEE_Panic(0); res = utee_cryp_obj_copy((uint32_t)destObject, (uint32_t)srcObject); - if (res != TEE_SUCCESS) - TEE_Panic(0); - goto out; +exit: + if (res != TEE_SUCCESS && + res != TEE_ERROR_CORRUPT_OBJECT && + res != TEE_ERROR_STORAGE_NOT_AVAILABLE) + TEE_Panic(res); -err: - if (res == TEE_ERROR_CORRUPT_OBJECT) { - res = utee_storage_obj_del(srcObject); - if (res != TEE_SUCCESS) - TEE_Panic(0); - return TEE_ERROR_CORRUPT_OBJECT; - } - if (res == TEE_ERROR_STORAGE_NOT_AVAILABLE) - return res; - TEE_Panic(0); -out: - return TEE_SUCCESS; + return res; } TEE_Result TEE_GenerateKey(TEE_ObjectHandle object, uint32_t keySize, diff --git a/ta/ta.mk b/ta/ta.mk index 553266bb899..5176de32bfe 100644 --- a/ta/ta.mk +++ b/ta/ta.mk @@ -39,6 +39,8 @@ base-prefix := incdirs-host := $(filter-out lib/libutils%, $(incdirs$(sm))) incfiles-extra-host := lib/libutils/ext/include/compiler.h incfiles-extra-host += lib/libutils/ext/include/util.h +incfiles-extra-host += $(out-dir)/core/include/generated/conf.h +incfiles-extra-host += $(out-dir)/core/conf.mk incfiles-extra-host += core/include/tee/tee_fs_key_manager.h #