OP-TEE5-RPMB FS2

RPMB FS流程

具体见注释。

rpmb_fs_open

@optee_os/core/tee/tee_rpmb_fs.c
主要

  • 构建struct rpmb_file_handle数据结构指针——文件指针
  • 加/解锁
  • call rpmb_fs_open_internal——open的主要逻辑
static TEE_Result rpmb_fs_open(struct tee_pobj *po, size_t *size,
                   struct tee_file_handle **ret_fh)
{
    TEE_Result res;
    //申请一个文件句柄,相当于fopen的FILE指针,po是上层的句柄,在这一层我们要用的是fh
    struct rpmb_file_handle *fh = alloc_file_handle(po, po->temporary);

    if (!fh)
        return TEE_ERROR_OUT_OF_MEMORY;

    mutex_lock(&rpmb_mutex);//日常加锁
    //真·open
    res = rpmb_fs_open_internal(fh, &po->uuid, false);
    if (!res && size)
        *size = fh->fat_entry.data_size;

    mutex_unlock(&rpmb_mutex);//日常解锁

    if (res)
        free(fh);
    else
        *ret_fh = (struct tee_file_handle *)fh;

    return res;
}

rpmb_fs_open_internal

@optee_os/core/tee/tee_rpmb_fs.c
主要

  • call rpmb_fs_setup——初始化
  • 如果创建文件
    准备在RPMB申请新数据空间
  • 构造新的或读取已有的fat表项[1]
  • 如果创建文件
    生成EFEK[2]
    写入新fat表项
static TEE_Result rpmb_fs_open_internal(struct rpmb_file_handle *fh,
                    const TEE_UUID *uuid, bool create)
{
    tee_mm_pool_t p;
    bool pool_result;
    TEE_Result res = TEE_ERROR_GENERIC;

    /* We need to do setup in order to make sure fs_par is filled in */
    res = rpmb_fs_setup(); //为使用FS的使用做准备,属于初始化动作
    if (res != TEE_SUCCESS)
        goto out;

    fh->uuid = uuid;
    if (create) { //如果创建文件
        /* Upper memory allocation must be used for RPMB_FS. */
        //准备在RPMB中申请一块空间用来存储新文件
        pool_result = tee_mm_init(&p,
                      RPMB_STORAGE_START_ADDRESS,
                      fs_par->max_rpmb_address,
                      RPMB_BLOCK_SIZE_SHIFT,
                      TEE_MM_POOL_HI_ALLOC);

        if (!pool_result) {
            res = TEE_ERROR_OUT_OF_MEMORY;
            goto out;
        }
        //读取fat表,为新的文件构造表项,fat表是用来管理RPMB FS的元数据
        res = read_fat(fh, &p);
        tee_mm_final(&p);
        if (res != TEE_SUCCESS)
            goto out;
    } else { //如果不是创建文件
        //读取fat表,为新的文件构造表项,fat表是用来管理RPMB FS的元数据
        res = read_fat(fh, NULL);
        if (res != TEE_SUCCESS)
            goto out;
    }

    /*
     * If this is opened with create and the entry found was not active
     * then this is a new file and the FAT entry must be written
     */
    if (create) { //如果创建文件
        if ((fh->fat_entry.flags & FILE_IS_ACTIVE) == 0) { //如果分到的fat表项是没有被使用的
            memset(&fh->fat_entry, 0,
                sizeof(struct rpmb_fat_entry));
            memcpy(fh->fat_entry.filename, fh->filename,
                strlen(fh->filename));
            /* Start address and size are 0 */
            fh->fat_entry.flags = FILE_IS_ACTIVE; //设置fat表项为被使用的

            res = generate_fek(&fh->fat_entry, uuid); //生成EFEK,用来给文件数据加密的
            if (res != TEE_SUCCESS)
                goto out;
            DMSG("GENERATE FEK key: %p",
                 (void *)fh->fat_entry.fek);
            DHEXDUMP(fh->fat_entry.fek, sizeof(fh->fat_entry.fek));

            res = write_fat_entry(fh, true); //把新建的表项写入RPMB
            if (res != TEE_SUCCESS)
                goto out;
        }
    }

    res = TEE_SUCCESS;

out:
    return res;
}

rpmb_fs_setup

