You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
staticuint32_tload_ta(size_tnum_params, structtee_ioctl_param*params)
{
intta_found=0;
size_tsize=0;
structparam_value*val_cmd=NULL;
TEEC_UUIDuuid;
TEEC_SharedMemoryshm_ta;
memset(&uuid, 0, sizeof(uuid));
memset(&shm_ta, 0, sizeof(shm_ta));
if (num_params!=2||get_value(num_params, params, 0, &val_cmd) ||get_param(num_params, params, 1, &shm_ta))
returnTEEC_ERROR_BAD_PARAMETERS;
uuid_from_octets(&uuid, (void*)val_cmd);
size=shm_ta.size;
ta_found=TEECI_LoadSecureModule(supplicant_params.ta_dir, &uuid, shm_ta.buffer, &size);
if (ta_found!=TA_BINARY_FOUND) {
EMSG(" TA not found");
returnTEEC_ERROR_ITEM_NOT_FOUND;
}
MEMREF_SIZE(params+1) =size;
/* * If a buffer wasn't provided, just tell which size it should be. * If it was provided but isn't big enough, report an error. */if (shm_ta.buffer&&size>shm_ta.size)
returnTEEC_ERROR_SHORT_BUFFER;
returnTEEC_SUCCESS;
}
07_OPTEE-OS_系统集成之(五)REE侧上层软件
OP-TEE在REE侧的上层软件包括libteec库和tee_supplicant。
libteec库和tee_supplicant属于REE侧用户空间的功能,属于OP-TEE架构中的重要组成部分。
1. OP-TEE软件架构
OP-TEE的软件分为REE侧部分和TEE侧部分,分别包括:
使用OP-TEE来实现特定的安全功能需要开发者根据实际需求开发特定的CA和TA程序并集成到OP-TEE中。CA端负责在REE侧实现该新功能在用户空间的对外接口,TA端的代码则是在OP-TEE OS的用户空间负责实现具体的安全功能,例如使用何种算法组合来对数据进行安全处理、对处理后的数据的安全保存、解密加密数据等功能。在OP-TEE中划分了安全世界和正常世界,两个世界通过session进行通信,通过COMMAND确定执行对象,通过shared memory来进行大量的数据交换。如图所示1:
ARM在硬件上将处理器分为两种模式(trustzone结构)如图所示:
对应的OPTEE在软件栈上需要协同trustzone:
借助OP-TEE来实现特定安全需求时,一次完整的功能调用一般是起源于CA,TA实现具体功能并返回结果数据给CA。整个过程需要经过OP-TEE的客户端接口、OP-TEE在Linux内核端的驱动、 Monitor模式/EL3下安全监控模式调用(smc)的处理、OP-TEE OS的线程处理、OP-TEE中的TA程序运行、OP-TEE端底层库或者硬件资源支持等几个阶段。当TA执行完具体请求之后会按照原路径将数据返回给CA。
不同厂商对具体API的具体实现不一样,但是其功能和对外接口都是遵循GP(Global Platform)的规范来进行封装。例如,海思和Mstar在实现CA端的API的方案不相同,海思在添加TA和CA时,在驱动层和TEE侧都会对调用TEE服务的进程或者线程做权限检查,建立类似白名单机制,在海思的TEE中添加TA和CA时必须注意将调用CA端接口的进程注册到TEE中。
由于当前所有厂商的TEE方案都会遵循GP标准,OP-TEE也遵循GP规范,本书中涉及的API的实现以OP-TEE中的源代码为准。
2. REE侧libteec库
CA使用libteec库中提供的接口来实现对TEE侧TA中具体命令的调用。libteec库是OP-TEE提供给用户在Linux用户空间使用的接口的实现,对于该部分每家芯片厂商可能不一样,但对外的接口都遵循GP规范中CA的接口进行定义。本章将以OP-TEE的实现方法为例进行介绍。
libteec库的所有源代码存放在 optee_client/libteec目录下,OP-TEE提供给Linux端使用的接口源代码的实现存放在
optee_client/libteec/src/tee_client_api.c
文件中。libteec库提供给上层用户使用的API一共有10个,都按照GP标准进行定义,使用这10个API能够满足用户在Linux用户空间的需求,在系统中这部分会被编译成libteec库,保存在REE侧的文件系统中以备上层使用。上述10个函数的功能和实现说明如下:
2.1 APIs
2.1.1 TEEC_InitializeContext
【定义】:
TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context);
【解释】:初始化一个TEEC_Context变量,该变量用于CA和TEE之间建立联系。其中参数name用来定义TEE的身份,如果该参数为NULL,则CA将会选择默认的TEE方案来建立联系。该API必须是CA调用的第一个libteec库的API,且该API不会触发TA的执行。
2.1.2 TEEC_FinalizeContext
【定义】:
void TEEC_FinalizeContext(TEEC_Context *context);
【解释】:释放一个已经被初始化的类型为TEEC_Context的变量,关闭CA与TEE之间的连接。在调用该函数之前必须确保打开的session已经被关闭。
2.1.3 TEEC_OpenSession
【定义】:
【解释】:打开一个CA与对应TA之间的一个session,该session用于CA与对应TA之间的联系,CA需要连接的TA是由UUID指定的。session具有不同的打开和连接方式,根据不同的打开和连接方式CA可以在执行打开session时传递数据给TA,以便TA对打开操作进行权限检查。各种打开方式说明如下:
【传递参数】:
相应地,TEEC_CloseSession和opensession成对出现。
opensession内部使用了ioctl的接口,还有一些内存共享的实现。
https://github.com/OP-TEE/optee_client/blob/master/libteec/src/tee_client_api.c#L594
2.1.4 TEEC_InvokeCommand
【定义】:
【解释】:通过cmd_id和打开的session来通知session对应的TA执行cmd_id指定的操作。
2.1.5 TEEC_RequestCancellation
【原型】:
void TEEC_RequestCancellation(TEEC_Operation *operation);
【解释】:取消某个CA与TA之间的操作,该接口只能由除执行TEEC_OpenSession和TEEC_InvokeCommand的线程之外的其他线程进行调用,而TA端或者TEE OS可以选择并不响应该请求。只有当operation中的 started域被设置成0之后,该操作方可有效。
2.1.6 TEEC_RegisterShareMemory
注册一块在CA端的内存作为CA与TA之间的共享内存。shareMemory结构体中的三个成员如下:
2.1.7 TEEC_RegisterShareMemoryFileDescriptor
注册一个在CA与TA之间的共享文件,在CA端会将文件的描述符fd传递给OP-TEE,其内容被存放到shm中。
2.1.8 TEEC_AllocateSharedMemory
分配一块共享内存,共享内存是由OP-TEE分配的,OP-TEE分配了共享内存之后将会返回该内存块的fd给CA,CA将fd映射到系统内存,然后将地址保存到shm中。
除此之外还有对应的TEEC_ReleaseSharedMemory来释放分配的内存。
2.2 CA调用libteec库接口流程
CA在使用libteec库中的接口来实现调用TA的操作时,一般过程是需要先建立context,然后建立与需要调用的TA之间的session,再通过执行invoke操作向TA发送command ID来实现具体的操作需求,待TA中command ID的内容执行完成之后,如果后续也不需要再次调用TA时,可以通过close session和final context来释放资源,完全关闭该CA与TA之间的联系。一次完整的操作过程如图所示。
3. REE守护进程tee_supplicant
tee_supplicant是常驻在Linux内核中的一个进程,主要作用是使OP-TEE能够通过tee_supplicant来访问REE侧的资源。例如加载存放在文件系统中的TA镜像到TEE中,对REE侧数据库的操作,对EMMC中RPMB分区的操作,提供socket通信等。 其源代码在optee_client/tee-supplicant目录中。编译之后会生成一个名为tee_supplicant的可执行文件, 该可执行文件在REE启动时会作为一个后台守护程序被自动启动。
3.1 tee_supplicant编译生成和自启动
tee_supplicant会在编译optee-client目标时被编译生成一个可执行文件。tee_supplicant可执行文件在Linux启动时会被作为后台程序启动。启动的动 作存放在build/init.d.optee文件中,其内容如下:
在编译时,init.d.optee文件将会被打包到根文件系统中并以optee名字存放在/etc/init.d目录中,而 且会被链接到
/etc/rc.d/S09_optee
文件。这些操作是在编译生成rootfs时进行的,详细情况可查看build/common.mk文件中filelist-tee-common目标的内容。系统启动tee_supplicant的过程如图所示:在最后的设备端的REE上,有这个文件,内部启动supplicant:
3.2 tee_supplicant入口函数
tee_supplicant作为Linux中的一个守护进程,起到处理RPC请求的服务器端的作用,通过类似于C/S的方式,为OP-TEE提供对REE侧资源进行操作 的实现。该可执行文件的入口函数存放在
optee_client/tee-supplicant/src/tee_supplicant.c
文件中。其入口函数内容如下:https://github.com/OP-TEE/optee_client/blob/master/tee-supplicant/src/tee_supplicant.c#L790
3.3 tee_supplicant存放RPC请求的结构体
在tee_supplicant中用于接收和发送请求的数据都存放在类型为tee_rpc_invoke的结构体变量中。该结构体内容如下:
tee_rpc_invoke结构体中的数据展开之后的组成如图所示:
3.4 tee_supplicant的监听程序
tee_supplicant启动后最终会进入一个无限循环,调用process_one_request函数来监控、接收、 处理、回复OP-TEE的请求。如图所示为tee_supplicant处理RPC请求过程:
参考: https://github.com/OP-TEE/optee_client/blob/master/tee-supplicant/src/tee_supplicant.c#L613
tee_supplicant获取TA的RPC请求。tee_supplicant通过read_request接收来自TA端的请求。该函数会阻塞tee驱动层面,其内容如下:
在OP-TEE驱动中ioctl的TEE_IOC_SUPPL_RECV操作将会阻塞,直到接收 到来自TA的请求。
当tee_supplicant解析出RPC请求的功能ID,并根据该ID找到对应的处理函数,完成TEE请求操作后,tee_supplicant通过调用write_response函数将处 理结果和数据返回给TA。该函数的内容和解释如下:
3.5 RPC的请求处理
当解析完来自TA的RPC请求,获取到具体参数后,在process_one_request函数中会根据请求的功能ID来决定具体执行什么操作。这些操作包括:
4. RPC请求
tee_supplicant获取到远程过程调用(Remote Procedure Call,RPC)请求后会解析出功能ID,然后根据该ID值来命中tee_supplicant提供的具体操作。当请求处理完成后会将处理结果和数据发送给OP-TEE驱动,OP-TEE驱动最终会触发安全监控模式调用(smc)将数据传递给OP-TEE。
4.1 加载TA镜像
请求加载TA镜像的功能ID为
RPC_CMD_LOAD_TA
。执行该功能时, tee_supplicant会到文件系统中将TA镜像的内容读取到共享内存中。该操作是通过调用load_ta函数来实现的,该函数定义在tee_supplicant.c文件中,在 REE侧加载TA镜像文件的整体流程如图所示。当load_ta执行完成并正确读取了TA镜像文件的信息之后,最终会将读取到的数据通过调用write_response函数,将数据发送给OP-TEE驱动,由驱动来完成将数据发送给OP-TEE的操作。OP-TEE会对接收到的TA镜像的合法性进行校验,主要是验证TA镜像文件的电子签名是否合法。
4.2 操作REE侧文件系统
当功能ID为RPC_CMD_FS时,tee_supplicant会根据TA请求调用tee_supp_fs_process函数来完成对 文件系统的具体操作,包括常规的文件和目录的打开、关闭、读取、写入、重命名、删除等。其内容如下:
https://github.com/OP-TEE/optee_client/blob/master/tee-supplicant/src/tee_supp_fs.c
tee_supp_fs_process函数主要是对REE侧文件系统进行操作。如果执行的是open、create操作则会返回文件的操作句柄fd值给OP-TEE;如果是write操作则会将需要写的内容写到具体的文件中。
4.3 操作RPMB
当功能ID为RPC_CMD_RPMB时,tee_supplicant会根据TA请求调用process_rpmb函数 来完成对EMMC中rmpb分区的操作。EMMC中的RPMB分区,在读写过程中会执行验签和加解密的操作。其内容如下:
https://github.com/OP-TEE/optee_client/blob/master/tee-supplicant/src/rpmb.c
4.4 分配释放共享内存
当功能ID为RPC_CMD_SHM_ALLOC时,tee_supplicant会根据TA请求调用process_alloc函数来分配TA与tee_supplicant之间的共享内存。其内容如下:
当功能ID为RPC_CMD_SHM_FREE时,tee_supplicant会根据TA请求调用process_free函数来释放TA与tee_supplicant之间的共享内存。
4.5 socket
当功能ID为OPTEE_MSG_RPC_CMD_SOCKET时, tee_supplicant会根据TA请求调用tee_socket_process 函数来完成网络套接字(socket)的相关操作,包括网络套接字的建立、发送、接收和ioctl操作。其内容如下:
https://github.com/OP-TEE/optee_client/blob/master/tee-supplicant/src/tee_socket.c
supplicant给TA提供服务,TA可以通过这些功能远程对REE测一些资源进行操作。
Ref
Footnotes
Demystifying ARM TrustZone TEE Client API using OP-TEE ↩
The text was updated successfully, but these errors were encountered: