22. OP-TEE中TA与CA执行流程-------tee-supplicant(一)

   

  

tee_supplicant的主要作用是使OP-TEE能够通过tee_supplicant来访问REE端文件系统中的资源,例如加载存放在文件系统中的TA镜像到TEE中,对REE端数据库的操作,对EMMC中RPMB分区的操作,提供socket通信等。 其源代码optee_client/tee-supplicant目录中。编译之后会生成一个名字为tee_supplicant的可执行文件,该可执行文件在REE启动的时候会作为一个后台程序被自动启动,而且常驻于系统中。

1. tee_supplicant编译生成和Linux中的自启动

  tee_supplicant会在编译optee-client目标的时候被编译生成一个可执行文件,具体编译过程请查看optee-client目录中的Makefile文件结合《3.OP-TEE+qemu的编译--工程编译target依赖关系》文章就能明了该可执行文件是如何一步步被编译出来的。

  tee_supplicant可执行文件在Linux启动的时候会被作为后台程序启动。启动的动作存放在build/init.d.optee文件中,其内容如下:

#!/bin/sh
#
# /etc/init.d/optee
#
# Start/stop tee-supplicant (OP-TEE normal world daemon)
#
case "$1" in
    start)
	if [ -e /bin/tee-supplicant -a -e /dev/teepriv0 ]; then
		echo "Starting tee-supplicant..."
		tee-supplicant&	#将tee_supplicat以后台方式启动
		exit 0
	else
		echo "tee-supplicant or TEE device not found"
		exit 1
	fi

        ;;
    stop)
	killall tee-supplicant
	;;
    status)
	cat /dev/teepriv0 2>&1 | grep -q "Device or resource busy" || not="not "
	echo "tee-supplicant is ${not}active"
	;;
esac

  在编译的时候init.d.optee文件将会被打包到根文件系统中并以"optee“名字存放在/etc/init.d目录中。而且会被链接到/etc/rc.d/S09_optee文件。这些操作是在编译生成rootfs的时候所做的,详细情况请查看build/common.mk文件中filelist-tee-common目标的内容。系统启动tee_supplicant的过程如下图所示:

2. tee_supplicant入口函数

  tee_supplicant启动后作为Linux中的一个后台程序运行,起到处理RPC请求 service的作用。通过类似于C/S的方式为OP-TEE提供对REE端文件系统的操作。该可执行文件的源代码的入口函数存放在optee_client/tee-supplicant/src/tee_supplicant.c文件中。其入口函数内容如下:

int main(int argc, char *argv[])
{
	struct thread_arg arg = { .fd = -1 };
	int e;

/* 初始化互斥体 */
	e = pthread_mutex_init(&arg.mutex, NULL);
	if (e) {
		EMSG("pthread_mutex_init: %s", strerror(e));
		EMSG("terminating...");
		exit(EXIT_FAILURE);
	}

/* 判定是否带有启动参数,如果带有启动参数,则打开对应的驱动文件
    如果没有带参数,则打开默认的驱动文件 */
	if (argc > 2)
		return usage();
	if (argc == 2) {
		arg.fd = open_dev(argv[1]);
		if (arg.fd < 0) {
			EMSG("failed to open \"%s\"", argv[1]);
			exit(EXIT_FAILURE);
		}
	} else {
/*打开/dev/teepriv0设备,该设备为tee驱动设备文件,返回操作句柄*/
		arg.fd = get_dev_fd();
		if (arg.fd < 0) {
			EMSG("failed to find an OP-TEE supplicant device");
			exit(EXIT_FAILURE);
		}
	}

	if (tee_supp_fs_init() != 0) {
		EMSG("error tee_supp_fs_init");
		exit(EXIT_FAILURE);
	}

	if (sql_fs_init() != 0) {
		EMSG("sql_fs_init() failed ");
		exit(EXIT_FAILURE);
	}

/* 调用process_one_request函数接收来自TEE的请求,并加以处理 */
	while (!arg.abort) {
		if (!process_one_request(&arg))
			arg.abort = true;
	}

	close(arg.fd);
	return EXIT_FAILURE;
}