@optee_os/core/tee/tee_rpmb_fs.c
主要:

  • fs_par已经赋值,说明这个结构体填充完了,立刻成功返回,不再初始化
  • 获取RPMB分区块数,块大小是1<<RPMB_BLOCK_SIZE_SHIFT——256
  • 读取struct rpmb_fs_partition,确定是否需要重置分区
  • (可能会)重置分区
  • fs_par指针申请结构体空间,并给成员赋值
static TEE_Result rpmb_fs_setup(void)
{
    TEE_Result res = TEE_ERROR_GENERIC;
    struct rpmb_fs_partition *partition_data = NULL;
    struct rpmb_file_handle *fh = NULL;
    uint32_t max_rpmb_block = 0;

    if (fs_par) {
        res = TEE_SUCCESS;
        goto out;
    }
    //获取最大块数,后面用来填充fs_par
    res = tee_rpmb_get_max_block(CFG_RPMB_FS_DEV_ID, &max_rpmb_block);
    if (res != TEE_SUCCESS)
        goto out;

    partition_data = calloc(1, sizeof(struct rpmb_fs_partition));
    if (!partition_data) {
        res = TEE_ERROR_OUT_OF_MEMORY;
        goto out;
    }
    //读取RPMB中最开始的那段数据,解析为struct rpmb_fs_partition
    res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS,
                (uint8_t *)partition_data,
                sizeof(struct rpmb_fs_partition), NULL, NULL);
    if (res != TEE_SUCCESS)
        goto out;

#ifndef CFG_RPMB_RESET_FAT
    if (partition_data->rpmb_fs_magic == RPMB_FS_MAGIC) { //核对魔数
        if (partition_data->fs_version == FS_VERSION) { //核对版本
            res = TEE_SUCCESS;
            goto store_fs_par; // 正常情况会走这里
        } else { //版本不对就不能访问
            /* Wrong software is in use. */
            res = TEE_ERROR_ACCESS_DENIED;
            goto out;
        }
    }
#else
    EMSG("**** Clearing Storage ****"); //正常不会走这里,这里会重置RPMB分区
#endif

    //下面开始重置RPMB分区
    /* Setup new partition data. */
    partition_data->rpmb_fs_magic = RPMB_FS_MAGIC;
    partition_data->fs_version = FS_VERSION;
    partition_data->fat_start_address = RPMB_FS_FAT_START_ADDRESS; //512

    /* Initial FAT entry with FILE_IS_LAST_ENTRY flag set. */
    fh = alloc_file_handle(NULL, false); //准备写入一个fat表项
    if (!fh) {
        res = TEE_ERROR_OUT_OF_MEMORY;
        goto out;
    }
    fh->fat_entry.flags = FILE_IS_LAST_ENTRY; //这个表项标记为最后一项
    fh->rpmb_fat_address = partition_data->fat_start_address;

    /* Write init FAT entry and partition data to RPMB. */
    res = write_fat_entry(fh, true); //写入这个唯一的表项,这个表项对应的范围是从512开始所有空间
    if (res != TEE_SUCCESS)
        goto out;
    //记下目前的write counter,在TEE OS里面好像没什么用
    res =
        tee_rpmb_get_write_counter(CFG_RPMB_FS_DEV_ID,
                       &partition_data->write_counter);
    if (res != TEE_SUCCESS)
        goto out;
    //将新的struct rpmb_fs_partition写进去
    res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS,
                 (uint8_t *)partition_data,
                 sizeof(struct rpmb_fs_partition), NULL, NULL);

#ifndef CFG_RPMB_RESET_FAT
store_fs_par: //正常情况会从上面直接跳到这里
#endif
    //开始填充fs_par
    /* Store FAT start address. */
    fs_par = calloc(1, sizeof(struct rpmb_fs_parameters));
    if (!fs_par) {
        res = TEE_ERROR_OUT_OF_MEMORY;
        goto out;
    }
    //就填充这两个东西:fat表起始位置+RPMB分区最后一块的地址
    fs_par->fat_start_address = partition_data->fat_start_address;
    fs_par->max_rpmb_address = max_rpmb_block << RPMB_BLOCK_SIZE_SHIFT;

    dump_fat();

out:
    free(fh);
    free(partition_data);
    return res;
}

  1. fat表是RPMB分区的元数据,和FAT32文件系统的类似,但是更简单。

  2. EFEK是用来给文件加密的密钥,在存储到REE FS或RPMB FS之前,文件都需要先被加密。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容