summaryrefslogtreecommitdiff
path: root/core/tee
diff options
context:
space:
mode:
Diffstat (limited to 'core/tee')
-rw-r--r--core/tee/fs_htree.c937
-rw-r--r--core/tee/sub.mk2
-rw-r--r--core/tee/tee_cryp_utl.c7
-rw-r--r--core/tee/tee_fs_key_manager.c232
-rw-r--r--core/tee/tee_fs_rpc.c95
-rw-r--r--core/tee/tee_obj.c17
-rw-r--r--core/tee/tee_pobj.c14
-rw-r--r--core/tee/tee_ree_fs.c706
-rw-r--r--core/tee/tee_rpmb_fs.c205
-rw-r--r--core/tee/tee_sql_fs.c419
-rw-r--r--core/tee/tee_svc_storage.c346
11 files changed, 1568 insertions, 1412 deletions
diff --git a/core/tee/fs_htree.c b/core/tee/fs_htree.c
new file mode 100644
index 0000000..53cb81e
--- /dev/null
+++ b/core/tee/fs_htree.c
@@ -0,0 +1,937 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <initcall.h>
+#include <kernel/tee_common_otp.h>
+#include <optee_msg_supplicant.h>
+#include <stdlib.h>
+#include <string_ext.h>
+#include <string.h>
+#include <tee/fs_htree.h>
+#include <tee/tee_cryp_provider.h>
+#include <tee/tee_fs_key_manager.h>
+#include <tee/tee_fs_rpc.h>
+#include <utee_defines.h>
+#include <util.h>
+
+#define TEE_FS_HTREE_CHIP_ID_SIZE 32
+#define TEE_FS_HTREE_HASH_ALG TEE_ALG_SHA256
+#define TEE_FS_HTREE_TSK_SIZE TEE_FS_HTREE_HASH_SIZE
+#define TEE_FS_HTREE_ENC_ALG TEE_ALG_AES_ECB_NOPAD
+#define TEE_FS_HTREE_ENC_SIZE TEE_AES_BLOCK_SIZE
+#define TEE_FS_HTREE_SSK_SIZE TEE_FS_HTREE_HASH_SIZE
+
+#define TEE_FS_HTREE_AUTH_ENC_ALG TEE_ALG_AES_GCM
+#define TEE_FS_HTREE_HMAC_ALG TEE_ALG_HMAC_SHA256
+
+#define BLOCK_NUM_TO_NODE_ID(num) ((num) + 1)
+
+#define NODE_ID_TO_BLOCK_NUM(id) ((id) - 1)
+
+/*
+ * The hash tree is implemented as a binary tree with the purpose to ensure
+ * integrity of the data in the nodes. The data in the nodes their turn
+ * provides both integrity and confidentiality of the data blocks.
+ *
+ * The hash tree is saved in a file as:
+ * +----------------------------+
+ * | htree_image.0 |
+ * | htree_image.1 |
+ * +----------------------------+
+ * | htree_node_image.1.0 |
+ * | htree_node_image.1.1 |
+ * +----------------------------+
+ * | htree_node_image.2.0 |
+ * | htree_node_image.2.1 |
+ * +----------------------------+
+ * | htree_node_image.3.0 |
+ * | htree_node_image.3.1 |
+ * +----------------------------+
+ * | htree_node_image.4.0 |
+ * | htree_node_image.4.1 |
+ * +----------------------------+
+ * ...
+ *
+ * htree_image is the header of the file, there's two instances of it. One
+ * which is committed and the other is used when updating the file. Which
+ * is committed is indicated by the "counter" field, the one with the
+ * largest value is selected.
+ *
+ * htree_node_image is a node in the hash tree, each node has two instances
+ * which is committed is decided by the parent node .flag bit
+ * HTREE_NODE_COMMITTED_CHILD. Which version is the committed version of
+ * node 1 is determined by the by the lowest bit of the counter field in
+ * the header.
+ *
+ * Note that nodes start counting at 1 while blocks at 0, this means that
+ * block 0 is represented by node 1.
+ *
+ * Where different elements are stored in the file is managed by the file
+ * system. In the case of SQL FS the version of the node/block is ignored
+ * as the atomic update is finalized with a call to
+ * tee_fs_rpc_end_transaction().
+ */
+
+#define HTREE_NODE_COMMITTED_BLOCK BIT32(0)
+/* n is 0 or 1 */
+#define HTREE_NODE_COMMITTED_CHILD(n) BIT32(1 + (n))
+
+struct htree_node {
+ size_t id;
+ bool dirty;
+ bool block_updated;
+ struct tee_fs_htree_node_image node;
+ struct htree_node *parent;
+ struct htree_node *child[2];
+};
+
+struct tee_fs_htree {
+ struct htree_node root;
+ struct tee_fs_htree_image head;
+ uint8_t fek[TEE_FS_HTREE_FEK_SIZE];
+ struct tee_fs_htree_imeta imeta;
+ bool dirty;
+ const struct tee_fs_htree_storage *stor;
+ void *stor_aux;
+};
+
+struct traverse_arg;
+typedef TEE_Result (*traverse_cb_t)(struct traverse_arg *targ,
+ struct htree_node *node);
+struct traverse_arg {
+ struct tee_fs_htree *ht;
+ traverse_cb_t cb;
+ void *arg;
+};
+
+static TEE_Result rpc_read(struct tee_fs_htree *ht, enum tee_fs_htree_type type,
+ size_t idx, size_t vers, void *data, size_t dlen)
+{
+ TEE_Result res;
+ struct tee_fs_rpc_operation op;
+ size_t bytes;
+ void *p;
+
+ res = ht->stor->rpc_read_init(ht->stor_aux, &op, type, idx, vers, &p);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ res = ht->stor->rpc_read_final(&op, &bytes);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ if (bytes != dlen)
+ return TEE_ERROR_CORRUPT_OBJECT;
+
+ memcpy(data, p, dlen);
+ return TEE_SUCCESS;
+}
+
+static TEE_Result rpc_read_head(struct tee_fs_htree *ht, size_t vers,
+ struct tee_fs_htree_image *head)
+{
+ return rpc_read(ht, TEE_FS_HTREE_TYPE_HEAD, 0, vers,
+ head, sizeof(*head));
+}
+
+static TEE_Result rpc_read_node(struct tee_fs_htree *ht, size_t node_id,
+ size_t vers,
+ struct tee_fs_htree_node_image *node)
+{
+ return rpc_read(ht, TEE_FS_HTREE_TYPE_NODE, node_id - 1, vers,
+ node, sizeof(*node));
+}
+
+static TEE_Result rpc_write(struct tee_fs_htree *ht,
+ enum tee_fs_htree_type type, size_t idx,
+ size_t vers, const void *data, size_t dlen)
+{
+ TEE_Result res;
+ struct tee_fs_rpc_operation op;
+ void *p;
+
+ res = ht->stor->rpc_write_init(ht->stor_aux, &op, type, idx, vers, &p);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ memcpy(p, data, dlen);
+ return ht->stor->rpc_write_final(&op);
+}
+
+static TEE_Result rpc_write_head(struct tee_fs_htree *ht, size_t vers,
+ const struct tee_fs_htree_image *head)
+{
+ return rpc_write(ht, TEE_FS_HTREE_TYPE_HEAD, 0, vers,
+ head, sizeof(*head));
+}
+
+static TEE_Result rpc_write_node(struct tee_fs_htree *ht, size_t node_id,
+ size_t vers,
+ const struct tee_fs_htree_node_image *node)
+{
+ return rpc_write(ht, TEE_FS_HTREE_TYPE_NODE, node_id - 1, vers,
+ node, sizeof(*node));
+}
+
+static TEE_Result traverse_post_order(struct traverse_arg *targ,
+ struct htree_node *node)
+{
+ TEE_Result res;
+
+ /*
+ * This function is recursing but not very deep, only with Log(N)
+ * maximum depth.
+ */
+
+ if (!node)
+ return TEE_SUCCESS;
+
+ res = traverse_post_order(targ, node->child[0]);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ res = traverse_post_order(targ, node->child[1]);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ return targ->cb(targ, node);
+}
+
+static TEE_Result htree_traverse_post_order(struct tee_fs_htree *ht,
+ traverse_cb_t cb, void *arg)
+{
+ struct traverse_arg targ = { ht, cb, arg };
+
+ return traverse_post_order(&targ, &ht->root);
+}
+
+static size_t node_id_to_level(size_t node_id)
+{
+ assert(node_id && node_id < UINT_MAX);
+ /* Calculate level of the node, root node (1) has level 1 */
+ return sizeof(unsigned int) * 8 - __builtin_clz(node_id);
+}
+
+static struct htree_node *find_closest_node(struct tee_fs_htree *ht,
+ size_t node_id)
+{
+ struct htree_node *node = &ht->root;
+ size_t level = node_id_to_level(node_id);
+ size_t n;
+
+ /* n = 1 because root node is level 1 */
+ for (n = 1; n < level; n++) {
+ struct htree_node *child;
+ size_t bit_idx;
+
+ /*
+ * The difference between levels of the current node and
+ * the node we're looking for tells which bit decides
+ * direction in the tree.
+ *
+ * As the first bit has index 0 we'll subtract 1
+ */
+ bit_idx = level - n - 1;
+ child = node->child[((node_id >> bit_idx) & 1)];
+ if (!child)
+ return node;
+ node = child;
+ }
+
+ return node;
+}
+
+static struct htree_node *find_node(struct tee_fs_htree *ht, size_t node_id)
+{
+ struct htree_node *node = find_closest_node(ht, node_id);
+
+ if (node && node->id == node_id)
+ return node;
+ return NULL;
+}
+
+static TEE_Result get_node(struct tee_fs_htree *ht, bool create,
+ size_t node_id, struct htree_node **node_ret)
+{
+ struct htree_node *node;
+ struct htree_node *nc;
+ size_t n;
+
+ node = find_closest_node(ht, node_id);
+ if (!node)
+ return TEE_ERROR_GENERIC;
+ if (node->id == node_id)
+ goto ret_node;
+
+ /*
+ * Trying to read beyond end of file should be caught earlier than
+ * here.
+ */
+ if (!create)
+ return TEE_ERROR_GENERIC;
+
+ /*
+ * Add missing nodes, some nodes may already be there. When we've
+ * processed the range all nodes up to node_id will be in the tree.
+ */
+ for (n = node->id + 1; n <= node_id; n++) {
+ node = find_closest_node(ht, n);
+ if (node->id == n)
+ continue;
+ /* Node id n should be a child of node */
+ assert((n >> 1) == node->id);
+ assert(!node->child[n & 1]);
+
+ nc = calloc(1, sizeof(*nc));
+ if (!nc)
+ return TEE_ERROR_OUT_OF_MEMORY;
+ nc->id = n;
+ nc->parent = node;
+ node->child[n & 1] = nc;
+ node = nc;
+ }
+
+ if (node->id > ht->imeta.max_node_id)
+ ht->imeta.max_node_id = node->id;
+
+ret_node:
+ *node_ret = node;
+ return TEE_SUCCESS;
+}
+
+static int get_idx_from_counter(uint32_t counter0, uint32_t counter1)
+{
+ if (!(counter0 & 1)) {
+ if (!(counter1 & 1))
+ return 0;
+ if (counter0 > counter1)
+ return 0;
+ else
+ return 1;
+ }
+
+ if (counter1 & 1)
+ return 1;
+ else
+ return -1;
+}
+
+static TEE_Result init_head_from_data(struct tee_fs_htree *ht)
+{
+ TEE_Result res;
+ struct tee_fs_htree_image head[2];
+ int idx;
+
+ for (idx = 0; idx < 2; idx++) {
+ res = rpc_read_head(ht, idx, head + idx);
+ if (res != TEE_SUCCESS)
+ return res;
+ }
+
+ idx = get_idx_from_counter(head[0].counter, head[1].counter);
+ if (idx < 0)
+ return TEE_ERROR_SECURITY;
+
+ res = rpc_read_node(ht, 1, idx, &ht->root.node);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ ht->head = head[idx];
+ ht->root.id = 1;
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result init_tree_from_data(struct tee_fs_htree *ht)
+{
+ TEE_Result res;
+ struct tee_fs_htree_node_image node_image;
+ struct htree_node *node;
+ struct htree_node *nc;
+ size_t committed_version;
+ size_t node_id = 2;
+
+ while (node_id <= ht->imeta.max_node_id) {
+ node = find_node(ht, node_id >> 1);
+ if (!node)
+ return TEE_ERROR_GENERIC;
+ committed_version = !!(node->node.flags &
+ HTREE_NODE_COMMITTED_CHILD(node_id & 1));
+
+ res = rpc_read_node(ht, node_id, committed_version,
+ &node_image);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ res = get_node(ht, true, node_id, &nc);
+ if (res != TEE_SUCCESS)
+ return res;
+ nc->node = node_image;
+ node_id++;
+ }
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result calc_node_hash(struct htree_node *node, void *ctx,
+ uint8_t *digest)
+{
+ TEE_Result res;
+ uint32_t alg = TEE_FS_HTREE_HASH_ALG;
+ uint8_t *ndata = (uint8_t *)&node->node + sizeof(node->node.hash);
+ size_t nsize = sizeof(node->node) - sizeof(node->node.hash);
+
+ res = crypto_ops.hash.init(ctx, alg);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ res = crypto_ops.hash.update(ctx, alg, ndata, nsize);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ if (node->child[0]) {
+ res = crypto_ops.hash.update(ctx, alg,
+ node->child[0]->node.hash,
+ sizeof(node->child[0]->node.hash));
+ if (res != TEE_SUCCESS)
+ return res;
+ }
+
+ if (node->child[1]) {
+ res = crypto_ops.hash.update(ctx, alg,
+ node->child[1]->node.hash,
+ sizeof(node->child[1]->node.hash));
+ if (res != TEE_SUCCESS)
+ return res;
+ }
+
+ return crypto_ops.hash.final(ctx, alg, digest, TEE_FS_HTREE_HASH_SIZE);
+}
+
+static TEE_Result authenc_init(void **ctx_ret, TEE_OperationMode mode,
+ struct tee_fs_htree *ht,
+ struct tee_fs_htree_node_image *ni,
+ size_t payload_len)
+{
+ TEE_Result res = TEE_SUCCESS;
+ const uint32_t alg = TEE_FS_HTREE_AUTH_ENC_ALG;
+ uint8_t *ctx;
+ size_t ctx_size;
+ size_t aad_len = TEE_FS_HTREE_FEK_SIZE + TEE_FS_HTREE_IV_SIZE;
+ uint8_t *iv;
+
+ if (ni) {
+ iv = ni->iv;
+ } else {
+ iv = ht->head.iv;
+ aad_len += TEE_FS_HTREE_HASH_SIZE + sizeof(ht->head.counter);
+ }
+
+ if (mode == TEE_MODE_ENCRYPT) {
+ res = crypto_ops.prng.read(iv, TEE_FS_HTREE_IV_SIZE);
+ if (res != TEE_SUCCESS)
+ return res;
+ }
+
+ res = crypto_ops.authenc.get_ctx_size(alg, &ctx_size);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ ctx = malloc(ctx_size);
+ if (!ctx) {
+ EMSG("request memory size %zu failed", ctx_size);
+ return TEE_ERROR_OUT_OF_MEMORY;
+ }
+
+ res = crypto_ops.authenc.init(ctx, alg, mode,
+ ht->fek, TEE_FS_HTREE_FEK_SIZE,
+ iv, TEE_FS_HTREE_IV_SIZE,
+ TEE_FS_HTREE_TAG_SIZE, aad_len,
+ payload_len);
+ if (res != TEE_SUCCESS)
+ goto exit;
+
+ if (!ni) {
+ res = crypto_ops.authenc.update_aad(ctx, alg, mode,
+ ht->root.node.hash,
+ TEE_FS_HTREE_FEK_SIZE);
+ if (res != TEE_SUCCESS)
+ goto exit;
+
+ res = crypto_ops.authenc.update_aad(ctx, alg, mode,
+ (void *)&ht->head.counter,
+ sizeof(ht->head.counter));
+ if (res != TEE_SUCCESS)
+ goto exit;
+ }
+
+ res = crypto_ops.authenc.update_aad(ctx, alg, mode, ht->head.enc_fek,
+ TEE_FS_HTREE_FEK_SIZE);
+ if (res != TEE_SUCCESS)
+ goto exit;
+
+ res = crypto_ops.authenc.update_aad(ctx, alg, mode, iv,
+ TEE_FS_HTREE_IV_SIZE);
+
+exit:
+ if (res == TEE_SUCCESS)
+ *ctx_ret = ctx;
+ else
+ free(ctx);
+
+ return res;
+}
+
+static TEE_Result authenc_decrypt_final(void *ctx, const uint8_t *tag,
+ const void *crypt, size_t len,
+ void *plain)
+{
+ TEE_Result res;
+ size_t out_size = len;
+
+ res = crypto_ops.authenc.dec_final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG,
+ crypt, len, plain, &out_size,
+ tag, TEE_FS_HTREE_TAG_SIZE);
+ crypto_ops.authenc.final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG);
+ free(ctx);
+
+ if (res == TEE_SUCCESS && out_size != len)
+ return TEE_ERROR_GENERIC;
+ if (res == TEE_ERROR_MAC_INVALID)
+ return TEE_ERROR_CORRUPT_OBJECT;
+
+ return res;
+}
+
+static TEE_Result authenc_encrypt_final(void *ctx, uint8_t *tag,
+ const void *plain, size_t len,
+ void *crypt)
+{
+ TEE_Result res;
+ size_t out_size = len;
+ size_t out_tag_size = TEE_FS_HTREE_TAG_SIZE;
+
+ res = crypto_ops.authenc.enc_final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG,
+ plain, len, crypt, &out_size,
+ tag, &out_tag_size);
+ crypto_ops.authenc.final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG);
+ free(ctx);
+
+ if (res == TEE_SUCCESS &&
+ (out_size != len || out_tag_size != TEE_FS_HTREE_TAG_SIZE))
+ return TEE_ERROR_GENERIC;
+
+ return res;
+}
+
+static TEE_Result verify_root(struct tee_fs_htree *ht)
+{
+ TEE_Result res;
+ void *ctx;
+
+ res = tee_fs_fek_crypt(TEE_MODE_DECRYPT, ht->head.enc_fek,
+ sizeof(ht->fek), ht->fek);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ res = authenc_init(&ctx, TEE_MODE_DECRYPT, ht, NULL, sizeof(ht->imeta));
+ if (res != TEE_SUCCESS)
+ return res;
+
+ return authenc_decrypt_final(ctx, ht->head.tag, ht->head.imeta,
+ sizeof(ht->imeta), &ht->imeta);
+}
+
+static TEE_Result verify_node(struct traverse_arg *targ,
+ struct htree_node *node)
+{
+ void *ctx = targ->arg;
+ TEE_Result res;
+ uint8_t digest[TEE_FS_HTREE_HASH_SIZE];
+
+ res = calc_node_hash(node, ctx, digest);
+ if (res == TEE_SUCCESS &&
+ buf_compare_ct(digest, node->node.hash, sizeof(digest)))
+ return TEE_ERROR_CORRUPT_OBJECT;
+
+ return res;
+}
+
+static TEE_Result verify_tree(struct tee_fs_htree *ht)
+{
+ TEE_Result res;
+ size_t size;
+ void *ctx;
+
+ if (!crypto_ops.hash.get_ctx_size || !crypto_ops.hash.init ||
+ !crypto_ops.hash.update || !crypto_ops.hash.final)
+ return TEE_ERROR_NOT_SUPPORTED;
+
+ res = crypto_ops.hash.get_ctx_size(TEE_FS_HTREE_HASH_ALG, &size);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ ctx = malloc(size);
+ if (!ctx)
+ return TEE_ERROR_OUT_OF_MEMORY;
+
+ res = htree_traverse_post_order(ht, verify_node, ctx);
+ free(ctx);
+
+ return res;
+}
+
+static TEE_Result init_root_node(struct tee_fs_htree *ht)
+{
+ TEE_Result res;
+ size_t size;
+ void *ctx;
+
+ res = crypto_ops.hash.get_ctx_size(TEE_FS_HTREE_HASH_ALG, &size);
+ if (res != TEE_SUCCESS)
+ return res;
+ ctx = malloc(size);
+ if (!ctx)
+ return TEE_ERROR_OUT_OF_MEMORY;
+
+ ht->root.id = 1;
+
+ res = calc_node_hash(&ht->root, ctx, ht->root.node.hash);
+ free(ctx);
+
+ return res;
+}
+
+TEE_Result tee_fs_htree_open(bool create,
+ const struct tee_fs_htree_storage *stor,
+ void *stor_aux, struct tee_fs_htree **ht_ret)
+{
+ TEE_Result res;
+ struct tee_fs_htree *ht = calloc(1, sizeof(*ht));
+
+ if (!ht)
+ return TEE_ERROR_OUT_OF_MEMORY;
+
+ ht->stor = stor;
+ ht->stor_aux = stor_aux;
+
+ if (create) {
+ const struct tee_fs_htree_image dummy_head = { .counter = 0 };
+
+ res = crypto_ops.prng.read(ht->fek, sizeof(ht->fek));
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = tee_fs_fek_crypt(TEE_MODE_ENCRYPT, ht->fek,
+ sizeof(ht->fek), ht->head.enc_fek);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = init_root_node(ht);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ ht->dirty = true;
+ res = tee_fs_htree_sync_to_storage(&ht);
+ if (res != TEE_SUCCESS)
+ goto out;
+ res = rpc_write_head(ht, 0, &dummy_head);
+ } else {
+ res = init_head_from_data(ht);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = verify_root(ht);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = init_tree_from_data(ht);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = verify_tree(ht);
+ }
+out:
+ if (res == TEE_SUCCESS)
+ *ht_ret = ht;
+ else
+ tee_fs_htree_close(&ht);
+ return res;
+}
+
+struct tee_fs_htree_meta *tee_fs_htree_get_meta(struct tee_fs_htree *ht)
+{
+ return &ht->imeta.meta;
+}
+
+static TEE_Result free_node(struct traverse_arg *targ __unused,
+ struct htree_node *node)
+{
+ if (node->parent)
+ free(node);
+ return TEE_SUCCESS;
+}
+
+void tee_fs_htree_close(struct tee_fs_htree **ht)
+{
+ if (!*ht)
+ return;
+ htree_traverse_post_order(*ht, free_node, NULL);
+ free(*ht);
+ *ht = NULL;
+}
+
+static TEE_Result htree_sync_node_to_storage(struct traverse_arg *targ,
+ struct htree_node *node)
+{
+ TEE_Result res;
+ uint8_t vers;
+
+ /*
+ * The node can be dirty while the block isn't updated due to
+ * updated children, but if block is updated the node has to be
+ * dirty.
+ */
+ assert(node->dirty >= node->block_updated);
+
+ if (!node->dirty)
+ return TEE_SUCCESS;
+
+ if (node->parent) {
+ uint32_t f = HTREE_NODE_COMMITTED_CHILD(node->id & 1);
+
+ node->parent->dirty = true;
+ node->parent->node.flags ^= f;
+ vers = !!(node->parent->node.flags & f);
+ } else {
+ /*
+ * Counter isn't updated yet, it's increased just before
+ * writing the header.
+ */
+ vers = !(targ->ht->head.counter & 1);
+ }
+
+ res = calc_node_hash(node, targ->arg, node->node.hash);
+ if (res != TEE_SUCCESS)
+ return res;
+
+ node->dirty = false;
+ node->block_updated = false;
+
+ return rpc_write_node(targ->ht, node->id, vers, &node->node);
+}
+
+static TEE_Result update_root(struct tee_fs_htree *ht)
+{
+ TEE_Result res;
+ void *ctx;
+
+ ht->head.counter++;
+
+ res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, NULL, sizeof(ht->imeta));
+ if (res != TEE_SUCCESS)
+ return res;
+
+ return authenc_encrypt_final(ctx, ht->head.tag, &ht->imeta,
+ sizeof(ht->imeta), &ht->head.imeta);
+}
+
+TEE_Result tee_fs_htree_sync_to_storage(struct tee_fs_htree **ht_arg)
+{
+ TEE_Result res;
+ struct tee_fs_htree *ht = *ht_arg;
+ size_t size;
+ void *ctx;
+
+ if (!ht)
+ return TEE_ERROR_CORRUPT_OBJECT;
+
+ if (!ht->dirty)
+ return TEE_SUCCESS;
+
+ res = crypto_ops.hash.get_ctx_size(TEE_FS_HTREE_HASH_ALG, &size);
+ if (res != TEE_SUCCESS)
+ return res;
+ ctx = malloc(size);
+ if (!ctx)
+ return TEE_ERROR_OUT_OF_MEMORY;
+
+ res = htree_traverse_post_order(ht, htree_sync_node_to_storage, ctx);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ /* All the nodes are written to storage now. Time to update root. */
+ res = update_root(ht);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = rpc_write_head(ht, ht->head.counter & 1, &ht->head);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ ht->dirty = false;
+out:
+ free(ctx);
+ if (res != TEE_SUCCESS)
+ tee_fs_htree_close(ht_arg);
+ return res;
+}
+
+static TEE_Result get_block_node(struct tee_fs_htree *ht, bool create,
+ size_t block_num, struct htree_node **node)
+{
+ TEE_Result res;
+ struct htree_node *nd;
+
+ res = get_node(ht, create, BLOCK_NUM_TO_NODE_ID(block_num), &nd);
+ if (res == TEE_SUCCESS)
+ *node = nd;
+
+ return res;
+}
+
+TEE_Result tee_fs_htree_write_block(struct tee_fs_htree **ht_arg,
+ size_t block_num, const void *block)
+{
+ struct tee_fs_htree *ht = *ht_arg;
+ TEE_Result res;
+ struct tee_fs_rpc_operation op;
+ struct htree_node *node = NULL;
+ uint8_t block_vers;
+ void *ctx;
+ void *enc_block;
+
+ if (!ht)
+ return TEE_ERROR_CORRUPT_OBJECT;
+
+ res = get_block_node(ht, true, block_num, &node);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ if (!node->block_updated)
+ node->node.flags ^= HTREE_NODE_COMMITTED_BLOCK;
+
+ block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK);
+ res = ht->stor->rpc_write_init(ht->stor_aux, &op,
+ TEE_FS_HTREE_TYPE_BLOCK, block_num,
+ block_vers, &enc_block);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, &node->node,
+ ht->stor->block_size);
+ if (res != TEE_SUCCESS)
+ goto out;
+ res = authenc_encrypt_final(ctx, node->node.tag, block,
+ ht->stor->block_size, enc_block);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = ht->stor->rpc_write_final(&op);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ node->block_updated = true;
+ node->dirty = true;
+ ht->dirty = true;
+out:
+ if (res != TEE_SUCCESS)
+ tee_fs_htree_close(ht_arg);
+ return res;
+}
+
+TEE_Result tee_fs_htree_read_block(struct tee_fs_htree **ht_arg,
+ size_t block_num, void *block)
+{
+ struct tee_fs_htree *ht = *ht_arg;
+ TEE_Result res;
+ struct tee_fs_rpc_operation op;
+ struct htree_node *node;
+ uint8_t block_vers;
+ size_t len;
+ void *ctx;
+ void *enc_block;
+
+ if (!ht)
+ return TEE_ERROR_CORRUPT_OBJECT;
+
+ res = get_block_node(ht, false, block_num, &node);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK);
+ res = ht->stor->rpc_read_init(ht->stor_aux, &op,
+ TEE_FS_HTREE_TYPE_BLOCK, block_num,
+ block_vers, &enc_block);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = ht->stor->rpc_read_final(&op, &len);
+ if (res != TEE_SUCCESS)
+ goto out;
+ if (len != ht->stor->block_size) {
+ res = TEE_ERROR_CORRUPT_OBJECT;
+ goto out;
+ }
+
+ res = authenc_init(&ctx, TEE_MODE_DECRYPT, ht, &node->node,
+ ht->stor->block_size);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = authenc_decrypt_final(ctx, node->node.tag, enc_block,
+ ht->stor->block_size, block);
+out:
+ if (res != TEE_SUCCESS)
+ tee_fs_htree_close(ht_arg);
+ return res;
+}
+
+TEE_Result tee_fs_htree_truncate(struct tee_fs_htree **ht_arg, size_t block_num)
+{
+ struct tee_fs_htree *ht = *ht_arg;
+ size_t node_id = BLOCK_NUM_TO_NODE_ID(block_num);
+ struct htree_node *node;
+
+ if (!ht)
+ return TEE_ERROR_CORRUPT_OBJECT;
+
+ while (node_id < ht->imeta.max_node_id) {
+ node = find_closest_node(ht, ht->imeta.max_node_id);
+ assert(node && node->id == ht->imeta.max_node_id);
+ assert(!node->child[0] && !node->child[1]);
+ assert(node->parent);
+ assert(node->parent->child[node->id & 1] == node);
+ node->parent->child[node->id & 1] = NULL;
+ free(node);
+ ht->imeta.max_node_id--;
+ ht->dirty = true;
+ }
+
+ return TEE_SUCCESS;
+}
diff --git a/core/tee/sub.mk b/core/tee/sub.mk
index 32f0f98..97c4b7a 100644
--- a/core/tee/sub.mk
+++ b/core/tee/sub.mk
@@ -31,6 +31,8 @@ srcs-y += tee_svc_storage.c
srcs-$(CFG_RPMB_FS) += tee_rpmb_fs.c
srcs-$(CFG_REE_FS) += tee_ree_fs.c
srcs-$(CFG_SQL_FS) += tee_sql_fs.c
+srcs-$(call cfg-one-enabled,CFG_REE_FS CFG_SQL_FS \
+ CFG_TEE_CORE_EMBED_INTERNAL_TESTS) += fs_htree.c
srcs-$(call cfg-one-enabled,CFG_REE_FS CFG_SQL_FS) += tee_fs_rpc.c
srcs-$(call cfg-one-enabled,CFG_REE_FS CFG_SQL_FS CFG_RPMB_FS) += \
tee_fs_rpc_cache.c
diff --git a/core/tee/tee_cryp_utl.c b/core/tee/tee_cryp_utl.c
index fa01161..b63e790 100644
--- a/core/tee/tee_cryp_utl.c
+++ b/core/tee/tee_cryp_utl.c
@@ -392,6 +392,13 @@ __weak void plat_prng_add_jitter_entropy(void)
tee_prng_add_entropy((uint8_t *)&current, sizeof(current));
}
+__weak void plat_prng_add_jitter_entropy_norpc(void)
+{
+#ifndef CFG_SECURE_TIME_SOURCE_REE
+ plat_prng_add_jitter_entropy();
+#endif
+}
+
static TEE_Result tee_cryp_init(void)
{
if (crypto_ops.init)
diff --git a/core/tee/tee_fs_key_manager.c b/core/tee/tee_fs_key_manager.c
index c827cef..fa579c6 100644
--- a/core/tee/tee_fs_key_manager.c
+++ b/core/tee/tee_fs_key_manager.c
@@ -55,16 +55,6 @@ struct tee_fs_ssk {
uint8_t key[TEE_FS_KM_SSK_SIZE];
};
-struct aad {
- const uint8_t *encrypted_key;
- const uint8_t *iv;
-};
-
-struct km_header {
- struct aad aad;
- uint8_t *tag;
-};
-
static struct tee_fs_ssk tee_fs_ssk;
static uint8_t string_for_ssk_gen[] = "ONLY_FOR_tee_fs_ssk";
@@ -109,17 +99,17 @@ exit:
return res;
}
-static TEE_Result fek_crypt(TEE_OperationMode mode,
- uint8_t *key, int size)
+TEE_Result tee_fs_fek_crypt(TEE_OperationMode mode, const uint8_t *in_key,
+ size_t size, uint8_t *out_key)
{
TEE_Result res;
uint8_t *ctx = NULL;
size_t ctx_size;
uint8_t tsk[TEE_FS_KM_TSK_SIZE];
- uint8_t dst_key[TEE_FS_KM_FEK_SIZE];
+ uint8_t dst_key[size];
struct tee_ta_session *sess;
- if (!key)
+ if (!in_key || !out_key)
return TEE_ERROR_BAD_PARAMETERS;
if (size != TEE_FS_KM_FEK_SIZE)
@@ -151,13 +141,13 @@ static TEE_Result fek_crypt(TEE_OperationMode mode,
goto exit;
res = crypto_ops.cipher.update(ctx, TEE_FS_KM_ENC_FEK_ALG,
- mode, true, key, size, dst_key);
+ mode, true, in_key, size, dst_key);
if (res != TEE_SUCCESS)
goto exit;
crypto_ops.cipher.final(ctx, TEE_FS_KM_ENC_FEK_ALG);
- memcpy(key, dst_key, sizeof(dst_key));
+ memcpy(out_key, dst_key, sizeof(dst_key));
exit:
free(ctx);
@@ -170,11 +160,6 @@ static TEE_Result generate_fek(uint8_t *key, uint8_t len)
return crypto_ops.prng.read(key, len);
}
-static TEE_Result generate_iv(uint8_t *iv, uint8_t len)
-{
- return crypto_ops.prng.read(iv, len);
-}
-
static TEE_Result tee_fs_init_key_manager(void)
{
int res = TEE_SUCCESS;
@@ -204,94 +189,6 @@ static TEE_Result tee_fs_init_key_manager(void)
return res;
}
-static TEE_Result do_auth_enc(TEE_OperationMode mode,
- struct km_header *hdr,
- uint8_t *fek, int fek_len,
- const uint8_t *data_in, size_t in_size,
- uint8_t *data_out, size_t *out_size)
-{
- TEE_Result res = TEE_SUCCESS;
- uint8_t *ctx = NULL;
- size_t ctx_size;
- size_t tag_len = TEE_FS_KM_MAX_TAG_LEN;
-
- if ((mode != TEE_MODE_ENCRYPT) && (mode != TEE_MODE_DECRYPT))
- return TEE_ERROR_BAD_PARAMETERS;
-
- if (*out_size < in_size) {
- EMSG("output buffer(%zd) < input buffer(%zd)",
- *out_size, in_size);
- return TEE_ERROR_SHORT_BUFFER;
- }
-
- res = crypto_ops.authenc.get_ctx_size(TEE_FS_KM_AUTH_ENC_ALG,
- &ctx_size);
- if (res != TEE_SUCCESS)
- return res;
-
- ctx = malloc(ctx_size);
- if (!ctx) {
- EMSG("request memory size %zu failed", ctx_size);
- return TEE_ERROR_OUT_OF_MEMORY;
- }
-
- res = crypto_ops.authenc.init(ctx, TEE_FS_KM_AUTH_ENC_ALG,
- mode, fek, fek_len, hdr->aad.iv,
- TEE_FS_KM_IV_LEN, TEE_FS_KM_MAX_TAG_LEN,
- sizeof(struct aad), in_size);
- if (res != TEE_SUCCESS)
- goto exit;
-
- res = crypto_ops.authenc.update_aad(ctx, TEE_FS_KM_AUTH_ENC_ALG,
- mode, (uint8_t *)hdr->aad.encrypted_key,
- TEE_FS_KM_FEK_SIZE);
- if (res != TEE_SUCCESS)
- goto exit;
-
- res = crypto_ops.authenc.update_aad(ctx, TEE_FS_KM_AUTH_ENC_ALG,
- mode, (uint8_t *)hdr->aad.iv,
- TEE_FS_KM_IV_LEN);
- if (res != TEE_SUCCESS)
- goto exit;
-
- if (mode == TEE_MODE_ENCRYPT) {
- res = crypto_ops.authenc.enc_final(ctx, TEE_FS_KM_AUTH_ENC_ALG,
- data_in, in_size, data_out, out_size,
- hdr->tag, &tag_len);
- } else {
- res = crypto_ops.authenc.dec_final(ctx, TEE_FS_KM_AUTH_ENC_ALG,
- data_in, in_size, data_out, out_size,
- hdr->tag, tag_len);
- }
-
- if (res != TEE_SUCCESS)
- goto exit;
-
- crypto_ops.authenc.final(ctx, TEE_FS_KM_AUTH_ENC_ALG);
-
-exit:
- free(ctx);
- return res;
-}
-
-size_t tee_fs_get_header_size(enum tee_fs_file_type type)
-{
- size_t header_size = 0;
-
- switch (type) {
- case META_FILE:
- header_size = sizeof(struct meta_header);
- break;
- case BLOCK_FILE:
- header_size = sizeof(struct block_header);
- break;
- default:
- panic("Unknown file type");
- }
-
- return header_size;
-}
-
TEE_Result tee_fs_generate_fek(uint8_t *buf, int buf_size)
{
TEE_Result res;
@@ -303,117 +200,7 @@ TEE_Result tee_fs_generate_fek(uint8_t *buf, int buf_size)
if (res != TEE_SUCCESS)
return res;
- return fek_crypt(TEE_MODE_ENCRYPT, buf,
- TEE_FS_KM_FEK_SIZE);
-}
-
-TEE_Result tee_fs_encrypt_file(enum tee_fs_file_type file_type,
- const uint8_t *data_in, size_t data_in_size,
- uint8_t *data_out, size_t *data_out_size,
- const uint8_t *encrypted_fek)
-{
- TEE_Result res = TEE_SUCCESS;
- struct km_header hdr;
- uint8_t iv[TEE_FS_KM_IV_LEN];
- uint8_t tag[TEE_FS_KM_MAX_TAG_LEN];
- uint8_t fek[TEE_FS_KM_FEK_SIZE];
- uint8_t *ciphertext;
- size_t cipher_size;
- size_t header_size = tee_fs_get_header_size(file_type);
-
- /*
- * Meta File Format: |Header|Chipertext|
- * Header Format: |AAD|Tag|
- * AAD Format: |Encrypted_FEK|IV|
- *
- * Block File Format: |Header|Ciphertext|
- * Header Format: |IV|Tag|
- *
- * TSK = HMAC(SSK, TA_UUID)
- * FEK = AES_DECRYPT(TSK, Encrypted_FEK)
- * Chipertext = AES_GCM_ENCRYPT(FEK, IV, Meta_Info, AAD)
- */
-
- if (*data_out_size != (header_size + data_in_size))
- return TEE_ERROR_SHORT_BUFFER;
-
- res = generate_iv(iv, TEE_FS_KM_IV_LEN);
- if (res != TEE_SUCCESS)
- goto fail;
-
- memcpy(fek, encrypted_fek, TEE_FS_KM_FEK_SIZE);
- res = fek_crypt(TEE_MODE_DECRYPT, fek, TEE_FS_KM_FEK_SIZE);
- if (res != TEE_SUCCESS)
- goto fail;
-
- ciphertext = data_out + header_size;
- cipher_size = data_in_size;
-
- hdr.aad.iv = iv;
- hdr.aad.encrypted_key = encrypted_fek;
- hdr.tag = tag;
-
- res = do_auth_enc(TEE_MODE_ENCRYPT, &hdr,
- fek, TEE_FS_KM_FEK_SIZE,
- data_in, data_in_size,
- ciphertext, &cipher_size);
-
- if (res == TEE_SUCCESS) {
- if (file_type == META_FILE) {
- memcpy(data_out, encrypted_fek, TEE_FS_KM_FEK_SIZE);
- data_out += TEE_FS_KM_FEK_SIZE;
- }
-
- memcpy(data_out, iv, TEE_FS_KM_IV_LEN);
- data_out += TEE_FS_KM_IV_LEN;
- memcpy(data_out, tag, TEE_FS_KM_MAX_TAG_LEN);
-
- *data_out_size = header_size + cipher_size;
- }
-
-fail:
- return res;
-}
-
-TEE_Result tee_fs_decrypt_file(enum tee_fs_file_type file_type,
- const uint8_t *data_in, size_t data_in_size,
- uint8_t *plaintext, size_t *plaintext_size,
- uint8_t *encrypted_fek)
-{
- TEE_Result res = TEE_SUCCESS;
- struct km_header km_hdr;
- size_t file_hdr_size = tee_fs_get_header_size(file_type);
- const uint8_t *cipher = data_in + file_hdr_size;
- int cipher_size = data_in_size - file_hdr_size;
- uint8_t fek[TEE_FS_KM_FEK_SIZE];
-
- if (file_type == META_FILE) {
- struct meta_header *hdr = (struct meta_header *)data_in;
-
- km_hdr.aad.encrypted_key = hdr->encrypted_key;
- km_hdr.aad.iv = hdr->common.iv;
- km_hdr.tag = hdr->common.tag;
-
- /* return encrypted FEK to tee_fs which is used for block
- * encryption/decryption */
- memcpy(encrypted_fek, hdr->encrypted_key, TEE_FS_KM_FEK_SIZE);
- } else {
- struct block_header *hdr = (struct block_header *)data_in;
-
- km_hdr.aad.encrypted_key = encrypted_fek;
- km_hdr.aad.iv = hdr->common.iv;
- km_hdr.tag = hdr->common.tag;
- }
-
- memcpy(fek, km_hdr.aad.encrypted_key, TEE_FS_KM_FEK_SIZE);
- res = fek_crypt(TEE_MODE_DECRYPT, fek, TEE_FS_KM_FEK_SIZE);
- if (res != TEE_SUCCESS) {
- EMSG("Failed to decrypt FEK, res=0x%x", res);
- return res;
- }
-
- return do_auth_enc(TEE_MODE_DECRYPT, &km_hdr, fek, TEE_FS_KM_FEK_SIZE,
- cipher, cipher_size, plaintext, plaintext_size);
+ return tee_fs_fek_crypt(TEE_MODE_ENCRYPT, buf, TEE_FS_KM_FEK_SIZE, buf);
}
static TEE_Result sha256(uint8_t *out, size_t out_size, const uint8_t *in,
@@ -518,8 +305,8 @@ TEE_Result tee_fs_crypt_block(uint8_t *out, const uint8_t *in, size_t size,
blk_idx);
/* Decrypt FEK */
- memcpy(fek, encrypted_fek, TEE_FS_KM_FEK_SIZE);
- res = fek_crypt(TEE_MODE_DECRYPT, fek, TEE_FS_KM_FEK_SIZE);
+ res = tee_fs_fek_crypt(TEE_MODE_DECRYPT, encrypted_fek,
+ TEE_FS_KM_FEK_SIZE, fek);
if (res != TEE_SUCCESS)
return res;
@@ -550,4 +337,3 @@ exit:
}
service_init_late(tee_fs_init_key_manager);
-
diff --git a/core/tee/tee_fs_rpc.c b/core/tee/tee_fs_rpc.c
index 5e1078a..3ce1ba8 100644
--- a/core/tee/tee_fs_rpc.c
+++ b/core/tee/tee_fs_rpc.c
@@ -26,14 +26,17 @@
*/
#include <assert.h>
+#include <kernel/tee_misc.h>
#include <kernel/thread.h>
#include <mm/core_memprot.h>
#include <optee_msg_supplicant.h>
#include <stdlib.h>
-#include <string.h>
#include <string_ext.h>
+#include <string.h>
#include <tee/tee_fs.h>
#include <tee/tee_fs_rpc.h>
+#include <tee/tee_pobj.h>
+#include <tee/tee_svc_storage.h>
#include <trace.h>
#include <util.h>
@@ -48,16 +51,15 @@ static TEE_Result operation_commit(struct tee_fs_rpc_operation *op)
}
static TEE_Result operation_open(uint32_t id, unsigned int cmd,
- const char *fname, int *fd)
+ struct tee_pobj *po, int *fd)
{
struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 };
TEE_Result res;
void *va;
paddr_t pa;
uint64_t cookie;
- size_t fname_size = strlen(fname) + 1;
- va = tee_fs_rpc_cache_alloc(fname_size, &pa, &cookie);
+ va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie);
if (!va)
return TEE_ERROR_OUT_OF_MEMORY;
@@ -66,9 +68,12 @@ static TEE_Result operation_open(uint32_t id, unsigned int cmd,
op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
op.params[1].u.tmem.buf_ptr = pa;
- op.params[1].u.tmem.size = fname_size;
+ op.params[1].u.tmem.size = TEE_FS_NAME_MAX;
op.params[1].u.tmem.shm_ref = cookie;
- strlcpy(va, fname, fname_size);
+ res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX,
+ po, po->temporary);
+ if (res != TEE_SUCCESS)
+ return res;
op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT;
@@ -79,14 +84,14 @@ static TEE_Result operation_open(uint32_t id, unsigned int cmd,
return res;
}
-TEE_Result tee_fs_rpc_open(uint32_t id, const char *fname, int *fd)
+TEE_Result tee_fs_rpc_open(uint32_t id, struct tee_pobj *po, int *fd)
{
- return operation_open(id, OPTEE_MRF_OPEN, fname, fd);
+ return operation_open(id, OPTEE_MRF_OPEN, po, fd);
}
-TEE_Result tee_fs_rpc_create(uint32_t id, const char *fname, int *fd)
+TEE_Result tee_fs_rpc_create(uint32_t id, struct tee_pobj *po, int *fd)
{
- return operation_open(id, OPTEE_MRF_CREATE, fname, fd);
+ return operation_open(id, OPTEE_MRF_CREATE, po, fd);
}
TEE_Result tee_fs_rpc_close(uint32_t id, int fd)
@@ -196,15 +201,15 @@ TEE_Result tee_fs_rpc_truncate(uint32_t id, int fd, size_t len)
return operation_commit(&op);
}
-TEE_Result tee_fs_rpc_remove(uint32_t id, const char *fname)
+TEE_Result tee_fs_rpc_remove(uint32_t id, struct tee_pobj *po)
{
+ TEE_Result res;
struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 };
void *va;
paddr_t pa;
uint64_t cookie;
- size_t name_len = strlen(fname) + 1;
- va = tee_fs_rpc_cache_alloc(name_len, &pa, &cookie);
+ va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie);
if (!va)
return TEE_ERROR_OUT_OF_MEMORY;
@@ -213,25 +218,27 @@ TEE_Result tee_fs_rpc_remove(uint32_t id, const char *fname)
op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
op.params[1].u.tmem.buf_ptr = pa;
- op.params[1].u.tmem.size = name_len;
+ op.params[1].u.tmem.size = TEE_FS_NAME_MAX;
op.params[1].u.tmem.shm_ref = cookie;
- strlcpy(va, fname, name_len);
+ res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX,
+ po, po->temporary);
+ if (res != TEE_SUCCESS)
+ return res;
return operation_commit(&op);
}
-TEE_Result tee_fs_rpc_rename(uint32_t id, const char *old_fname,
- const char *new_fname, bool overwrite)
+TEE_Result tee_fs_rpc_rename(uint32_t id, struct tee_pobj *old,
+ struct tee_pobj *new, bool overwrite)
{
+ TEE_Result res;
struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 };
char *va;
paddr_t pa;
uint64_t cookie;
- size_t old_fname_size = strlen(old_fname) + 1;
- size_t new_fname_size = strlen(new_fname) + 1;
+ bool temp;
- va = tee_fs_rpc_cache_alloc(old_fname_size + new_fname_size,
- &pa, &cookie);
+ va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX * 2, &pa, &cookie);
if (!va)
return TEE_ERROR_OUT_OF_MEMORY;
@@ -241,20 +248,37 @@ TEE_Result tee_fs_rpc_rename(uint32_t id, const char *old_fname,
op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
op.params[1].u.tmem.buf_ptr = pa;
- op.params[1].u.tmem.size = old_fname_size;
+ op.params[1].u.tmem.size = TEE_FS_NAME_MAX;
op.params[1].u.tmem.shm_ref = cookie;
- strlcpy(va, old_fname, old_fname_size);
+ if (new)
+ temp = old->temporary;
+ else
+ temp = true;
+ res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX,
+ old, temp);
+ if (res != TEE_SUCCESS)
+ return res;
op.params[2].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
- op.params[2].u.tmem.buf_ptr = pa + old_fname_size;
- op.params[2].u.tmem.size = new_fname_size;
+ op.params[2].u.tmem.buf_ptr = pa + TEE_FS_NAME_MAX;
+ op.params[2].u.tmem.size = TEE_FS_NAME_MAX;
op.params[2].u.tmem.shm_ref = cookie;
- strlcpy(va + old_fname_size, new_fname, new_fname_size);
+ if (new) {
+ res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX,
+ TEE_FS_NAME_MAX,
+ new, new->temporary);
+ } else {
+ res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX,
+ TEE_FS_NAME_MAX,
+ old, false);
+ }
+ if (res != TEE_SUCCESS)
+ return res;
return operation_commit(&op);
}
-TEE_Result tee_fs_rpc_opendir(uint32_t id, const char *name,
+TEE_Result tee_fs_rpc_opendir(uint32_t id, const TEE_UUID *uuid,
struct tee_fs_dir **d)
{
TEE_Result res;
@@ -262,13 +286,12 @@ TEE_Result tee_fs_rpc_opendir(uint32_t id, const char *name,
void *va;
paddr_t pa;
uint64_t cookie;
- size_t name_len = strlen(name) + 1;
struct tee_fs_dir *dir = calloc(1, sizeof(*dir));
if (!dir)
return TEE_ERROR_OUT_OF_MEMORY;
- va = tee_fs_rpc_cache_alloc(name_len, &pa, &cookie);
+ va = tee_fs_rpc_cache_alloc(TEE_FS_NAME_MAX, &pa, &cookie);
if (!va) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto err_exit;
@@ -279,9 +302,11 @@ TEE_Result tee_fs_rpc_opendir(uint32_t id, const char *name,
op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
op.params[1].u.tmem.buf_ptr = pa;
- op.params[1].u.tmem.size = name_len;
+ op.params[1].u.tmem.size = TEE_FS_NAME_MAX;
op.params[1].u.tmem.shm_ref = cookie;
- strlcpy(va, name, name_len);
+ res = tee_svc_storage_create_dirname(va, TEE_FS_NAME_MAX, uuid);
+ if (res != TEE_SUCCESS)
+ return res;
op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT;
@@ -308,8 +333,6 @@ TEE_Result tee_fs_rpc_closedir(uint32_t id, struct tee_fs_dir *d)
op.params[0].u.value.a = OPTEE_MRF_CLOSEDIR;
op.params[0].u.value.b = d->nw_dir;
- if (d)
- free(d->d.d_name);
free(d);
return operation_commit(&op);
}
@@ -344,9 +367,9 @@ TEE_Result tee_fs_rpc_readdir(uint32_t id, struct tee_fs_dir *d,
if (res != TEE_SUCCESS)
return res;
- free(d->d.d_name);
- d->d.d_name = strndup(va, max_name_len);
- if (!d->d.d_name)
+ d->d.oidlen = tee_hs2b(va, d->d.oid, strnlen(va, max_name_len),
+ sizeof(d->d.oid));
+ if (!d->d.oidlen)
return TEE_ERROR_OUT_OF_MEMORY;
*ent = &d->d;
diff --git a/core/tee/tee_obj.c b/core/tee/tee_obj.c
index 78cf937..6dcfbf3 100644
--- a/core/tee/tee_obj.c
+++ b/core/tee/tee_obj.c
@@ -31,7 +31,6 @@
#include <tee_api_defines.h>
#include <mm/tee_mmu.h>
#include <tee/tee_fs.h>
-#include <tee/tee_fs_defs.h>
#include <tee/tee_pobj.h>
#include <trace.h>
#include <tee/tee_svc_storage.h>
@@ -79,32 +78,20 @@ void tee_obj_close_all(struct user_ta_ctx *utc)
TEE_Result tee_obj_verify(struct tee_ta_session *sess, struct tee_obj *o)
{
TEE_Result res;
- char *file = NULL;
const struct tee_file_operations *fops = o->pobj->fops;
struct tee_file_handle *fh = NULL;
if (!fops)
return TEE_ERROR_STORAGE_NOT_AVAILABLE;
- 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;
- }
-
- res = fops->open(file, &fh);
+ res = fops->open(o->pobj, &fh);
if (res == TEE_ERROR_CORRUPT_OBJECT) {
EMSG("Object corrupt\n");
+ fops->remove(o->pobj);
tee_obj_close(to_user_ta_ctx(sess->ctx), o);
- fops->remove(file);
}
- free(file);
fops->close(&fh);
-exit:
return res;
}
diff --git a/core/tee/tee_pobj.c b/core/tee/tee_pobj.c
index a7aee31..0f9fb46 100644
--- a/core/tee/tee_pobj.c
+++ b/core/tee/tee_pobj.c
@@ -80,7 +80,8 @@ static TEE_Result tee_pobj_check_access(uint32_t oflags, uint32_t nflags)
}
TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len,
- uint32_t flags, const struct tee_file_operations *fops,
+ uint32_t flags, bool temporary,
+ const struct tee_file_operations *fops,
struct tee_pobj **obj)
{
struct tee_pobj *o;
@@ -100,10 +101,12 @@ TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len,
}
if (*obj) {
+ if (temporary != (*obj)->temporary) {
+ res = TEE_ERROR_ACCESS_CONFLICT;
+ goto out;
+ }
res = tee_pobj_check_access((*obj)->flags, flags);
- if (res != TEE_SUCCESS)
- *obj = NULL;
- else
+ if (res == TEE_SUCCESS)
(*obj)->refcnt++;
goto out;
}
@@ -119,6 +122,7 @@ TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len,
memcpy(&o->uuid, uuid, sizeof(TEE_UUID));
o->flags = flags;
o->fops = fops;
+ o->temporary = temporary;
o->obj_id = malloc(obj_id_len);
if (o->obj_id == NULL) {
@@ -134,6 +138,8 @@ TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len,
res = TEE_SUCCESS;
out:
+ if (res != TEE_SUCCESS)
+ *obj = NULL;
mutex_unlock(&pobjs_mutex);
return res;
}
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,
diff --git a/core/tee/tee_rpmb_fs.c b/core/tee/tee_rpmb_fs.c
index 229bce7..dcac98b 100644
--- a/core/tee/tee_rpmb_fs.c
+++ b/core/tee/tee_rpmb_fs.c
@@ -26,22 +26,24 @@
*/
#include <assert.h>
-#include <kernel/tee_common.h>
#include <kernel/mutex.h>
#include <kernel/panic.h>
+#include <kernel/tee_common.h>
#include <kernel/tee_common_otp.h>
+#include <kernel/tee_misc.h>
#include <kernel/thread.h>
#include <mm/core_memprot.h>
#include <mm/tee_mm.h>
#include <optee_msg_supplicant.h>
#include <stdlib.h>
-#include <string.h>
#include <string_ext.h>
+#include <string.h>
#include <sys/queue.h>
#include <tee/tee_cryp_provider.h>
-#include <tee/tee_fs_defs.h>
#include <tee/tee_fs.h>
#include <tee/tee_fs_key_manager.h>
+#include <tee/tee_pobj.h>
+#include <tee/tee_svc_storage.h>
#include <trace.h>
#include <util.h>
@@ -89,8 +91,6 @@ struct rpmb_file_handle {
char filename[TEE_RPMB_FS_FILENAME_LENGTH];
/* Address for current entry in RPMB */
uint32_t rpmb_fat_address;
- /* Current position */
- uint32_t pos;
};
/**
@@ -106,13 +106,10 @@ struct rpmb_fs_partition {
};
/**
- * A node in a list of directory entries. entry->name is a
- * pointer to name here.
+ * A node in a list of directory entries.
*/
struct tee_rpmb_fs_dirent {
struct tee_fs_dirent entry;
- char name[TEE_RPMB_FS_FILENAME_LENGTH];
- /* */
SIMPLEQ_ENTRY(tee_rpmb_fs_dirent) link;
};
@@ -1581,7 +1578,6 @@ out:
static void dump_fh(struct rpmb_file_handle *fh)
{
DMSG("fh->filename=%s", fh->filename);
- DMSG("fh->pos=%u", fh->pos);
DMSG("fh->rpmb_fat_address=%u", fh->rpmb_fat_address);
DMSG("fh->fat_entry.start_address=%u", fh->fat_entry.start_address);
DMSG("fh->fat_entry.data_size=%u", fh->fat_entry.data_size);
@@ -1592,7 +1588,8 @@ static void dump_fh(struct rpmb_file_handle *fh __unused)
}
#endif
-static struct rpmb_file_handle *alloc_file_handle(const char *filename)
+static struct rpmb_file_handle *alloc_file_handle(struct tee_pobj *po,
+ bool temporary)
{
struct rpmb_file_handle *fh = NULL;
@@ -1600,8 +1597,10 @@ static struct rpmb_file_handle *alloc_file_handle(const char *filename)
if (!fh)
return NULL;
- if (filename)
- strlcpy(fh->filename, filename, sizeof(fh->filename));
+ if (po)
+ tee_svc_storage_create_filename(fh->filename,
+ sizeof(fh->filename), po,
+ temporary);
return fh;
}
@@ -1696,7 +1695,7 @@ static TEE_Result rpmb_fs_setup(void)
partition_data->fat_start_address = RPMB_FS_FAT_START_ADDRESS;
/* Initial FAT entry with FILE_IS_LAST_ENTRY flag set. */
- fh = alloc_file_handle(NULL);
+ fh = alloc_file_handle(NULL, false);
if (!fh) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
@@ -1924,29 +1923,17 @@ again:
return res;
}
-static TEE_Result rpmb_fs_open_internal(const char *file, bool create,
+static TEE_Result rpmb_fs_open_internal(struct tee_pobj *po, bool create,
struct tee_file_handle **ret_fh)
{
struct rpmb_file_handle *fh = NULL;
- size_t filelen;
tee_mm_pool_t p;
bool pool_result;
TEE_Result res = TEE_ERROR_GENERIC;
mutex_lock(&rpmb_mutex);
- filelen = strlen(file);
- if (filelen >= TEE_RPMB_FS_FILENAME_LENGTH - 1 || filelen == 0) {
- res = TEE_ERROR_BAD_PARAMETERS;
- goto out;
- }
-
- if (file[filelen - 1] == '/') {
- res = TEE_ERROR_BAD_PARAMETERS;
- goto out;
- }
-
- fh = alloc_file_handle(file);
+ fh = alloc_file_handle(po, po->temporary);
if (!fh) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
@@ -1988,7 +1975,8 @@ static TEE_Result rpmb_fs_open_internal(const char *file, bool create,
if ((fh->fat_entry.flags & FILE_IS_ACTIVE) == 0) {
memset(&fh->fat_entry, 0,
sizeof(struct rpmb_fat_entry));
- memcpy(fh->fat_entry.filename, file, strlen(file));
+ memcpy(fh->fat_entry.filename, fh->filename,
+ strlen(fh->filename));
/* Start address and size are 0 */
fh->fat_entry.flags = FILE_IS_ACTIVE;
@@ -2025,8 +2013,8 @@ static void rpmb_fs_close(struct tee_file_handle **tfh)
*tfh = NULL;
}
-static TEE_Result rpmb_fs_read(struct tee_file_handle *tfh, void *buf,
- size_t *len)
+static TEE_Result rpmb_fs_read(struct tee_file_handle *tfh, size_t pos,
+ void *buf, size_t *len)
{
TEE_Result res;
struct rpmb_file_handle *fh = (struct rpmb_file_handle *)tfh;
@@ -2043,29 +2031,28 @@ static TEE_Result rpmb_fs_read(struct tee_file_handle *tfh, void *buf,
if (res != TEE_SUCCESS)
goto out;
- if (fh->pos >= fh->fat_entry.data_size) {
+ if (pos >= fh->fat_entry.data_size) {
*len = 0;
goto out;
}
- size = MIN(size, fh->fat_entry.data_size - fh->pos);
+ size = MIN(size, fh->fat_entry.data_size - pos);
if (size) {
res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID,
- fh->fat_entry.start_address + fh->pos, buf,
+ fh->fat_entry.start_address + pos, buf,
size, fh->fat_entry.fek);
if (res != TEE_SUCCESS)
goto out;
}
*len = size;
- fh->pos += size;
out:
mutex_unlock(&rpmb_mutex);
return res;
}
-static TEE_Result rpmb_fs_write(struct tee_file_handle *tfh, const void *buf,
- size_t size)
+static TEE_Result rpmb_fs_write(struct tee_file_handle *tfh, size_t pos,
+ const void *buf, size_t size)
{
TEE_Result res;
struct rpmb_file_handle *fh = (struct rpmb_file_handle *)tfh;
@@ -2108,8 +2095,8 @@ static TEE_Result rpmb_fs_write(struct tee_file_handle *tfh, const void *buf,
if (fh->fat_entry.flags & FILE_IS_LAST_ENTRY)
panic("invalid last entry flag");
- end = fh->pos + size;
- start_addr = fh->fat_entry.start_address + fh->pos;
+ end = pos + size;
+ start_addr = fh->fat_entry.start_address + pos;
if (end <= fh->fat_entry.data_size &&
tee_rpmb_write_is_atomic(CFG_RPMB_FS_DEV_ID, start_addr, size)) {
@@ -2143,7 +2130,7 @@ static TEE_Result rpmb_fs_write(struct tee_file_handle *tfh, const void *buf,
goto out;
}
- memcpy(newbuf + fh->pos, buf, size);
+ memcpy(newbuf + pos, buf, size);
newaddr = tee_mm_get_smem(mm);
res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, newaddr, newbuf,
@@ -2158,7 +2145,6 @@ static TEE_Result rpmb_fs_write(struct tee_file_handle *tfh, const void *buf,
goto out;
}
- fh->pos += size;
out:
mutex_unlock(&rpmb_mutex);
if (pool_result)
@@ -2169,68 +2155,14 @@ out:
return res;
}
-static TEE_Result rpmb_fs_seek(struct tee_file_handle *tfh, int32_t offset,
- TEE_Whence whence, int32_t *new_offs)
-
-{
- struct rpmb_file_handle *fh = (struct rpmb_file_handle *)tfh;
- TEE_Result res;
- tee_fs_off_t new_pos;
-
- mutex_lock(&rpmb_mutex);
-
- res = read_fat(fh, NULL);
- if (res != TEE_SUCCESS)
- goto out;
-
- switch (whence) {
- case TEE_DATA_SEEK_SET:
- new_pos = offset;
- break;
-
- case TEE_DATA_SEEK_CUR:
- new_pos = fh->pos + offset;
- break;
-
- case TEE_DATA_SEEK_END:
- new_pos = fh->fat_entry.data_size + offset;
- break;
-
- default:
- res = TEE_ERROR_BAD_PARAMETERS;
- goto out;
- }
-
- 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 out;
- }
-
- fh->pos = new_pos;
- if (new_offs)
- *new_offs = new_pos;
-out:
- mutex_unlock(&rpmb_mutex);
- return res;
-}
-
-static TEE_Result rpmb_fs_remove(const char *filename)
+static TEE_Result rpmb_fs_remove(struct tee_pobj *po)
{
TEE_Result res = TEE_ERROR_GENERIC;
struct rpmb_file_handle *fh = NULL;
mutex_lock(&rpmb_mutex);
- if (!filename || strlen(filename) >= TEE_RPMB_FS_FILENAME_LENGTH - 1) {
- res = TEE_ERROR_BAD_PARAMETERS;
- goto out;
- }
-
- fh = alloc_file_handle(filename);
+ fh = alloc_file_handle(po, po->temporary);
if (!fh) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
@@ -2250,39 +2182,33 @@ out:
return res;
}
-static TEE_Result rpmb_fs_rename(const char *old_name, const char *new_name,
+static TEE_Result rpmb_fs_rename(struct tee_pobj *old, struct tee_pobj *new,
bool overwrite)
{
TEE_Result res = TEE_ERROR_GENERIC;
struct rpmb_file_handle *fh_old = NULL;
struct rpmb_file_handle *fh_new = NULL;
- uint32_t old_len;
- uint32_t new_len;
mutex_lock(&rpmb_mutex);
- if (!old_name || !new_name) {
+ if (!old) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
- old_len = strlen(old_name);
- new_len = strlen(new_name);
-
- if ((old_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) ||
- (new_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || (new_len == 0)) {
-
- res = TEE_ERROR_BAD_PARAMETERS;
- goto out;
- }
-
- fh_old = alloc_file_handle(old_name);
+ if (new)
+ fh_old = alloc_file_handle(old, old->temporary);
+ else
+ fh_old = alloc_file_handle(old, true);
if (!fh_old) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
}
- fh_new = alloc_file_handle(new_name);
+ if (new)
+ fh_new = alloc_file_handle(new, new->temporary);
+ else
+ fh_new = alloc_file_handle(old, false);
if (!fh_new) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
@@ -2307,7 +2233,8 @@ static TEE_Result rpmb_fs_rename(const char *old_name, const char *new_name,
}
memset(fh_old->fat_entry.filename, 0, TEE_RPMB_FS_FILENAME_LENGTH);
- memcpy(fh_old->fat_entry.filename, new_name, new_len);
+ memcpy(fh_old->fat_entry.filename, fh_new->filename,
+ strlen(fh_new->filename));
res = write_fat_entry(fh_old, false);
@@ -2477,15 +2404,20 @@ static TEE_Result rpmb_fs_dir_populate(const char *path,
goto out;
}
- memset(next, 0, sizeof(*next));
- next->entry.d_name = next->name;
- memcpy(next->name,
- &filename[pathlen],
- filelen - pathlen);
+ next->entry.oidlen = tee_hs2b(
+ (uint8_t *)&filename[pathlen],
+ next->entry.oid,
+ filelen - pathlen,
+ sizeof(next->entry.oid));
+ if (next->entry.oidlen) {
+ SIMPLEQ_INSERT_TAIL(&dir->next,
+ next, link);
+ current = next;
+ } else {
+ free(next);
+ next = NULL;
+ }
- SIMPLEQ_INSERT_TAIL(&dir->next, next,
- link);
- current = next;
}
}
@@ -2514,32 +2446,25 @@ out:
return res;
}
-static TEE_Result rpmb_fs_opendir(const char *path, struct tee_fs_dir **dir)
+static TEE_Result rpmb_fs_opendir(const TEE_UUID *uuid, struct tee_fs_dir **dir)
{
uint32_t len;
- uint32_t max_size;
char path_local[TEE_RPMB_FS_FILENAME_LENGTH];
TEE_Result res = TEE_ERROR_GENERIC;
struct tee_fs_dir *rpmb_dir = NULL;
- if (!path || !dir) {
+ if (!uuid || !dir) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
- /*
- * There must be room for at least the NULL char and a char for the
- * filename after the path.
- */
- max_size = TEE_RPMB_FS_FILENAME_LENGTH - 2;
- len = strlen(path);
- if (len > max_size || len == 0) {
+ memset(path_local, 0, sizeof(path_local));
+ if (tee_svc_storage_create_dirname(path_local, sizeof(path_local) - 1,
+ uuid) != TEE_SUCCESS) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
-
- memset(path_local, 0, sizeof(path_local));
- memcpy(path_local, path, len);
+ len = strlen(path_local);
/* Add a slash to correctly match the full directory name. */
if (path_local[len - 1] != '/')
@@ -2591,14 +2516,15 @@ static void rpmb_fs_closedir(struct tee_fs_dir *dir)
}
}
-static TEE_Result rpmb_fs_open(const char *file, struct tee_file_handle **fh)
+static TEE_Result rpmb_fs_open(struct tee_pobj *po, struct tee_file_handle **fh)
{
- return rpmb_fs_open_internal(file, false, fh);
+ return rpmb_fs_open_internal(po, false, fh);
}
-static TEE_Result rpmb_fs_create(const char *file, struct tee_file_handle **fh)
+static TEE_Result rpmb_fs_create(struct tee_pobj *po,
+ struct tee_file_handle **fh)
{
- return rpmb_fs_open_internal(file, true, fh);
+ return rpmb_fs_open_internal(po, true, fh);
}
const struct tee_file_operations rpmb_fs_ops = {
@@ -2607,7 +2533,6 @@ const struct tee_file_operations rpmb_fs_ops = {
.close = rpmb_fs_close,
.read = rpmb_fs_read,
.write = rpmb_fs_write,
- .seek = rpmb_fs_seek,
.truncate = rpmb_fs_truncate,
.rename = rpmb_fs_rename,
.remove = rpmb_fs_remove,
diff --git a/core/tee/tee_sql_fs.c b/core/tee/tee_sql_fs.c
index e38e1bc..bfc04f6 100644
--- a/core/tee/tee_sql_fs.c
+++ b/core/tee/tee_sql_fs.c
@@ -29,15 +29,6 @@
* This file implements the tee_file_operations structure for a secure
* filesystem based on an SQLite database in normal world.
* The atomicity of each operation is ensured by using SQL transactions.
- * 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 SQL filesystem, and has the following structure:
- *
- * [ File meta-data ][ Block #0 ][Block #1]...
- * [meta_header|sql_fs_file_meta][block_header|user data][ ]...
- *
- * meta_header and block_header are defined in tee_fs_key_manager.h.
*/
#include <assert.h>
@@ -45,13 +36,12 @@
#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_key_manager.h>
#include <tee/tee_fs_rpc.h>
#include <trace.h>
#include <utee_defines.h>
@@ -61,22 +51,10 @@
#define BLOCK_SHIFT 12
#define BLOCK_SIZE (1 << BLOCK_SHIFT)
-struct sql_fs_file_meta {
- size_t length;
-};
-
/* File descriptor */
struct sql_fs_fd {
- struct sql_fs_file_meta meta;
- uint8_t encrypted_fek[TEE_FS_KM_FEK_SIZE];
- tee_fs_off_t pos;
+ struct tee_fs_htree *ht;
int fd; /* returned by normal world */
- int flags; /* open flags */
-};
-
-struct tee_fs_dir {
- int nw_dir;
- struct tee_fs_dirent d;
};
static struct mutex sql_fs_mutex = MUTEX_INITIALIZER;
@@ -96,9 +74,10 @@ static TEE_Result sql_fs_end_transaction_rpc(bool rollback)
rollback);
}
-static TEE_Result sql_fs_opendir_rpc(const char *name, struct tee_fs_dir **d)
+static TEE_Result sql_fs_opendir_rpc(const TEE_UUID *uuid,
+ struct tee_fs_dir **d)
{
- return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_SQL_FS, name, d);
+ return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_SQL_FS, uuid, d);
}
static TEE_Result sql_fs_readdir_rpc(struct tee_fs_dir *d,
@@ -107,15 +86,15 @@ static TEE_Result sql_fs_readdir_rpc(struct tee_fs_dir *d,
return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_SQL_FS, d, ent);
}
-static TEE_Result sql_fs_remove_rpc(const char *file)
+static TEE_Result sql_fs_remove_rpc(struct tee_pobj *po)
{
- return tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, file);
+ return tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, po);
}
-static TEE_Result sql_fs_rename_rpc(const char *old, const char *nw,
+static TEE_Result sql_fs_rename_rpc(struct tee_pobj *old, struct tee_pobj *new,
bool overwrite)
{
- return tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_SQL_FS, old, nw, overwrite);
+ return tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_SQL_FS, old, new, overwrite);
}
static void sql_fs_closedir_rpc(struct tee_fs_dir *d)
@@ -128,21 +107,6 @@ static void sql_fs_closedir_rpc(struct tee_fs_dir *d)
* End of interface with tee-supplicant
*/
-static size_t meta_size(void)
-{
- return tee_fs_get_header_size(META_FILE) +
- sizeof(struct sql_fs_file_meta);
-}
-
-static size_t block_header_size(void)
-{
- return tee_fs_get_header_size(BLOCK_FILE);
-}
-
-static size_t block_size_raw(void)
-{
- return block_header_size() + BLOCK_SIZE;
-}
/* Return the block number from a position in the user data */
static ssize_t block_num(tee_fs_off_t pos)
@@ -150,131 +114,108 @@ static ssize_t block_num(tee_fs_off_t pos)
return pos / BLOCK_SIZE;
}
-/* Return the position of a block in the DB file */
-static ssize_t block_pos_raw(size_t block_num)
+static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
+ size_t *offs, size_t *size)
{
- return meta_size() + block_num * block_size_raw();
-}
-
-static TEE_Result write_meta(struct sql_fs_fd *fdp)
-{
- TEE_Result res;
- size_t ct_size = meta_size();
- void *ct;
- struct tee_fs_rpc_operation op;
-
- res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd, 0,
- ct_size, &ct);
- if (res != TEE_SUCCESS)
- return res;
-
-
- res = tee_fs_encrypt_file(META_FILE,
- (const uint8_t *)&fdp->meta,
- sizeof(fdp->meta), ct, &ct_size,
- fdp->encrypted_fek);
- if (res != TEE_SUCCESS)
- return res;
-
- return tee_fs_rpc_write_final(&op);
+ const size_t node_size = sizeof(struct tee_fs_htree_node_image);
+ const size_t block_nodes = BLOCK_SIZE / node_size;
+ size_t pbn;
+ size_t bidx;
+
+
+ /*
+ * File layout
+ *
+ * phys block 0:
+ * tee_fs_htree_image @ offs = 0
+ *
+ * phys block 1:
+ * tee_fs_htree_node_image 0 @ offs = 0
+ * tee_fs_htree_node_image 1 @ offs = node_size * 2
+ * ...
+ * tee_fs_htree_node_image 61 @ offs = node_size * 122
+ *
+ * phys block 2:
+ * data block 0
+ *
+ * ...
+ *
+ * phys block 64:
+ * data block 61
+ *
+ * phys block 65:
+ * tee_fs_htree_node_image 62 @ offs = 0
+ * tee_fs_htree_node_image 63 @ offs = node_size * 2
+ * ...
+ * tee_fs_htree_node_image 121 @ offs = node_size * 123
+ *
+ * ...
+ */
+
+ switch (type) {
+ case TEE_FS_HTREE_TYPE_HEAD:
+ *offs = 0;
+ *size = sizeof(struct tee_fs_htree_image);
+ return TEE_SUCCESS;
+ case TEE_FS_HTREE_TYPE_NODE:
+ pbn = 1 + ((idx / block_nodes) * block_nodes);
+ *offs = pbn * BLOCK_SIZE + node_size * (idx % block_nodes);
+ *size = node_size;
+ return TEE_SUCCESS;
+ case TEE_FS_HTREE_TYPE_BLOCK:
+ bidx = idx;
+ pbn = 2 + bidx + bidx / (block_nodes - 1);
+ *offs = pbn * BLOCK_SIZE;
+ *size = BLOCK_SIZE;
+ return TEE_SUCCESS;
+ default:
+ return TEE_ERROR_GENERIC;
+ }
}
-static TEE_Result create_meta(struct sql_fs_fd *fdp, const char *fname)
+static TEE_Result sql_fs_rpc_read_init(void *aux,
+ struct tee_fs_rpc_operation *op,
+ enum tee_fs_htree_type type, size_t idx,
+ uint8_t vers __unused, void **data)
{
+ struct sql_fs_fd *fdp = aux;
TEE_Result res;
+ size_t offs;
+ size_t size;
- memset(&fdp->meta, 0, sizeof(fdp->meta));
-
- res = tee_fs_generate_fek(fdp->encrypted_fek, TEE_FS_KM_FEK_SIZE);
- if (res != TEE_SUCCESS)
- return res;
-
- res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_SQL_FS, fname, &fdp->fd);
+ res = get_offs_size(type, idx, &offs, &size);
if (res != TEE_SUCCESS)
return res;
- return write_meta(fdp);
+ return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd,
+ offs, size, data);
}
-static TEE_Result read_meta(struct sql_fs_fd *fdp, const char *fname)
+static TEE_Result sql_fs_rpc_write_init(void *aux,
+ struct tee_fs_rpc_operation *op,
+ enum tee_fs_htree_type type, size_t idx,
+ uint8_t vers __unused, void **data)
{
+ struct sql_fs_fd *fdp = aux;
TEE_Result res;
- size_t msize = meta_size();
- size_t out_size = sizeof(fdp->meta);
- void *meta;
- size_t bytes;
- struct tee_fs_rpc_operation op;
-
- res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_SQL_FS, fname, &fdp->fd);
- if (res != TEE_SUCCESS)
- return res;
-
- res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd, 0,
- msize, &meta);
- if (res != TEE_SUCCESS)
- return res;
-
- res = tee_fs_rpc_read_final(&op, &bytes);
- if (res != TEE_SUCCESS)
- return res;
+ size_t offs;
+ size_t size;
- return tee_fs_decrypt_file(META_FILE, meta, msize,
- (uint8_t *)&fdp->meta, &out_size,
- fdp->encrypted_fek);
-}
-
-/*
- * Read one block of user data.
- * Returns:
- * < 0: read error
- * 0: block does not exist (reading past last block)
- * > 0: success
- */
-static TEE_Result read_block(struct sql_fs_fd *fdp, size_t 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(bnum);
- size_t bytes;
- void *ct;
- struct tee_fs_rpc_operation op;
-
- res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd, pos,
- ct_size, &ct);
+ res = get_offs_size(type, idx, &offs, &size);
if (res != TEE_SUCCESS)
return res;
- res = tee_fs_rpc_read_final(&op, &bytes);
- if (res != TEE_SUCCESS)
- return res;
- if (!bytes)
- return TEE_SUCCESS; /* Block does not exist */
- return tee_fs_decrypt_file(BLOCK_FILE, ct, bytes, data,
- &out_size, fdp->encrypted_fek);
+ return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd,
+ offs, size, data);
}
-/* Write one block of user data */
-static TEE_Result write_block(struct sql_fs_fd *fdp, size_t bnum, uint8_t *data)
-{
- TEE_Result res;
- size_t ct_size = block_size_raw();
- ssize_t pos = block_pos_raw(bnum);
- void *ct;
- struct tee_fs_rpc_operation op;
-
- res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd, pos,
- ct_size, &ct);
- if (res != TEE_SUCCESS)
- return res;
-
- res = tee_fs_encrypt_file(BLOCK_FILE, data, BLOCK_SIZE, ct,
- &ct_size, fdp->encrypted_fek);
- if (res != TEE_SUCCESS)
- return res;
-
- return tee_fs_rpc_write_final(&op);
-}
+static const struct tee_fs_htree_storage sql_fs_storage_ops = {
+ .block_size = BLOCK_SIZE,
+ .rpc_read_init = sql_fs_rpc_read_init,
+ .rpc_read_final = tee_fs_rpc_read_final,
+ .rpc_write_init = sql_fs_rpc_write_init,
+ .rpc_write_final = tee_fs_rpc_write_final,
+};
/*
* Partial write (< BLOCK_SIZE) into a block: read/update/write
@@ -296,16 +237,21 @@ static TEE_Result write_block_partial(struct sql_fs_fd *fdp, size_t bnum,
if (!buf)
return TEE_ERROR_OUT_OF_MEMORY;
- res = read_block(fdp, bnum, buf);
- if (res != TEE_SUCCESS)
- goto exit;
+ if (bnum * BLOCK_SIZE <
+ ROUNDUP(tee_fs_htree_get_meta(fdp->ht)->length, BLOCK_SIZE)) {
+ res = tee_fs_htree_read_block(&fdp->ht, bnum, buf);
+ if (res != TEE_SUCCESS)
+ goto exit;
+ } else {
+ memset(buf, 0, BLOCK_SIZE);
+ }
if (data)
memcpy(buf + offset, data, len);
else
memset(buf + offset, 0, len);
- res = write_block(fdp, bnum, buf);
+ res = tee_fs_htree_write_block(&fdp->ht, bnum, buf);
exit:
free(buf);
return res;
@@ -315,32 +261,42 @@ static TEE_Result sql_fs_ftruncate_internal(struct sql_fs_fd *fdp,
tee_fs_off_t new_length)
{
TEE_Result res;
- tee_fs_off_t old_length;
-
- old_length = (tee_fs_off_t)fdp->meta.length;
+ struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
- if (new_length == old_length)
+ if ((size_t)new_length == meta->length)
return TEE_SUCCESS;
sql_fs_begin_transaction_rpc();
- if (new_length < old_length) {
+ if ((size_t)new_length < meta->length) {
/* Trim unused blocks */
- int old_last_block = block_num(old_length);
+ int old_last_block = block_num(meta->length);
int last_block = block_num(new_length);
- tee_fs_off_t off;
if (last_block < old_last_block) {
- off = block_pos_raw(last_block);
+ size_t offs;
+ size_t sz;
+
+ res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
+ ROUNDUP(new_length, BLOCK_SIZE) /
+ BLOCK_SIZE, &offs, &sz);
+ if (res != TEE_SUCCESS)
+ goto exit;
+
+ res = tee_fs_htree_truncate(&fdp->ht,
+ new_length / BLOCK_SIZE);
+ if (res != TEE_SUCCESS)
+ goto exit;
+
res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_SQL_FS,
- fdp->fd, off);
+ fdp->fd, offs + sz);
if (res != TEE_SUCCESS)
goto exit;
}
} else {
/* Extend file with zeroes */
- tee_fs_off_t off = old_length % BLOCK_SIZE;
- size_t bnum = block_num(old_length);
+ tee_fs_off_t off = meta->length % BLOCK_SIZE;
+ size_t bnum = block_num(meta->length);
size_t end_bnum = block_num(new_length);
while (bnum <= end_bnum) {
@@ -354,70 +310,28 @@ static TEE_Result sql_fs_ftruncate_internal(struct sql_fs_fd *fdp,
}
}
- fdp->meta.length = new_length;
- res = write_meta(fdp);
+ meta->length = new_length;
+ res = TEE_SUCCESS;
exit:
+ if (res == TEE_SUCCESS)
+ res = tee_fs_htree_sync_to_storage(&fdp->ht);
sql_fs_end_transaction_rpc(res != TEE_SUCCESS);
return res;
}
-static TEE_Result sql_fs_seek(struct tee_file_handle *fh, int32_t offset,
- TEE_Whence whence, int32_t *new_offs)
-{
- TEE_Result res;
- struct sql_fs_fd *fdp = (struct sql_fs_fd *)fh;
- tee_fs_off_t pos;
-
- mutex_lock(&sql_fs_mutex);
-
- switch (whence) {
- case TEE_DATA_SEEK_SET:
- pos = offset;
- break;
-
- case TEE_DATA_SEEK_CUR:
- pos = fdp->pos + offset;
- break;
-
- case TEE_DATA_SEEK_END:
- pos = fdp->meta.length + offset;
- break;
-
- default:
- res = TEE_ERROR_BAD_PARAMETERS;
- goto exit_ret;
- }
-
- if (pos > TEE_DATA_MAX_POSITION) {
- EMSG("Position is beyond TEE_DATA_MAX_POSITION");
- res = TEE_ERROR_BAD_PARAMETERS;
- goto exit_ret;
- }
-
- if (pos < 0)
- pos = 0;
-
- fdp->pos = pos;
- if (new_offs)
- *new_offs = pos;
- res = TEE_SUCCESS;
-exit_ret:
- mutex_unlock(&sql_fs_mutex);
- return res;
-}
-
static void sql_fs_close(struct tee_file_handle **fh)
{
struct sql_fs_fd *fdp = (struct sql_fs_fd *)*fh;
if (fdp) {
- tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd);
+ tee_fs_htree_close(&fdp->ht);
+ tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd);
free(fdp);
*fh = NULL;
}
}
-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;
@@ -432,36 +346,41 @@ static TEE_Result open_internal(const char *file, bool create,
mutex_lock(&sql_fs_mutex);
if (create)
- res = create_meta(fdp, file);
+ res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_SQL_FS, po, &fdp->fd);
else
- res = read_meta(fdp, file);
+ res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_SQL_FS, po, &fdp->fd);
+ if (res != TEE_SUCCESS)
+ goto out;
+ res = tee_fs_htree_open(create, &sql_fs_storage_ops, fdp, &fdp->ht);
+out:
if (res == TEE_SUCCESS) {
*fh = (struct tee_file_handle *)fdp;
} else {
if (fdp && fdp->fd != -1)
tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd);
if (created)
- tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, file);
+ tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, po);
free(fdp);
}
mutex_unlock(&sql_fs_mutex);
return res;
}
-static TEE_Result sql_fs_open(const char *file, struct tee_file_handle **fh)
+static TEE_Result sql_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 sql_fs_create(const char *file, struct tee_file_handle **fh)
+static TEE_Result sql_fs_create(struct tee_pobj *po,
+ struct tee_file_handle **fh)
{
- return open_internal(file, true, fh);
+ return open_internal(po, true, fh);
}
-static TEE_Result sql_fs_read(struct tee_file_handle *fh, void *buf,
- size_t *len)
+static TEE_Result sql_fs_read(struct tee_file_handle *fh, size_t pos,
+ void *buf, size_t *len)
{
TEE_Result res;
struct sql_fs_fd *fdp = (struct sql_fs_fd *)fh;
@@ -470,14 +389,15 @@ static TEE_Result sql_fs_read(struct tee_file_handle *fh, void *buf,
uint8_t *block = NULL;
int start_block_num;
int end_block_num;
+ size_t file_size;
mutex_lock(&sql_fs_mutex);
- if ((fdp->pos + remain_bytes) < remain_bytes ||
- fdp->pos > (tee_fs_off_t)fdp->meta.length)
+ file_size = tee_fs_htree_get_meta(fdp->ht)->length;
+ if ((pos + remain_bytes) < remain_bytes || pos > file_size)
remain_bytes = 0;
- else if (fdp->pos + remain_bytes > fdp->meta.length)
- remain_bytes = fdp->meta.length - fdp->pos;
+ else if (pos + remain_bytes > file_size)
+ remain_bytes = file_size - pos;
*len = remain_bytes;
@@ -486,8 +406,8 @@ static TEE_Result sql_fs_read(struct tee_file_handle *fh, void *buf,
goto exit;
}
- start_block_num = block_num(fdp->pos);
- end_block_num = block_num(fdp->pos + remain_bytes - 1);
+ start_block_num = block_num(pos);
+ end_block_num = block_num(pos + remain_bytes - 1);
block = malloc(BLOCK_SIZE);
if (!block) {
@@ -496,17 +416,13 @@ static TEE_Result sql_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;
- /*
- * REVISIT: implement read_block_partial() since we have
- * write_block_partial()?
- */
- res = read_block(fdp, start_block_num, block);
+ res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
if (res != TEE_SUCCESS)
goto exit;
@@ -514,7 +430,7 @@ static TEE_Result sql_fs_read(struct tee_file_handle *fh, void *buf,
data_ptr += size_to_read;
remain_bytes -= size_to_read;
- fdp->pos += size_to_read;
+ pos += size_to_read;
start_block_num++;
}
@@ -525,11 +441,12 @@ exit:
return res;
}
-static TEE_Result sql_fs_write(struct tee_file_handle *fh, const void *buf,
- size_t len)
+static TEE_Result sql_fs_write(struct tee_file_handle *fh, size_t pos,
+ const void *buf, size_t len)
{
TEE_Result res;
struct sql_fs_fd *fdp = (struct sql_fs_fd *)fh;
+ struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
size_t remain_bytes = len;
const uint8_t *data_ptr = buf;
int start_block_num;
@@ -542,18 +459,18 @@ static TEE_Result sql_fs_write(struct tee_file_handle *fh, const void *buf,
sql_fs_begin_transaction_rpc();
- if (fdp->meta.length < (size_t)fdp->pos) {
+ if (meta->length < pos) {
/* Fill hole */
- res = sql_fs_ftruncate_internal(fdp, fdp->pos);
+ res = sql_fs_ftruncate_internal(fdp, pos);
if (res != TEE_SUCCESS)
goto exit;
}
- start_block_num = block_num(fdp->pos);
- end_block_num = block_num(fdp->pos + len - 1);
+ start_block_num = block_num(pos);
+ end_block_num = block_num(pos + len - 1);
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_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
if (size_to_write + offset > BLOCK_SIZE)
@@ -566,16 +483,17 @@ static TEE_Result sql_fs_write(struct tee_file_handle *fh, const void *buf,
data_ptr += size_to_write;
remain_bytes -= size_to_write;
- fdp->pos += size_to_write;
+ pos += size_to_write;
start_block_num++;
}
- if (fdp->meta.length < (size_t)fdp->pos) {
- fdp->meta.length = fdp->pos;
- res = write_meta(fdp);
- }
+ if (pos > meta->length)
+ meta->length = pos;
+
exit:
+ if (res == TEE_SUCCESS)
+ res = tee_fs_htree_sync_to_storage(&fdp->ht);
sql_fs_end_transaction_rpc(res != TEE_SUCCESS);
mutex_unlock(&sql_fs_mutex);
return res;
@@ -599,7 +517,6 @@ const struct tee_file_operations sql_fs_ops = {
.close = sql_fs_close,
.read = sql_fs_read,
.write = sql_fs_write,
- .seek = sql_fs_seek,
.truncate = sql_fs_truncate,
.opendir = sql_fs_opendir_rpc,
diff --git a/core/tee/tee_svc_storage.c b/core/tee/tee_svc_storage.c
index 916ddca..d852be1 100644
--- a/core/tee/tee_svc_storage.c
+++ b/core/tee/tee_svc_storage.c
@@ -32,7 +32,6 @@
#include <string.h>
#include <tee_api_defines_extensions.h>
#include <tee_api_defines.h>
-#include <tee/tee_fs_defs.h>
#include <tee/tee_fs.h>
#include <tee/tee_obj.h>
#include <tee/tee_pobj.h>
@@ -99,12 +98,6 @@ struct tee_storage_enum {
const struct tee_file_operations *fops;
};
-/*
- * Protect TA storage directory: avoid race conditions between (create
- * directory + create file) and (remove directory)
- */
-static struct mutex ta_dir_mutex = MUTEX_INITIALIZER;
-
static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
uint32_t enum_id,
struct tee_storage_enum **e_out)
@@ -140,114 +133,77 @@ static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
}
/* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */
-char *tee_svc_storage_create_filename(struct tee_ta_session *sess,
- void *object_id,
- uint32_t object_id_len,
- bool transient)
+TEE_Result tee_svc_storage_create_filename(void *buf, size_t blen,
+ struct tee_pobj *po, bool transient)
{
- uint8_t *file;
+ uint8_t *file = buf;
uint32_t pos = 0;
uint32_t hslen = 1 /* Leading slash */
- + TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len)
+ + TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + po->obj_id_len)
+ 1; /* Intermediate slash */
/* +1 for the '.' (temporary persistent object) */
if (transient)
hslen++;
- file = malloc(hslen);
- if (!file)
- return NULL;
+ if (blen < hslen)
+ return TEE_ERROR_SHORT_BUFFER;
file[pos++] = '/';
- pos += tee_b2hs((uint8_t *)&sess->ctx->uuid, &file[pos],
+ pos += tee_b2hs((uint8_t *)&po->uuid, &file[pos],
sizeof(TEE_UUID), hslen);
file[pos++] = '/';
if (transient)
file[pos++] = '.';
- tee_b2hs(object_id, file + pos, object_id_len, hslen - pos);
+ tee_b2hs(po->obj_id, file + pos, po->obj_id_len, hslen - pos);
- return (char *)file;
+ return TEE_SUCCESS;
}
/* "/TA_uuid" */
-char *tee_svc_storage_create_dirname(struct tee_ta_session *sess)
+TEE_Result tee_svc_storage_create_dirname(void *buf, size_t blen,
+ const TEE_UUID *uuid)
{
- uint8_t *dir;
+ uint8_t *dir = buf;
uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1;
- dir = malloc(hslen);
- if (!dir)
- return NULL;
+ if (blen < hslen)
+ return TEE_ERROR_SHORT_BUFFER;
dir[0] = '/';
- tee_b2hs((uint8_t *)&sess->ctx->uuid, dir + 1, sizeof(TEE_UUID),
- hslen);
+ tee_b2hs((uint8_t *)uuid, dir + 1, sizeof(TEE_UUID), hslen);
- return (char *)dir;
+ return TEE_SUCCESS;
}
static TEE_Result tee_svc_storage_remove_corrupt_obj(
struct tee_ta_session *sess,
struct tee_obj *o)
{
- TEE_Result res;
- char *file = NULL;
- const struct tee_file_operations *fops = o->pobj->fops;
-
- 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;
- }
-
+ o->pobj->fops->remove(o->pobj);
tee_obj_close(to_user_ta_ctx(sess->ctx), o);
- fops->remove(file);
- free(file);
- res = TEE_SUCCESS;
-
-exit:
- return res;
+ return TEE_SUCCESS;
}
-static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
- struct tee_obj *o)
+static TEE_Result tee_svc_storage_read_head(struct tee_obj *o)
{
TEE_Result res = TEE_SUCCESS;
size_t bytes;
struct tee_svc_storage_head head;
- char *file = NULL;
- const struct tee_file_operations *fops;
+ const struct tee_file_operations *fops = o->pobj->fops;
void *attr = NULL;
- if (o == NULL || o->pobj == NULL)
- return TEE_ERROR_BAD_PARAMETERS;
-
- fops = o->pobj->fops;
-
- 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;
- }
-
assert(!o->fh);
- res = fops->open(file, &o->fh);
+ res = fops->open(o->pobj, &o->fh);
if (res != TEE_SUCCESS)
goto exit;
/* read head */
bytes = sizeof(struct tee_svc_storage_head);
- res = fops->read(o->fh, &head, &bytes);
+ res = fops->read(o->fh, 0, &head, &bytes);
if (res != TEE_SUCCESS) {
if (res == TEE_ERROR_CORRUPT_OBJECT)
EMSG("Head corrupt\n");
@@ -263,6 +219,7 @@ static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
if (res != TEE_SUCCESS)
goto exit;
+ o->ds_pos = sizeof(struct tee_svc_storage_head) + head.meta_size;
if (head.meta_size) {
attr = malloc(head.meta_size);
if (!attr) {
@@ -272,7 +229,8 @@ static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
/* read meta */
bytes = head.meta_size;
- res = fops->read(o->fh, attr, &bytes);
+ res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
+ attr, &bytes);
if (res != TEE_SUCCESS || bytes != head.meta_size) {
res = TEE_ERROR_CORRUPT_OBJECT;
goto exit;
@@ -291,7 +249,6 @@ static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
exit:
free(attr);
- free(file);
return res;
}
@@ -299,63 +256,22 @@ exit:
static TEE_Result tee_svc_storage_update_head(struct tee_obj *o,
uint32_t ds_size)
{
- TEE_Result res;
- const struct tee_file_operations *fops;
- int32_t old_off;
+ size_t pos = offsetof(struct tee_svc_storage_head, ds_size);
- fops = o->pobj->fops;
-
- /* save original offset */
- res = fops->seek(o->fh, 0, TEE_DATA_SEEK_CUR, &old_off);
- if (res != TEE_SUCCESS)
- return res;
-
- /* update head.ds_size */
- res = fops->seek(o->fh, offsetof(struct tee_svc_storage_head,
- ds_size), TEE_DATA_SEEK_SET, NULL);
- if (res != TEE_SUCCESS)
- return res;
-
- res = fops->write(o->fh, &ds_size, sizeof(uint32_t));
- if (res != TEE_SUCCESS)
- return res;
-
- /* restore original offset */
- res = fops->seek(o->fh, old_off, TEE_DATA_SEEK_SET, NULL);
- return res;
+ return o->pobj->fops->write(o->fh, pos, &ds_size, sizeof(uint32_t));
}
-static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
- struct tee_obj *o,
+static TEE_Result tee_svc_storage_init_file(struct tee_obj *o,
struct tee_obj *attr_o, void *data,
uint32_t len)
{
TEE_Result res = TEE_SUCCESS;
struct tee_svc_storage_head head;
- char *tmpfile = NULL;
- const struct tee_file_operations *fops;
+ const struct tee_file_operations *fops = o->pobj->fops;
void *attr = NULL;
size_t attr_size = 0;
- if (o == NULL || o->pobj == NULL)
- return TEE_ERROR_BAD_PARAMETERS;
-
- fops = o->pobj->fops;
-
- /* create temporary persistent object filename */
- tmpfile = tee_svc_storage_create_filename(sess,
- o->pobj->obj_id,
- o->pobj->obj_id_len,
- true);
-
- if (tmpfile == NULL) {
- res = TEE_ERROR_OUT_OF_MEMORY;
- goto exit;
- }
-
- mutex_lock(&ta_dir_mutex);
- res = fops->create(tmpfile, &o->fh);
- mutex_unlock(&ta_dir_mutex);
+ res = fops->create(o->pobj, &o->fh);
if (res != TEE_SUCCESS)
goto exit;
@@ -389,6 +305,8 @@ static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
goto exit;
}
+ o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
+
/* write head */
head.magic = TEE_SVC_STORAGE_MAGIC;
head.head_size = sizeof(struct tee_svc_storage_head);
@@ -401,12 +319,13 @@ static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
head.have_attrs = o->have_attrs;
/* write head */
- res = fops->write(o->fh, &head, sizeof(struct tee_svc_storage_head));
+ res = fops->write(o->fh, 0, &head, sizeof(struct tee_svc_storage_head));
if (res != TEE_SUCCESS)
goto exit;
/* write meta */
- res = fops->write(o->fh, attr, attr_size);
+ res = fops->write(o->fh, sizeof(struct tee_svc_storage_head),
+ attr, attr_size);
if (res != TEE_SUCCESS)
goto exit;
@@ -415,11 +334,10 @@ static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
/* write data to fs if needed */
if (data && len)
- res = fops->write(o->fh, data, len);
+ res = fops->write(o->fh, o->ds_pos, data, len);
exit:
free(attr);
- free(tmpfile);
fops->close(&o->fh);
return res;
@@ -462,7 +380,7 @@ TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
goto err;
res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
- object_id_len, flags, fops, &po);
+ object_id_len, flags, false, fops, &po);
if (res != TEE_SUCCESS)
goto err;
@@ -479,7 +397,7 @@ TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
o->pobj = po;
tee_obj_add(utc, o);
- res = tee_svc_storage_read_head(sess, o);
+ res = tee_svc_storage_read_head(o);
if (res != TEE_SUCCESS) {
if (res == TEE_ERROR_CORRUPT_OBJECT) {
EMSG("Object corrupt");
@@ -496,11 +414,6 @@ TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
if (res != TEE_SUCCESS)
goto oclose;
- res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
- TEE_DATA_SEEK_SET, NULL);
- if (res != TEE_SUCCESS)
- goto err;
-
goto exit;
oclose:
@@ -528,9 +441,7 @@ TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
struct tee_ta_session *sess;
struct tee_obj *o = NULL;
struct tee_obj *attr_o = NULL;
- char *file = NULL;
struct tee_pobj *po = NULL;
- char *tmpfile = NULL;
struct user_ta_ctx *utc;
const struct tee_file_operations *fops = file_ops(storage_id);
size_t attr_size;
@@ -555,7 +466,7 @@ TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
goto err;
res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
- object_id_len, flags, fops, &po);
+ object_id_len, flags, true, fops, &po);
if (res != TEE_SUCCESS)
goto err;
@@ -588,33 +499,17 @@ TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
goto err;
}
- res = tee_svc_storage_init_file(sess, o, attr_o, data, len);
+ res = tee_svc_storage_init_file(o, attr_o, data, len);
if (res != TEE_SUCCESS)
goto err;
- /* create persistent object filename */
- file = tee_svc_storage_create_filename(sess, object_id,
- object_id_len, false);
- if (file == NULL) {
- res = TEE_ERROR_OUT_OF_MEMORY;
- goto err;
- }
-
- /* create temporary persistent object filename */
- tmpfile = tee_svc_storage_create_filename(sess, object_id,
- object_id_len,
- true);
- if (tmpfile == NULL) {
- res = TEE_ERROR_OUT_OF_MEMORY;
- goto err;
- }
-
/* rename temporary persistent object filename */
- res = fops->rename(tmpfile, file, !!(flags & TEE_DATA_FLAG_OVERWRITE));
+ po->temporary = false;
+ res = fops->rename(po, NULL, !!(flags & TEE_DATA_FLAG_OVERWRITE));
if (res != TEE_SUCCESS)
goto rmfile;
- res = fops->open(file, &o->fh);
+ res = fops->open(po, &o->fh);
if (res != TEE_SUCCESS)
goto err;
@@ -628,35 +523,26 @@ TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
if (res != TEE_SUCCESS)
goto oclose;
- res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
- TEE_DATA_SEEK_SET, NULL);
- if (res != TEE_SUCCESS)
- goto oclose;
-
- goto exit;
+ return TEE_SUCCESS;
oclose:
tee_obj_close(utc, o);
- goto exit;
+ return res;
rmfile:
- fops->remove(tmpfile);
+ fops->remove(po);
err:
if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
res = TEE_ERROR_CORRUPT_OBJECT;
- if (res == TEE_ERROR_CORRUPT_OBJECT && file)
- fops->remove(file);
+ if (res == TEE_ERROR_CORRUPT_OBJECT && po)
+ fops->remove(po);
if (o)
fops->close(&o->fh);
if (po)
tee_pobj_release(po);
free(o);
-exit:
- free(file);
- free(tmpfile);
-
return res;
}
@@ -665,9 +551,7 @@ TEE_Result syscall_storage_obj_del(unsigned long obj)
TEE_Result res;
struct tee_ta_session *sess;
struct tee_obj *o;
- char *file;
struct user_ta_ctx *utc;
- const struct tee_file_operations *fops;
res = tee_ta_get_current_session(&sess);
if (res != TEE_SUCCESS)
@@ -684,16 +568,9 @@ TEE_Result syscall_storage_obj_del(unsigned long obj)
if (o->pobj == NULL || o->pobj->obj_id == NULL)
return TEE_ERROR_BAD_STATE;
- file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
- o->pobj->obj_id_len, false);
- if (file == NULL)
- return TEE_ERROR_OUT_OF_MEMORY;
-
- fops = o->pobj->fops;
+ res = o->pobj->fops->remove(o->pobj);
tee_obj_close(utc, o);
- res = fops->remove(file);
- free(file);
return res;
}
@@ -743,31 +620,16 @@ TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
if (res != TEE_SUCCESS)
goto exit;
- /* get new ds name */
- new_file = tee_svc_storage_create_filename(sess, object_id,
- object_id_len, false);
- if (new_file == NULL) {
- res = TEE_ERROR_OUT_OF_MEMORY;
- goto exit;
- }
-
- old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
- o->pobj->obj_id_len, false);
- if (old_file == NULL) {
- res = TEE_ERROR_OUT_OF_MEMORY;
- goto exit;
- }
-
/* reserve dest name */
fops = o->pobj->fops;
res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
- fops, &po);
+ false, fops, &po);
if (res != TEE_SUCCESS)
goto exit;
/* move */
- res = fops->rename(old_file, new_file, false /* no overwrite */);
+ res = fops->rename(o->pobj, po, false /* no overwrite */);
if (res == TEE_ERROR_GENERIC)
goto exit;
@@ -843,48 +705,39 @@ TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
if (res != TEE_SUCCESS)
return res;
- e->fops->closedir(e->dir);
- e->fops = NULL;
- e->dir = NULL;
+ if (e->fops) {
+ e->fops->closedir(e->dir);
+ e->fops = NULL;
+ e->dir = NULL;
+ }
+ assert(!e->dir);
return TEE_SUCCESS;
}
-static TEE_Result tee_svc_storage_set_enum(char *d_name,
+static TEE_Result tee_svc_storage_set_enum(struct tee_fs_dirent *d,
const struct tee_file_operations *fops,
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) {
- 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;
- o->pobj->fops = fops;
-
- res = TEE_SUCCESS;
+ o->pobj->obj_id = malloc(d->oidlen);
+ if (!o->pobj->obj_id)
+ return TEE_ERROR_OUT_OF_MEMORY;
-exit:
- return res;
+ memcpy(o->pobj->obj_id, d->oid, d->oidlen);
+ o->pobj->obj_id_len = d->oidlen;
+ o->pobj->fops = fops;
+ return TEE_SUCCESS;
}
TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
unsigned long storage_id)
{
struct tee_storage_enum *e;
- char *dir;
TEE_Result res;
struct tee_ta_session *sess;
const struct tee_file_operations *fops = file_ops(storage_id);
@@ -902,17 +755,8 @@ TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
return TEE_ERROR_ITEM_NOT_FOUND;
e->fops = fops;
- dir = tee_svc_storage_create_dirname(sess);
- if (dir == NULL) {
- res = TEE_ERROR_OUT_OF_MEMORY;
- goto exit;
- }
-
assert(!e->dir);
- res = fops->opendir(dir, &e->dir);
- free(dir);
-exit:
- return res;
+ return fops->opendir(&sess->ctx->uuid, &e->dir);
}
TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
@@ -975,11 +819,12 @@ TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
goto exit;
}
- res = tee_svc_storage_set_enum(d->d_name, e->fops, o);
+ o->pobj->uuid = sess->ctx->uuid;
+ res = tee_svc_storage_set_enum(d, e->fops, o);
if (res != TEE_SUCCESS)
goto exit;
- res = tee_svc_storage_read_head(sess, o);
+ res = tee_svc_storage_read_head(o);
if (res != TEE_SUCCESS)
goto exit;
@@ -1040,7 +885,8 @@ TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
goto exit;
bytes = len;
- res = o->pobj->fops->read(o->fh, data, &bytes);
+ res = o->pobj->fops->read(o->fh, o->ds_pos + o->info.dataPosition,
+ data, &bytes);
if (res != TEE_SUCCESS) {
EMSG("Error code=%x\n", (uint32_t)res);
if (res == TEE_ERROR_CORRUPT_OBJECT) {
@@ -1092,7 +938,8 @@ TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
if (res != TEE_SUCCESS)
goto exit;
- res = o->pobj->fops->write(o->fh, data, len);
+ res = o->pobj->fops->write(o->fh, o->ds_pos + o->info.dataPosition,
+ data, len);
if (res != TEE_SUCCESS)
goto exit;
@@ -1163,39 +1010,50 @@ TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
TEE_Result res;
struct tee_ta_session *sess;
struct tee_obj *o;
- int32_t off;
size_t attr_size;
+ tee_fs_off_t new_pos;
res = tee_ta_get_current_session(&sess);
if (res != TEE_SUCCESS)
- goto exit;
+ return res;
res = tee_obj_get(to_user_ta_ctx(sess->ctx),
tee_svc_uref_to_vaddr(obj), &o);
if (res != TEE_SUCCESS)
- goto exit;
+ return res;
- if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
- res = TEE_ERROR_BAD_STATE;
- goto exit;
- }
+ if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
+ return TEE_ERROR_BAD_STATE;
res = tee_obj_attr_to_binary(o, NULL, &attr_size);
if (res != TEE_SUCCESS)
- goto exit;
+ return res;
- off = offset;
- if (whence == TEE_DATA_SEEK_SET)
- off += sizeof(struct tee_svc_storage_head) + attr_size;
+ switch (whence) {
+ case TEE_DATA_SEEK_SET:
+ new_pos = offset;
+ break;
+ case TEE_DATA_SEEK_CUR:
+ new_pos = o->info.dataPosition + offset;
+ break;
+ case TEE_DATA_SEEK_END:
+ new_pos = o->info.dataSize + offset;
+ break;
+ default:
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
- res = o->pobj->fops->seek(o->fh, off, whence, &off);
- if (res != TEE_SUCCESS)
- goto exit;
- o->info.dataPosition = off - (sizeof(struct tee_svc_storage_head) +
- attr_size);
+ if (new_pos < 0)
+ new_pos = 0;
-exit:
- return res;
+ if (new_pos > TEE_DATA_MAX_POSITION) {
+ EMSG("Position is beyond TEE_DATA_MAX_POSITION");
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ o->info.dataPosition = new_pos;
+
+ return TEE_SUCCESS;
}
void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)