diff options
Diffstat (limited to 'core/tee/tee_ree_fs.c')
-rw-r--r-- | core/tee/tee_ree_fs.c | 706 |
1 files changed, 207 insertions, 499 deletions
diff --git a/core/tee/tee_ree_fs.c b/core/tee/tee_ree_fs.c index 7a82acb..544ed3e 100644 --- a/core/tee/tee_ree_fs.c +++ b/core/tee/tee_ree_fs.c @@ -26,125 +26,45 @@ */ #include <assert.h> -#include <kernel/thread.h> #include <kernel/mutex.h> #include <kernel/panic.h> +#include <kernel/thread.h> #include <mm/core_memprot.h> #include <optee_msg_supplicant.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <string_ext.h> +#include <string.h> #include <sys/queue.h> +#include <tee/fs_htree.h> #include <tee/tee_cryp_provider.h> #include <tee/tee_fs.h> -#include <tee/tee_fs_defs.h> #include <tee/tee_fs_rpc.h> -#include <tee/tee_fs_key_manager.h> #include <trace.h> #include <utee_defines.h> #include <util.h> -/* - * This file implements the tee_file_operations structure for a secure - * filesystem based on single file in normal world. - * - * All fields in the REE file are duplicated with two versions 0 and 1. The - * active meta-data block is selected by the lowest bit in the - * meta-counter. The active file block is selected by corresponding bit - * number in struct tee_fs_file_info.backup_version_table. - * - * The atomicity of each operation is ensured by updating meta-counter when - * everything in the secondary blocks (both meta-data and file-data blocks) - * are successfully written. The main purpose of the code below is to - * perform block encryption and authentication of the file data, and - * properly handle seeking through the file. One file (in the sense of - * struct tee_file_operations) maps to one file in the REE filesystem, and - * has the following structure: - * - * [ 4 bytes meta-counter] - * [ meta-data version 0][ meta-data version 1 ] - * [ Block 0 version 0 ][ Block 0 version 1 ] - * [ Block 1 version 0 ][ Block 1 version 1 ] - * ... - * [ Block n version 0 ][ Block n version 1 ] - * - * One meta-data block is built up as: - * [ struct meta_header | struct tee_fs_get_header_size ] - * - * One data block is built up as: - * [ struct block_header | BLOCK_FILE_SIZE bytes ] - * - * struct meta_header and struct block_header are defined in - * tee_fs_key_manager.h. - * - */ - #define BLOCK_SHIFT 12 #define BLOCK_SIZE (1 << BLOCK_SHIFT) -#define MAX_FILE_SIZE (BLOCK_SIZE * NUM_BLOCKS_PER_FILE) - struct tee_fs_fd { - uint32_t meta_counter; - struct tee_fs_file_meta meta; - tee_fs_off_t pos; - uint32_t flags; - bool is_new_file; + struct tee_fs_htree *ht; int fd; }; -static inline int pos_to_block_num(int position) +static int pos_to_block_num(int position) { return position >> BLOCK_SHIFT; } -static inline int get_last_block_num(size_t size) -{ - return pos_to_block_num(size - 1); -} - -static bool get_backup_version_of_block(struct tee_fs_file_meta *meta, - size_t block_num) -{ - uint32_t index = (block_num / 32); - uint32_t block_mask = 1 << (block_num % 32); - - return !!(meta->info.backup_version_table[index] & block_mask); -} - -static inline void toggle_backup_version_of_block( - struct tee_fs_file_meta *meta, - size_t block_num) -{ - uint32_t index = (block_num / 32); - uint32_t block_mask = 1 << (block_num % 32); - - meta->info.backup_version_table[index] ^= block_mask; -} - -struct block_operations { - - /* - * Read a block from REE File System which is corresponding - * to the given block_num. - */ - struct block *(*read)(struct tee_fs_fd *fdp, int block_num); - - /* - * Write the given block to REE File System - */ - int (*write)(struct tee_fs_fd *fdp, struct block *b, - struct tee_fs_file_meta *new_meta); -}; - static struct mutex ree_fs_mutex = MUTEX_INITIALIZER; -static TEE_Result ree_fs_opendir_rpc(const char *name, struct tee_fs_dir **d) +static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid, + struct tee_fs_dir **d) { - return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name, d); + return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, uuid, d); } static void ree_fs_closedir_rpc(struct tee_fs_dir *d) @@ -159,330 +79,187 @@ static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d, return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent); } -static size_t meta_size(void) -{ - return tee_fs_get_header_size(META_FILE) + - sizeof(struct tee_fs_file_meta); -} - -static size_t meta_pos_raw(struct tee_fs_fd *fdp, bool active) -{ - size_t offs = sizeof(uint32_t); - - if ((fdp->meta_counter & 1) == active) - offs += meta_size(); - return offs; -} - -static size_t block_size_raw(void) -{ - return tee_fs_get_header_size(BLOCK_FILE) + BLOCK_SIZE; -} - -static size_t block_pos_raw(struct tee_fs_file_meta *meta, size_t block_num, - bool active) -{ - size_t n = block_num * 2; - - if (active == get_backup_version_of_block(meta, block_num)) - n++; - - return sizeof(uint32_t) + meta_size() * 2 + n * block_size_raw(); -} - -/* - * encrypted_fek: as input for META_FILE and BLOCK_FILE - */ -static TEE_Result encrypt_and_write_file(struct tee_fs_fd *fdp, - enum tee_fs_file_type file_type, size_t offs, - void *data_in, size_t data_in_size, - uint8_t *encrypted_fek) +static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos, + const void *buf, size_t len) { TEE_Result res; - struct tee_fs_rpc_operation op; - void *ciphertext; - size_t header_size = tee_fs_get_header_size(file_type); - size_t ciphertext_size = header_size + data_in_size; - + size_t start_block_num = pos_to_block_num(pos); + size_t end_block_num = pos_to_block_num(pos + len - 1); + size_t remain_bytes = len; + uint8_t *data_ptr = (uint8_t *)buf; + uint8_t *block; + struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); - res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, - offs, ciphertext_size, &ciphertext); - if (res != TEE_SUCCESS) - return res; + block = malloc(BLOCK_SIZE); + if (!block) + return TEE_ERROR_OUT_OF_MEMORY; - res = tee_fs_encrypt_file(file_type, data_in, data_in_size, - ciphertext, &ciphertext_size, encrypted_fek); - if (res != TEE_SUCCESS) - return res; + while (start_block_num <= end_block_num) { + size_t offset = pos % BLOCK_SIZE; + size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE); - return tee_fs_rpc_write_final(&op); -} + if (size_to_write + offset > BLOCK_SIZE) + size_to_write = BLOCK_SIZE - offset; -/* - * encrypted_fek: as output for META_FILE - * as input for BLOCK_FILE - */ -static TEE_Result read_and_decrypt_file(struct tee_fs_fd *fdp, - enum tee_fs_file_type file_type, size_t offs, - void *data_out, size_t *data_out_size, - uint8_t *encrypted_fek) -{ - TEE_Result res; - struct tee_fs_rpc_operation op; - size_t bytes; - void *ciphertext; + if (start_block_num * BLOCK_SIZE < + ROUNDUP(meta->length, BLOCK_SIZE)) { + res = tee_fs_htree_read_block(&fdp->ht, + start_block_num, block); + if (res != TEE_SUCCESS) + goto exit; + } else { + memset(block, 0, BLOCK_SIZE); + } - bytes = *data_out_size + tee_fs_get_header_size(file_type); - res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, offs, - bytes, &ciphertext); - if (res != TEE_SUCCESS) - return res; + if (data_ptr) + memcpy(block + offset, data_ptr, size_to_write); + else + memset(block + offset, 0, size_to_write); - res = tee_fs_rpc_read_final(&op, &bytes); - if (res != TEE_SUCCESS) - return res; + res = tee_fs_htree_write_block(&fdp->ht, start_block_num, + block); + if (res != TEE_SUCCESS) + goto exit; - if (!bytes) { - *data_out_size = 0; - return TEE_SUCCESS; + if (data_ptr) + data_ptr += size_to_write; + remain_bytes -= size_to_write; + start_block_num++; + pos += size_to_write; } - res = tee_fs_decrypt_file(file_type, ciphertext, bytes, data_out, - data_out_size, encrypted_fek); - if (res != TEE_SUCCESS) - return TEE_ERROR_CORRUPT_OBJECT; - return TEE_SUCCESS; -} - -static TEE_Result write_meta_file(struct tee_fs_fd *fdp, - struct tee_fs_file_meta *meta) -{ - size_t offs = meta_pos_raw(fdp, false); - - return encrypt_and_write_file(fdp, META_FILE, offs, - (void *)&meta->info, sizeof(meta->info), - meta->encrypted_fek); -} + if (pos > meta->length) + meta->length = pos; -static TEE_Result write_meta_counter(struct tee_fs_fd *fdp) -{ - TEE_Result res; - struct tee_fs_rpc_operation op; - size_t bytes = sizeof(uint32_t); - void *data; - - res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0, - bytes, &data); - if (res != TEE_SUCCESS) - return res; - - memcpy(data, &fdp->meta_counter, bytes); - - return tee_fs_rpc_write_final(&op); -} - -static TEE_Result create_meta(struct tee_fs_fd *fdp, const char *fname) -{ - TEE_Result res; - - memset(fdp->meta.info.backup_version_table, 0xff, - sizeof(fdp->meta.info.backup_version_table)); - fdp->meta.info.length = 0; - - res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE); - if (res != TEE_SUCCESS) - return res; - - res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd); - if (res != TEE_SUCCESS) - return res; - - fdp->meta.counter = fdp->meta_counter; - - res = write_meta_file(fdp, &fdp->meta); - if (res != TEE_SUCCESS) - return res; - return write_meta_counter(fdp); +exit: + free(block); + return res; } -static TEE_Result commit_meta_file(struct tee_fs_fd *fdp, - struct tee_fs_file_meta *new_meta) +static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx, + uint8_t vers, size_t *offs, size_t *size) { - TEE_Result res; - - new_meta->counter = fdp->meta_counter + 1; + const size_t node_size = sizeof(struct tee_fs_htree_node_image); + const size_t block_nodes = BLOCK_SIZE / (node_size * 2); + size_t pbn; + size_t bidx; - res = write_meta_file(fdp, new_meta); - if (res != TEE_SUCCESS) - return res; + assert(vers == 0 || vers == 1); /* - * From now on the new meta is successfully committed, - * change tee_fs_fd accordingly + * File layout + * + * phys block 0: + * tee_fs_htree_image vers 0 @ offs = 0 + * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image) + * + * phys block 1: + * tee_fs_htree_node_image 0 vers 0 @ offs = 0 + * tee_fs_htree_node_image 0 vers 1 @ offs = node_size + * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2 + * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3 + * ... + * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122 + * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123 + * + * phys block 2: + * data block 0 vers 0 + * + * phys block 3: + * data block 0 vers 1 + * + * ... + * phys block 63: + * data block 61 vers 0 + * + * phys block 64: + * data block 61 vers 1 + * + * phys block 65: + * tee_fs_htree_node_image 62 vers 0 @ offs = 0 + * tee_fs_htree_node_image 62 vers 1 @ offs = node_size + * tee_fs_htree_node_image 63 vers 0 @ offs = node_size * 2 + * tee_fs_htree_node_image 63 vers 1 @ offs = node_size * 3 + * ... + * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122 + * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123 + * + * ... */ - fdp->meta = *new_meta; - fdp->meta_counter = fdp->meta.counter; - return write_meta_counter(fdp); -} - -static TEE_Result read_meta_file(struct tee_fs_fd *fdp, - struct tee_fs_file_meta *meta) -{ - size_t meta_info_size = sizeof(struct tee_fs_file_info); - size_t offs = meta_pos_raw(fdp, true); - - return read_and_decrypt_file(fdp, META_FILE, offs, - &meta->info, &meta_info_size, - meta->encrypted_fek); + switch (type) { + case TEE_FS_HTREE_TYPE_HEAD: + *offs = sizeof(struct tee_fs_htree_image) * vers; + *size = sizeof(struct tee_fs_htree_image); + return TEE_SUCCESS; + case TEE_FS_HTREE_TYPE_NODE: + pbn = 1 + ((idx / block_nodes) * block_nodes * 2); + *offs = pbn * BLOCK_SIZE + + 2 * node_size * (idx % block_nodes) + + node_size * vers; + *size = node_size; + return TEE_SUCCESS; + case TEE_FS_HTREE_TYPE_BLOCK: + bidx = 2 * idx + vers; + pbn = 2 + bidx + bidx / (block_nodes * 2 - 1); + *offs = pbn * BLOCK_SIZE; + *size = BLOCK_SIZE; + return TEE_SUCCESS; + default: + return TEE_ERROR_GENERIC; + } } -static TEE_Result read_meta_counter(struct tee_fs_fd *fdp) +static TEE_Result ree_fs_rpc_read_init(void *aux, + struct tee_fs_rpc_operation *op, + enum tee_fs_htree_type type, size_t idx, + uint8_t vers, void **data) { + struct tee_fs_fd *fdp = aux; TEE_Result res; - struct tee_fs_rpc_operation op; - void *data; - size_t bytes = sizeof(uint32_t); - - res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0, - bytes, &data); - if (res != TEE_SUCCESS) - return res; + size_t offs; + size_t size; - res = tee_fs_rpc_read_final(&op, &bytes); + res = get_offs_size(type, idx, vers, &offs, &size); if (res != TEE_SUCCESS) return res; - if (bytes != sizeof(uint32_t)) - return TEE_ERROR_CORRUPT_OBJECT; - - memcpy(&fdp->meta_counter, data, bytes); - - return TEE_SUCCESS; + return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, + offs, size, data); } -static TEE_Result read_meta(struct tee_fs_fd *fdp, const char *fname) +static TEE_Result ree_fs_rpc_write_init(void *aux, + struct tee_fs_rpc_operation *op, + enum tee_fs_htree_type type, size_t idx, + uint8_t vers, void **data) { + struct tee_fs_fd *fdp = aux; TEE_Result res; + size_t offs; + size_t size; - res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd); - if (res != TEE_SUCCESS) - return res; - - res = read_meta_counter(fdp); - if (res != TEE_SUCCESS) - return res; - - return read_meta_file(fdp, &fdp->meta); -} - -static TEE_Result read_block(struct tee_fs_fd *fdp, int bnum, uint8_t *data) -{ - TEE_Result res; - size_t ct_size = block_size_raw(); - size_t out_size = BLOCK_SIZE; - ssize_t pos = block_pos_raw(&fdp->meta, bnum, true); - size_t bytes; - void *ct; - struct tee_fs_rpc_operation op; - - res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, pos, - ct_size, &ct); - if (res != TEE_SUCCESS) - return res; - res = tee_fs_rpc_read_final(&op, &bytes); + res = get_offs_size(type, idx, vers, &offs, &size); if (res != TEE_SUCCESS) return res; - if (!bytes) { - memset(data, 0, BLOCK_SIZE); - return TEE_SUCCESS; /* Block does not exist */ - } - return tee_fs_decrypt_file(BLOCK_FILE, ct, bytes, data, - &out_size, fdp->meta.encrypted_fek); + return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, + offs, size, data); } -static TEE_Result write_block(struct tee_fs_fd *fdp, size_t bnum, uint8_t *data, - struct tee_fs_file_meta *new_meta) -{ - TEE_Result res; - size_t offs = block_pos_raw(new_meta, bnum, false); - - res = encrypt_and_write_file(fdp, BLOCK_FILE, offs, data, - BLOCK_SIZE, new_meta->encrypted_fek); - if (res == TEE_SUCCESS) - toggle_backup_version_of_block(new_meta, bnum); - return res; -} - -static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, const void *buf, - size_t len, struct tee_fs_file_meta *new_meta) -{ - TEE_Result res; - int start_block_num = pos_to_block_num(fdp->pos); - int end_block_num = pos_to_block_num(fdp->pos + len - 1); - size_t remain_bytes = len; - uint8_t *data_ptr = (uint8_t *)buf; - uint8_t *block; - int orig_pos = fdp->pos; - - block = malloc(BLOCK_SIZE); - if (!block) - return TEE_ERROR_OUT_OF_MEMORY; - - while (start_block_num <= end_block_num) { - int offset = fdp->pos % BLOCK_SIZE; - size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE); - - if (size_to_write + offset > BLOCK_SIZE) - size_to_write = BLOCK_SIZE - offset; - - res = read_block(fdp, start_block_num, block); - if (res == TEE_ERROR_ITEM_NOT_FOUND) - memset(block, 0, BLOCK_SIZE); - else if (res != TEE_SUCCESS) - goto exit; - - if (data_ptr) - memcpy(block + offset, data_ptr, size_to_write); - else - memset(block + offset, 0, size_to_write); - - res = write_block(fdp, start_block_num, block, new_meta); - if (res != TEE_SUCCESS) - goto exit; - - if (data_ptr) - data_ptr += size_to_write; - remain_bytes -= size_to_write; - start_block_num++; - fdp->pos += size_to_write; - } - - if (fdp->pos > (tee_fs_off_t)new_meta->info.length) - new_meta->info.length = fdp->pos; - -exit: - free(block); - if (res != TEE_SUCCESS) - fdp->pos = orig_pos; - return res; -} +static const struct tee_fs_htree_storage ree_fs_storage_ops = { + .block_size = BLOCK_SIZE, + .rpc_read_init = ree_fs_rpc_read_init, + .rpc_read_final = tee_fs_rpc_read_final, + .rpc_write_init = ree_fs_rpc_write_init, + .rpc_write_final = tee_fs_rpc_write_final, +}; -static TEE_Result open_internal(const char *file, bool create, +static TEE_Result open_internal(struct tee_pobj *po, bool create, struct tee_file_handle **fh) { TEE_Result res; - size_t len; struct tee_fs_fd *fdp = NULL; - if (!file) - return TEE_ERROR_BAD_PARAMETERS; - - len = strlen(file) + 1; - if (len > TEE_FS_NAME_MAX) - return TEE_ERROR_BAD_PARAMETERS; - fdp = calloc(1, sizeof(struct tee_fs_fd)); if (!fdp) return TEE_ERROR_OUT_OF_MEMORY; @@ -491,17 +268,22 @@ static TEE_Result open_internal(const char *file, bool create, mutex_lock(&ree_fs_mutex); if (create) - res = create_meta(fdp, file); + res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd); else - res = read_meta(fdp, file); + res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd); + + if (res != TEE_SUCCESS) + goto out; + res = tee_fs_htree_open(create, &ree_fs_storage_ops, fdp, &fdp->ht); +out: if (res == TEE_SUCCESS) { *fh = (struct tee_file_handle *)fdp; } else { if (fdp->fd != -1) tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); if (create) - tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file); + tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po); free(fdp); } @@ -509,14 +291,15 @@ static TEE_Result open_internal(const char *file, bool create, return res; } -static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh) +static TEE_Result ree_fs_open(struct tee_pobj *po, struct tee_file_handle **fh) { - return open_internal(file, false, fh); + return open_internal(po, false, fh); } -static TEE_Result ree_fs_create(const char *file, struct tee_file_handle **fh) +static TEE_Result ree_fs_create(struct tee_pobj *po, + struct tee_file_handle **fh) { - return open_internal(file, true, fh); + return open_internal(po, true, fh); } static void ree_fs_close(struct tee_file_handle **fh) @@ -524,106 +307,53 @@ static void ree_fs_close(struct tee_file_handle **fh) struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh; if (fdp) { + tee_fs_htree_close(&fdp->ht); tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd); free(fdp); *fh = NULL; } } -static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset, - TEE_Whence whence, int32_t *new_offs) -{ - TEE_Result res; - tee_fs_off_t new_pos; - size_t filelen; - struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; - - mutex_lock(&ree_fs_mutex); - - DMSG("offset=%d, whence=%d", (int)offset, whence); - - filelen = fdp->meta.info.length; - - switch (whence) { - case TEE_DATA_SEEK_SET: - new_pos = offset; - break; - - case TEE_DATA_SEEK_CUR: - new_pos = fdp->pos + offset; - break; - - case TEE_DATA_SEEK_END: - new_pos = filelen + offset; - break; - - default: - res = TEE_ERROR_BAD_PARAMETERS; - goto exit; - } - - if (new_pos < 0) - new_pos = 0; - - if (new_pos > TEE_DATA_MAX_POSITION) { - EMSG("Position is beyond TEE_DATA_MAX_POSITION"); - res = TEE_ERROR_BAD_PARAMETERS; - goto exit; - } - - fdp->pos = new_pos; - if (new_offs) - *new_offs = new_pos; - res = TEE_SUCCESS; -exit: - mutex_unlock(&ree_fs_mutex); - return res; -} - -/* - * To ensure atomic truncate operation, we can: - * - * - update file length to new length - * - commit new meta - * - * To ensure atomic extend operation, we can: - * - * - update file length to new length - * - allocate and fill zero data to new blocks - * - commit new meta - * - * Any failure before committing new meta is considered as - * update failed, and the file content will not be updated - */ static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp, tee_fs_off_t new_file_len) { TEE_Result res; - size_t old_file_len = fdp->meta.info.length; - struct tee_fs_file_meta new_meta; + struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); - if (new_file_len > MAX_FILE_SIZE) - return TEE_ERROR_BAD_PARAMETERS; + if ((size_t)new_file_len > meta->length) { + size_t ext_len = new_file_len - meta->length; - new_meta = fdp->meta; - new_meta.info.length = new_file_len; + res = out_of_place_write(fdp, meta->length, NULL, ext_len); + if (res != TEE_SUCCESS) + return res; + } else { + size_t offs; + size_t sz; + + res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK, + ROUNDUP(new_file_len, BLOCK_SIZE) / + BLOCK_SIZE, 1, &offs, &sz); + if (res != TEE_SUCCESS) + return res; - if ((size_t)new_file_len > old_file_len) { - size_t ext_len = new_file_len - old_file_len; - int orig_pos = fdp->pos; + res = tee_fs_htree_truncate(&fdp->ht, + new_file_len / BLOCK_SIZE); + if (res != TEE_SUCCESS) + return res; - fdp->pos = old_file_len; - res = out_of_place_write(fdp, NULL, ext_len, &new_meta); - fdp->pos = orig_pos; + res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd, + offs + sz); if (res != TEE_SUCCESS) return res; + + meta->length = new_file_len; } - return commit_meta_file(fdp, &new_meta); + return tee_fs_htree_sync_to_storage(&fdp->ht); } -static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf, - size_t *len) +static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos, + void *buf, size_t *len) { TEE_Result res; int start_block_num; @@ -632,16 +362,15 @@ static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf, uint8_t *data_ptr = buf; uint8_t *block = NULL; struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; + struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht); mutex_lock(&ree_fs_mutex); remain_bytes = *len; - if ((fdp->pos + remain_bytes) < remain_bytes || - fdp->pos > (tee_fs_off_t)fdp->meta.info.length) + if ((pos + remain_bytes) < remain_bytes || pos > meta->length) remain_bytes = 0; - else if (fdp->pos + (tee_fs_off_t)remain_bytes > - (tee_fs_off_t)fdp->meta.info.length) - remain_bytes = fdp->meta.info.length - fdp->pos; + else if (pos + remain_bytes > meta->length) + remain_bytes = meta->length - pos; *len = remain_bytes; @@ -650,8 +379,8 @@ static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf, goto exit; } - start_block_num = pos_to_block_num(fdp->pos); - end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1); + start_block_num = pos_to_block_num(pos); + end_block_num = pos_to_block_num(pos + remain_bytes - 1); block = malloc(BLOCK_SIZE); if (!block) { @@ -660,24 +389,21 @@ static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf, } while (start_block_num <= end_block_num) { - tee_fs_off_t offset = fdp->pos % BLOCK_SIZE; + size_t offset = pos % BLOCK_SIZE; size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); if (size_to_read + offset > BLOCK_SIZE) size_to_read = BLOCK_SIZE - offset; - res = read_block(fdp, start_block_num, block); - if (res != TEE_SUCCESS) { - if (res == TEE_ERROR_MAC_INVALID) - res = TEE_ERROR_CORRUPT_OBJECT; + res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block); + if (res != TEE_SUCCESS) goto exit; - } memcpy(data_ptr, block + offset, size_to_read); data_ptr += size_to_read; remain_bytes -= size_to_read; - fdp->pos += size_to_read; + pos += size_to_read; start_block_num++; } @@ -688,27 +414,10 @@ exit: return res; } -/* - * To ensure atomicity of write operation, we need to - * do the following steps: - * (The sequence of operations is very important) - * - * - Create a new backup version of meta file as a copy - * of current meta file. - * - For each blocks to write: - * - Create new backup version for current block. - * - Write data to new backup version. - * - Update the new meta file accordingly. - * - Write the new meta file. - * - * (Any failure in above steps is considered as update failed, - * and the file content will not be updated) - */ -static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf, - size_t len) +static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos, + const void *buf, size_t len) { TEE_Result res; - struct tee_fs_file_meta new_meta; struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh; size_t file_size; @@ -717,31 +426,31 @@ static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf, mutex_lock(&ree_fs_mutex); - file_size = fdp->meta.info.length; + file_size = tee_fs_htree_get_meta(fdp->ht)->length; - if ((fdp->pos + len) > MAX_FILE_SIZE || (fdp->pos + len) < len) { + if ((pos + len) < len) { res = TEE_ERROR_BAD_PARAMETERS; goto exit; } - if (file_size < (size_t)fdp->pos) { - res = ree_fs_ftruncate_internal(fdp, fdp->pos); + if (file_size < pos) { + res = ree_fs_ftruncate_internal(fdp, pos); if (res != TEE_SUCCESS) goto exit; } - new_meta = fdp->meta; - res = out_of_place_write(fdp, buf, len, &new_meta); + res = out_of_place_write(fdp, pos, buf, len); if (res != TEE_SUCCESS) goto exit; - res = commit_meta_file(fdp, &new_meta); exit: + if (res == TEE_SUCCESS) + res = tee_fs_htree_sync_to_storage(&fdp->ht); mutex_unlock(&ree_fs_mutex); return res; } -static TEE_Result ree_fs_rename(const char *old, const char *new, +static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new, bool overwrite) { TEE_Result res; @@ -753,12 +462,12 @@ static TEE_Result ree_fs_rename(const char *old, const char *new, return res; } -static TEE_Result ree_fs_remove(const char *file) +static TEE_Result ree_fs_remove(struct tee_pobj *po) { TEE_Result res; mutex_lock(&ree_fs_mutex); - res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file); + res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po); mutex_unlock(&ree_fs_mutex); return res; @@ -782,7 +491,6 @@ const struct tee_file_operations ree_fs_ops = { .close = ree_fs_close, .read = ree_fs_read, .write = ree_fs_write, - .seek = ree_fs_seek, .truncate = ree_fs_truncate, .rename = ree_fs_rename, .remove = ree_fs_remove, |