3. tee_supplicant中的loop循环

  tee_supplicant启动之后最终会进入一个loop循环,调用process_one_request函数来监控,接收,处理,回复OP-TEE的请求。整个处理过程如下图所示:



process_one_request函数的内容如下:

static bool process_one_request(struct thread_arg *arg)
{
	union tee_rpc_invoke request;
	size_t num_params;
	size_t num_meta;
	struct tee_ioctl_param *params;
	uint32_t func;
	uint32_t ret;

	DMSG("looping");
	memset(&request, 0, sizeof(request));
	request.recv.num_params = RPC_NUM_PARAMS;

	/* Let it be known that we can deal with meta parameters */
/* 组合tee_supplican等待TA请求的参数 */
	params = (struct tee_ioctl_param *)(&request.send + 1);
	params->attr = TEE_IOCTL_PARAM_ATTR_META;

/* 增加当前正在等待处理的tee_supplicant的数量 */
	num_waiters_inc(arg);

/* 通过ioctl函数,将等待请求发送到tee驱动,在tee驱动中将会block住,
    直到有来自TA的请求才会返回 */
	if (!read_request(arg->fd, &request))
		return false;

/* 解析从TA发送的请求,分离出TA需要tee_supplicant所做的事情ID和相关参数 */
	if (!find_params(&request, &func, &num_params, ¶ms, &num_meta))
		return false;

/* 创建新的线程来等待接收来自TA的请求,将等待请求的数量减一 */
	if (num_meta && !num_waiters_dec(arg) && !spawn_thread(arg))
		return false;

/* 根据TA请求的ID来执行具体的handle */
	switch (func) {
	case RPC_CMD_LOAD_TA:
		ret = load_ta(num_params, params);	//加载在文件系统的TA镜像
		break;
	case RPC_CMD_FS:
		ret = tee_supp_fs_process(num_params, params);	//处理操作文件系统的请求
		break;
	case RPC_CMD_SQL_FS:
		ret = sql_fs_process(num_params, params);	//处理操作数据库文件的请求
		break;
	case RPC_CMD_RPMB:
		ret = process_rpmb(num_params, params);	//处理对EMMC中rpmb分区的操作请求
		break;
	case RPC_CMD_SHM_ALLOC:
		ret = process_alloc(arg->fd, num_params, params);	//处理分配共享内存的请求
		break;
	case RPC_CMD_SHM_FREE:
		ret = process_free(num_params, params);	//释放分配的共享内存的请求
		break;
	case RPC_CMD_GPROF:
		ret = gprof_process(num_params, params);	//处理gprof请求
		break;
	case OPTEE_MSG_RPC_CMD_SOCKET:
		ret = tee_socket_process(num_params, params);	//处理网络socket请求
		break;
	default:
		EMSG("Cmd [0x%" PRIx32 "] not supported", func);
		/* Not supported. */
		ret = TEEC_ERROR_NOT_SUPPORTED;
		break;
	}

	request.send.ret = ret;
/* 回复处理后的数据给TA */
	return write_response(arg->fd, &request);
}

4. 接收来自TA的请求

  tee_supplicant通过read_request来接收来自TA端的请求。该函数会block在tee驱动层面。内容如下:

static bool read_request(int fd, union tee_rpc_invoke *request)
{
	struct tee_ioctl_buf_data data;

	data.buf_ptr = (uintptr_t)request;
	data.buf_len = sizeof(*request);

/* 将在tee_supplicant中设定的用于存放TA请求的buffer和属性的地址作为参数,
    然后调用ioctl函数进入到tee驱动中等待来自TA的请求 */
	if (ioctl(fd, TEE_IOC_SUPPL_RECV, &data)) {
		EMSG("TEE_IOC_SUPPL_RECV: %s", strerror(errno));
		return false;
	}
	return true;
}

  在OP-TEE驱动中ioctl的TEE_IOC_SUPPL_RECV操作将会block住,直到接收到来自TA的请求。关于驱动部分将在后续章节详细介绍。

5. 解析来自TA的请求

  在tee_supplicant中,使用find_params函数来解析来自TA的请求。函数内容如下:

