当前位置: 首页 > 工具软件 > REE > 使用案例 >

OPTEE OS V3.3 REE FS 文件系统分析

翟元凯
2023-12-01

相关代码涉及主要涉及3个c文件,我们从底层开始

1. tee_ree_fs.c文件中

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,
};

这几个接口就是通过rpc调用非安全世界(linux/android)的读写接口,数据一般都是在tee端加密后调用这些接口传递给非安全端,由非安全端进行存储。

2. fs_htree.c文件是REE FS文件系统的核心代码,其核心思想是通过数据备份以达到断电保护的作用,代码依赖上诉rpc读写接口

文件的结构:

    /*
     * File layout
     * [demo with input:
     * BLOCK_SIZE = 4096,
     * node_size = 66,
     * block_nodes = 4096/(66*2) = 31 ]
     *
     * 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 30 vers 0 @ offs = node_size * 60
     * tee_fs_htree_node_image 30 vers 1 @ offs = node_size * 61
     *
     * phys block 2:
     * data block 0 vers 0
     *
     * phys block 3:
     * data block 0 vers 1
     *
     * ...
     * phys block 62:
     * data block 30 vers 0
     *
     * phys block 63:
     * data block 30 vers 1
     *
     * phys block 64:
     * tee_fs_htree_node_image 31  vers 0 @ offs = 0
     * tee_fs_htree_node_image 31  vers 1 @ offs = node_size
     * tee_fs_htree_node_image 32  vers 0 @ offs = node_size * 2
     * tee_fs_htree_node_image 32  vers 1 @ offs = node_size * 3
     * ...
     * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 60
     * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 61
     *
     * phys block 65:
     * data block 31 vers 0
     *
     * phys block 66:
     * data block 31 vers 1
     * ...
     */

node在存储的时候看似依次存储,实际在打开文件时会把node转成二叉树!node0是根节点,node1和node2是node0的子节点,node3和node4是node1的子节点,以此类推。假如有这么一个文件,他的所有数据都是存在vers0中的,现在我们更改其中的data block 6数据,我们会把数据加密然后存在data block 6 vers1中,同时修改对应node->node.flags = 1(表示使用data block 6 vers1而不是data block 6 vers0);若此时发生断电,再次打开改文件时依然使用的是data block 6 vers0中的数据,所有没有影响;若没有断电正常执行,程序会遍历htree中所有node,把更改的的node写入,这里也就是node6 vers1,node6发生改变他的父节点node2也要改变以指明子节点使用vers 1而不是使用vers 0,node2发生改变他的父节点node0也要改变,同时head中的计数器加一,这时数据完全写入成功,下次打开该文件时,通过计数器判断使用vers 1数据而不是vers 0数据。在计数器没有加一并写入之前发生断电,文件任然使用旧数据,文件数据不会发生更改,这就是ree fs文件系统断电保护大致原理。

主要函数

tee_fs_htree_open  读取文件,初始化htree

tee_fs_htree_write_block  加密数据并写入,同时设置node->node.flags ^= HTREE_NODE_COMMITTED_BLOCK;

                                         node->block_updated = true; node->dirty = true; ht->dirty = true;

tee_fs_htree_read_block 读取并解密数据

tee_fs_htree_sync_to_storage 写入信息有更改的node,其父节点也会跟着修改并写入,计数器ht->head.counter++;写入head

3. tee_ree_fs.c文件中

static const struct tee_fs_dirfile_operations ree_dirf_ops = {
    .open = ree_fs_open_primitive,
    .close = ree_fs_close_primitive,
    .read = ree_fs_read_primitive,
    .write = ree_fs_write_primitive,
    .commit_writes = ree_dirf_commit_writes,
};

这几个接口只是对htree接口的进一步封装而已

4. fs_dirfile.c

struct dirfile_entry {
    TEE_UUID uuid;
    uint8_t oid[TEE_OBJECT_ID_MAX_LEN];
    uint32_t oidlen;
    uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
    uint32_t file_number;
};

/*
 * File layout
 *
 * dirfile_entry.0
 * ...
 * dirfile_entry.n
 *
 * where n the index is disconnected from file_number in struct dirfile_entry
 */
目录文件,通过uuid和obj_id查找对应文件

5. 

static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size,
                  struct tee_file_handle **fh)
{
    TEE_Result res;
    struct tee_fs_dirfile_dirh *dirh = NULL;
    struct tee_fs_dirfile_fileh dfh;

    mutex_lock(&ree_fs_mutex);

    res = get_dirh(&dirh);//打开目录文件
    if (res != TEE_SUCCESS)
        goto out;

    res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,//查找指定文件
                  &dfh);
    if (res != TEE_SUCCESS)
        goto out;

    res = ree_fs_open_primitive(false, dfh.hash, &po->uuid, &dfh, fh);//打卡指定文件
    if (res == TEE_ERROR_ITEM_NOT_FOUND) {
        /*
         * If the object isn't found someone has tampered with it,
         * treat it as corrupt.
         */
        res = TEE_ERROR_CORRUPT_OBJECT;
    } else if (!res && size) {
        struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;

        *size = tee_fs_htree_get_meta(fdp->ht)->length;
    }

out:
    if (res)
        put_dirh(dirh, false);
    mutex_unlock(&ree_fs_mutex);

    return res;
}

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_dirfile_dirh *dirh = NULL;
    struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;

    mutex_lock(&ree_fs_mutex);

    res = get_dirh(&dirh);//打卡目录文件
    if (res)
        goto out;

    res = ree_fs_write_primitive(fh, pos, buf, len);//写入指定文件数据,数据未生效
    if (res)
        goto out;

    res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);//同步node和head信息,写入的数据生效
    if (res)
        goto out;

    res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);//更新目录文件中指定文件的hash值,写入未生效
    if (res)
        goto out;
    res = commit_dirh_writes(dirh);//同步目录文件的node及head信息,写入生效,ps:目录文件通过计数器来选择vers,数据文件                                                       //通过hash来选择,所以此时断电,目录文件还是使用旧的hash,数据文件任然使用旧的数据
out:
    put_dirh(dirh, res);
    mutex_unlock(&ree_fs_mutex);

    return res;
}
 

 类似资料: