最近又開始和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查看。