static bool find_params(union tee_rpc_invoke *request, uint32_t *func,
			size_t *num_params, struct tee_ioctl_param **params,
			size_t *num_meta)
{
	struct tee_ioctl_param *p;
	size_t n;

	p = (struct tee_ioctl_param *)(&request->recv + 1);

	/* Skip meta parameters in the front */
/* 跳过属性为TEE_IOCTL_PARAM_ATTR_META的参数 */
	for (n = 0; n < request->recv.num_params; n++)
		if (!(p[n].attr & TEE_IOCTL_PARAM_ATTR_META))
			break;

	*func = request->recv.func; //记录TA请求的操作编号
	*num_params = request->recv.num_params - n;	//确定TA真正的参数个数
	*params = p + n;	//将params指向TA发送过来的参数
	*num_meta = n;	//定位meta的起始位置

	/* Make sure that no meta parameters follows a non-meta parameter */
/* 确保剩下的参数中没有属性为TEE_IOCTL_PARAM_ATTR_META的参数 */
	for (; n < request->recv.num_params; n++) {
		if (p[n].attr & TEE_IOCTL_PARAM_ATTR_META) {
			EMSG("Unexpected meta parameter");
			return false;
		}
	}

	return true;
}

6. 请求的处理

  当解析玩来自TA的请求参数信息之后,在process_one_request函数中会使用switch方式,根据请求的func ID来决定具体执行什么操作,这些操作包括:1. 从文件系统中读取TA的镜像保存在共享内存中。2. 对文件系统中的节点进行读/写/打开/关闭/移除等操作。3.执行针对数据库的操作。4. 执行RPMB相关操作。5. 分配共享内存。6. 释放共享内存。7处理gprof请求。8. 执行网络socket请求。

7. 回复数据给TA

  tee_supplicant执行完具体的操作请求之后,会通过write_response函数将执行结果和数据反馈给TA。该函数内容如下:

static bool write_response(int fd, union tee_rpc_invoke *request)
{
	struct tee_ioctl_buf_data data;

/* 将需要返回给TA的数据存放在buffer中 */
	data.buf_ptr = (uintptr_t)&request->send;
	data.buf_len = sizeof(struct tee_iocl_supp_send_arg) +
		       sizeof(struct tee_ioctl_param) *
				request->send.num_params;

/* 调用驱动中ioctl函数的TEE_IOC_SUPPL_SEND功能,进数据发送给TA */
	if (ioctl(fd, TEE_IOC_SUPPL_SEND, &data)) {
		EMSG("TEE_IOC_SUPPL_SEND: %s", strerror(errno));
		return false;
	}
	return true;
}

8. tee_supplicant中使用的结构体

  在tee_supplicant中用于接收和发送请求的的数据都存放在类型为tee_rpc_invoke的结构体变量中,该结构体内容如下:

union tee_rpc_invoke {
	uint64_t buf[(RPC_BUF_SIZE - 1) / sizeof(uint64_t) + 1];
	struct tee_iocl_supp_recv_arg recv;
	struct tee_iocl_supp_send_arg send;
};

RPC_BUF_SIZE的定义如下:

#define RPC_BUF_SIZE	(sizeof(struct tee_iocl_supp_send_arg) + \
			 RPC_NUM_PARAMS * sizeof(struct tee_ioctl_param))

整个结构体中成员的排列如下图所示:


  在整个结构体中等待来自TA的请求的时候,第一部分为tee_ioctl_supp_send_arg结构体,当处理完请求之后,需要将处理后的数据发送给TA时,第一部分为tee_ioctl_supp_send_arg







 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
