Trusted Application結構分析

  最近又開始和Trusted Zone打起了交道,須要把Linaro開發的開源安全系統optee os移植到實驗室的老闆子上。不過導師要求我先開發一個應用,在普通環境和安全環境分別有一個程序,稱爲host與trusted application(簡稱TA)。讓我在這個過程當中瞭解一下這個系統。html

  optee os的github地址:https://github.com/OP-TEE/optee_os,一天幾個commit,那幾個大神真是勤勞。git

  無論怎麼說,我要先搞清楚這個應用的結構,幸虧這個項目還帶有一個測試工具集optee test ,這個測試確定包含host和TA兩端,因此能夠從這裏入手學習。github

  host就是一個普通的可執行文件,除了調用了TEE的Api,沒什麼特別的。api

  TA端是OPTEE中運行的程序,有他的要求,下面以一個簡單的測試存儲的TA——storage爲例介紹他的基本結構。安全

  程序文件session

  

  include目錄下的頭文件  app

  

  能夠看到所需的文件並很少。簡要介紹一下,makefile和sub.mk自沒必要說,storage.c寫的是一些簡單的調用TEE存儲API的邏輯。函數

  ta_entry.c比較重要,是TA的入口,裏面主要是工具

  TA_CreateEntryPoint,學習

  TA_DestroyEntryPoint,

  TA_OpenSessionEntryPoint,

  TA_CloseSessionEntryPoint,

  TA_InvokeCommandEntryPoint

  幾個函數,是做用經過名字便可看出,在<tee_ta_api.h>中早有定義,每個TA都要各自實現這幾個函數,不過代碼量很小,通常不須要寫邏輯,聲明出來,處理參數不要報錯就行。其中的TA_InvokeCommandEntryPoint主體是一個switch,用傳入的命令ID判斷和分發。

  Ta_storage.h

#ifndef TA_STORAGE_H
#define TA_STORAGE_H
#define TA_STORAGE_UUID { 0xb689f2a7, 0x8adf, 0x477a, \
    { 0x9f, 0x99, 0x32, 0xe9, 0x0c, 0x0a, 0xd0, 0xa2 } }

#define TA_STORAGE_CMD_OPEN           0
#define TA_STORAGE_CMD_CLOSE          1
#define TA_STORAGE_CMD_READ           2
#define TA_STORAGE_CMD_WRITE          3
#define TA_STORAGE_CMD_CREATE         4
#define TA_STORAGE_CMD_SEEK           5
#define TA_STORAGE_CMD_UNLINK         6
#define TA_STORAGE_CMD_RENAME         7
#define TA_STORAGE_CMD_TRUNC          8
#define TA_STORAGE_CMD_ALLOC_ENUM     9
#define TA_STORAGE_CMD_FREE_ENUM      10
#define TA_STORAGE_CMD_RESET_ENUM     11
#define TA_STORAGE_CMD_START_ENUM     12
#define TA_STORAGE_CMD_NEXT_ENUM      13

#endif /*TA_SKELETON_H */

  上面定義了該TA的UUID, 以及各個命令的宏。OPTEE經過UUID惟一標識系統裏的TA,所以這個UUID不能重複,這裏建議的是經過網站ITU-T UUID generator

http://www.itu.int/ITU-T/asn1/uuid.html)來建立惟一的ID,並且生成的數據長度和OPTEE的要求是一致的,只要按格式拆分就能夠了。

 

  上述命令在TA_InvokeCommandEntryPoint函數中用switch分發命令調用,處理請求的實現寫在storage.c中。

TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext,
                      uint32_t nCommandID, uint32_t nParamTypes,
                      TEE_Param pParams[4])
{
    (void)pSessionContext;

    switch (nCommandID) {
    case TA_STORAGE_CMD_OPEN:
        return ta_storage_cmd_open(nParamTypes, pParams);

    case TA_STORAGE_CMD_CLOSE:
        return ta_storage_cmd_close(nParamTypes, pParams)

        //......
}        

  

  user_ta_header_defines.h,TA的頭部信息,主要是UUID和一些空間信息。 

#ifndef USER_TA_HEADER_DEFINES_H
#define USER_TA_HEADER_DEFINES_H

#include <ta_storage.h>

#define TA_UUID TA_STORAGE_UUID

/*
 * This is important to have TA_FLAG_SINGLE_INSTANCE && !TA_FLAG_MULTI_SESSION
 * as it is used by the ytest
 */
#define TA_FLAGS        (TA_FLAG_USER_MODE | TA_FLAG_EXEC_DDR | \
                TA_FLAG_SINGLE_INSTANCE)
#define TA_STACK_SIZE        (2 * 1024)
#define TA_DATA_SIZE        (32 * 1024)  

  

  在optee_os/../kernel tee_ta_Manager.c裏面,tee_ta_init_static_ta_session函數中定義TA頭部結構體類型,在OPTEE收到Host端的請求,準備初始化會話,加載對應的TA時,會建立一個TA指針,在循環中從內存中定義的start到stop移動,依次比對UUID,從而獲取所需的TA頭部指針,而後調用tee_ta_load函數,檢查簽名,加載待運行的TA。

static TEE_Result tee_ta_init_static_ta_session(const TEE_UUID *uuid,
                struct tee_ta_session *s)
{
    struct tee_ta_ctx *ctx = NULL;
    ta_static_head_t *ta = NULL;

    DMSG("   Lookup for Static TA %08x-%04x-%04x",
         uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion);

    ta = &__start_ta_head_section;
    while (true) {
        if (ta >= &__stop_ta_head_section)
            return TEE_ERROR_ITEM_NOT_FOUND;
        if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0)
            break;
        ta++;
    }
        //......
}

 

  因此新增的TA應該預先把本身的頭部結構體放在區間內,通過分析,只要在編譯完成後,把.ta文件預先放在rootfs下的lib/optee_armtz/目錄內便可,運行時,系統將把這個目錄下的TA的頭部都加載到內存中以供查找。至於如何打包,最好的方式仍是經過修改makefile中Root FS部份內容,這樣每次編譯完都會把.ta打包入鏡像。
  以上就是一個簡單的TA項目基本的結構介紹和分析,更詳細的代碼請自行到github查看。

  optee_os

  optee test

相關文章
相關標籤/搜索