# 课程背景2021年ARM又推出了ARMv9架构,系统软件架构也在悄无声息地发生变化。在这种架构,强调的是隔离技术,包括资源的隔离、运行时隔离,特权操作系统的权限也变得越来越小…不管您是什么领域,ARM服务器、汽车电子、手机或者是其它设备终端,安全都是其的一个重要环节。我们常说的安全一般是只网络安全/业务安全/App安全,这些安全依赖的正是操作系统安全,操作系统安全所依赖的就是安全架构技术,在该安全架构,首当要学习的就是Trustzone/TEE技术。只有设备安全/操作系统安全/APP安全/网络安全/服务器安全整个一条链都安全了,那么你的业务才算得上的安全.不管您是做什么的,您做不做安全或虚拟化,掌握整个系统软件架构也是一件必要的事情。您只有掌握了安全架构,你才具有全局的视野,才能进行全局的软件设计,才称得上架构师。安全不仅仅是架构安全,安全还是一种生态,安全还产生一类标准。安全出现在产品声明周期的任何一个角落,它可能零碎地出现在硬件、零碎地出现在软件代码。如果你不了解安全,你可能无法进行优秀的产品设计,你甚至无法去正确的阅读代码。# 课程介绍(1) 讲解ARM最新硬件架构(ARM Core、ARM Architecture)、SOC架构(2) 讲解最新的Trustzone安全架构、TEE架构、Secureboot等(3) 讲解软件组件:TF-A(ATF)、optee_os、Linux Kernel、CA/TA应用程序等,及其交互模型、设计模型(4) 多系统交互代码导读、安全论证实践、CA/TA示例实践、安全业务设计实践(5) 我们学习的是全部硬件、全部系统,软硬结合,或者是大系统的软硬件融合# 课程收益1、安全不再神秘,能cover住全局2、熟悉ARM Architecture架构知识3、熟悉SOC架构知识4、熟悉主流的系统软件框架5、知道多系统之间是如何交互的,也能够进行系统级的设计6、深入了解当前的系统安全架构以及未来安全架构趋势7、熟悉基础的安全业务设计方法8、熟悉系统的启动流程、Secureboot等9、知道Linux Kernel在大系统的位置,以及与其它系统交互的方法10、熟悉各类标准和规范11、学习资料的获取方法 # 课程大纲《Trustzone/TEE/系统安全开发速成班》 --当前48节课/19小时说明: 本视频会持续更新,购买时请以课程目录为主。本EXCEL一个月更新一次。章节编号课程时常第一章基础和简介1课程介绍 8:332ARM和SOC的架构简介60:13第二章软硬件基础3armv8/armv9基础概念26:204ARMv8/ARMv9的Trustzone技术77:565ARMv7的Trustzone技术8:376安全架构及其未来趋势(FF-A/SPM/CCA)6:417ARMv9 CCA机密计算框架底层核心原理简介20:448ARMv9 RME安全扩展详解61:299ATF Quick Start0161:2710Optee Quick Start49:3411系统软件Quick Start21:0412Secureboot原理深度讲解60:2813Android AVB的介绍26:0914TZC400详解17:5615TZC400代码导读之ATF13:4416RPMB详解30:0617RPMB代码导读之optee14:0318efuse详解12:1919Anti-Rollback的介绍11:33第三章软件架构20TEE的组件介绍67:5921TEE的RPC反向调用31:1422TEE的调度模型21:3223各类标准和规范22:17第四章软件架构(高级)24多系统之间的管理模型(ABI/标准)10:3025多系统之间的调度12:2126多系统之间的断(不含虚拟化)61:4727多系统之间的断(虚拟化)6:5728再谈多系统之间的调度(多核多线程)10:3129其它(内存管理/PSCI...)10:12第五章安全应用开发基础30安全应用开发基础5:3731TEE环境:qemu_V8环境的使用4:2032TEE环境:编写一个CATA程序11:0433TEE环境:编写漂亮的文档4:1434TEE环境:搭建阅读代码神器opengrok3:2635TEE环境(必看):使用集成好的qemu_v8镜像程序20:2936[CA/TA开发]CATA的通信9:1837[CA/TA开发]CATA的传参27:1638[CA/TA开发]TEE的存储系统20:5739[CA/TA开发]TEE的密码学系统简介12:3740[CA/TA开发]TEE的密码学系统简介-数字摘要Hash等33:2141[CA/TA开发]TEE的密码学系统简介-对称密码学算法AES等12:2042[CA/TA开发]TEE的密码学系统简介-消息摘要算法HMAC等15:4843[CA/TA开发]TEE的密码学系统简介-非对称密码学算法RSA等7:33第六章安全业务设计高级44Gatekeeper的介绍29:3245keymaster/keymint/keystore/keystore213:2746生物认证(指纹/人脸)13:5747DRM的介绍21:3748TUI的介绍17:03总计时统计(分钟)1128:12 说明:本课程会持续更新…
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值