前言
在开发过程中用到了teei_daemon,一开始没有关注它的具体实现用来干什么,结果出了问题,花了不少时间才解决了,下面就来简要分析下teei_daemon的工作流程
teei_daemon简介
主要是引导豆荚相关的tee os,关于tee?简单说一下:TEE(Trust Execution Environment),也叫可信执行环境。相对于还有REE(Rich Execution Environment),都属于arm的一种操作模式。TEE和REE分别又对应了Secure World和Normal World。像我们相关的Linux都是应用在Normal World,而涉及到指纹支付,签名校验都是在Secure World。对于Android的keystore都是与TEE密切相关的 那TEE环境下也需要有自己的操作系统Trustonic、高通的QSEE、国内的豆荚,还有开源的OPTEE等,目前Google自己也有一套相关的TEE相关的操作系统。 好了,说了那么多,teei_daemon到底是拿来干嘛的?简单来说用于引导加载tee相关的OS环境,这里是用来引导豆荚相关的OS。
teei_daemon代码分析
teei_daemon在相关init.rc中启动
service tee_microtrust /sbin/teei_daemon
disabled
oneshot
seclabel u:r:recovery:s0
teei_daemon相关源码路径在 hardware/samsung_slsi/< platform >/teei_daemon/
,很简单的只有几个文件,我们从main.c开始看
- 首先函数一开始打印相关版本信息,并设置了相关属性值。同时申请了BUFFER_SIZE的内存空间,后面会用到
IMSG_ERROR("TEEI Daemon VERSION [%s]", UTOS_VERSION);
IMSG_INFO("TEEI Daemon VERSION [%s]", UTOS_VERSION);
IMSG_INFO("TEEI Daemon start ...");
property_set("soter.teei.init", "INIT_START");
rw_buffer = (unsigned char*)malloc(BUFFER_SIZE);
if (rw_buffer == NULL) {
IMSG_ERROR("%s : %d Can not malloc enough memory.\n", __func__, __LINE__);
return -1;
}
- 打开
/dev/tz_vfs
这个设备节点,否则一直等待直到成功打开.内核中该节点注册在drivers/teei/V1.0/tz_driver/目录下
while (1) {
vfs_fd = open(DEV_FILE, O_RDWR);
if (vfs_fd < 0) {
IMSG_ERROR("%s : %d Can not open the device node.\n", __func__, __LINE__);
continue;
}
break;
}
- 创建了两个线程,下面来看一下这两个线程分别做了什么事
pthread_create(&ntid, NULL, (void*)init_OS_fn, NULL);
/* pthread_create(&first_time_boot_id, NULL, (void*)keymaster_first_time_fn, NULL); */
/* create a thread for start data area working */
pthread_create(&loadtee_id, NULL, (void*)loadtee_fn, NULL);
先来看一下init_OS_fn这个函数做了什么?它主要调用了init_TEEI_OS,并设置了相关的属性值.init_TEEI_OS中主要对/dev/teei_config做了相关的操作,底层主要是初始化了一些锁,申请相关的内存空间,用于后面加载teei os
static int init_OS_fn(void) {
int ret = 0;
IMSG_INFO("begin to init TEEI OS");
ret = init_TEEI_OS();
if (!ret) {
property_set("soter.teei.init", "INIT_OK");
}
return 0;
}
static int init_TEEI_OS() {
int fd = open("/dev/teei_config", O_RDWR);
int flag = 0;
int ret = ioctl(fd, TEEI_CONFIG_IOCTL_INIT_TEEI, &flag);
if (0 != ret) {
IMSG_ERROR("Can not init Soter OS ,please fix it ret = %d !", ret);
} else {
IMSG_INFO("begin to init TEEI OS OK flag = %d", flag);
}
close(fd);
return ret;
}
再来看看loadtee_fn这个函数:1、loadtee_fn首先获取了ro.crypto.state和ro.crypto.type这两个属性值,关于这两个属性的配置是在init进程中,执行do_mount_all时,通过读取fstab文件进行设置的。所以在teei_daemon执行时,需要对其进行解密;2、将table数组中定义的一些文件拷贝至指定的位置,跳转到table这个二维数组里,都是alipayapp等相关的TA(可信应用)拷贝到/data/thh/目录下
static int loadtee_fn(void) {
IMSG_INFO("running in loadtee_fn.");
char value[PROPERTY_VALUE_MAX];
char value_type[PROPERTY_VALUE_MAX];
char value_state[PROPERTY_VALUE_MAX];
property_get("ro.crypto.state", value, "");
property_get("ro.crypto.type", value_type, "");
if (strcmp("unencrypted", value) != 0 && strcmp("unsupported", value) != 0) {
/*data encrypted, wait for decrption.*/
if(strcmp("file", value_type) != 0) {
property_get("vold.decrypt", value, "");
while (strcmp("trigger_restart_framework", value) != 0) {
/*still decrypting... wait one second.*/
usleep(10000);
property_get("vold.decrypt", value, "");
}
}
}
property_get("soter.teei.state", value_state, "");
while(strcmp("OK", value_state) != 0) {
/*still decrypting... wait one second.*/
usleep(10000);
property_get("soter.teei.state", value_state, "");
}
IMSG_INFO("create tee storage ...");
/*create_tee_storage(table[0],0);*/
create_tee_storage(table[1]);
create_tee_storage(table[2]);
create_tee_storage(table[3]);
create_tee_storage(table[4]);
create_tee_storage(table[5]);
create_tee_storage(table[6]);
create_tee_storage(table[7]);
create_tee_storage(table[8]);
create_tee_storage(table[9]);
create_tee_storage(table[10]);
create_tee_storage(table[11]);
create_tee_storage(table[12]);
create_tee_storage(table[13]);
create_tee_storage(table[14]);
create_tee_storage(table[15]);
keymaster_unlock();
return 0;
再来看一下keymaster_unlock这个函数,函数也很简单,打开/dev/teei_config这个设备节点,之后使用ioctl函数写入命令
static void keymaster_unlock(void) {
int fd = open("/dev/teei_config", O_RDWR);
int flag = 0;
int ret = ioctl(fd, TEEI_CONFIG_IOCTL_UNLOCK, &flag);
if (0 != ret) {
IMSG_ERROR("keymaster unlock boot_decrypt_lock failed !");
} else {
IMSG_INFO("unlock boot_decrypt_lock success");
}
close(fd);
}
底层驱动里面对于ioctl这个cmd做了什么呢?很简单,只是调用了up释放了boot_decryto_lock这个互斥量。而在上面说的的init_TEEI_OS函数中对初始化的init_teei_framework
,通过ioctl加载了相关的TA之后,通过TEEI_CONFIG_IOCTL_UNLOCK这个cmd,之后便可加载相关的teei os,当然啦,这部分基本都是不开源的,之后,相关的TEE OS就起来了。
static long teei_config_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
int retVal = 0;
switch (cmd) {
case TEEI_CONFIG_IOCTL_INIT_TEEI:
if (teei_flags == 1)
break;
retVal = init_teei_framework();
TEEI_BOOT_FOOTPRINT((char *)teei_boot_error_to_string(retVal));
teei_flags = 1;
break;
case TEEI_CONFIG_IOCTL_UNLOCK:
up(&(boot_decryto_lock));
break;
default:
IMSG_ERROR("[%s][%d] command not found!\n", __func__, __LINE__);
retVal = -EINVAL;
}
return retVal;
}
down(&boot_decryto_lock);
up(&boot_decryto_lock);
TEEI_BOOT_FOOTPRINT("TEEI BOOT Decrypt Unlocked");
retVal = teei_service_init_second();
TEEI_BOOT_FOOTPRINT("TEEI BOOT Service2 Inited");
if (retVal == -1)
return TEEI_BOOT_ERROR_INIT_SERVICE2_FAILED;
t_os_load_image();
TEEI_BOOT_FOOTPRINT("TEEI BOOT Load TEES Completed");
if (soter_error_flag == 1)
return TEEI_BOOT_ERROR_LOAD_TA_FAILED;
teei_config_flag = 1;
complete(&global_down_lock);
wake_up(&__fp_open_wq);
TEEI_BOOT_FOOTPRINT("TEEI BOOT All Completed");
之后调用set_task_capability函数,给普通用户设置相应的capabilities。让teei_daemon在不是root权限下也能正常的运行。
static int set_task_capability(void)
{
int stat;
int ret;
cap_value_t capList[6] = { CAP_DAC_OVERRIDE, CAP_SYS_RAWIO, CAP_SETUID, CAP_SETGID, CAP_SETPCAP, CAP_SYS_ADMIN } ;
unsigned num_caps = 6;
get_allkinds_uid();
stat = setuid(geteuid());
pid_t parentPid = getpid();
if (!parentPid) {
IMSG_ERROR("Can not get task pid!\n");
return 1;
}
cap_t caps = cap_init();
cap_set_flag(caps, CAP_EFFECTIVE, num_caps, capList, CAP_SET);
cap_set_flag(caps, CAP_INHERITABLE, num_caps, capList, CAP_SET);
cap_set_flag(caps, CAP_PERMITTED, num_caps, capList, CAP_SET);
ret = cap_set_proc(caps);
if (ret) {
IMSG_ERROR("capset() failed! error code %d\n", ret);
return EXIT_FAILURE;
}
listCaps();
/* cap_free(caps); */
return 0;
}
最后从/dev/tz_vfs节点读取数据,存入rw_buffer,之后调用analysis_command解析命令,执行不同的操作
while (1) {
len = 31232;
len = read(vfs_fd, rw_buffer, BUFFER_SIZE);
IMSG_DEBUG("%s : %d read result = %d.\n", __func__, __LINE__, len);
if (len < 0) {
IMSG_ERROR("%s : %d Can not read the VFS device node, len = [%d] ret = [%d]. Wait for 1s\n",
__func__, __LINE__, len, errno);
usleep(10000);
continue;
}
retVal = analysis_command(rw_buffer);
if (retVal < 0) {
IMSG_ERROR("%s : %d Invail command read from VFS device node.\n", __func__, __LINE__);
continue;
}
writeLen = retVal;
retVal = write(vfs_fd, rw_buffer, writeLen);
if (retVal < 0) {
IMSG_ERROR("%s : %d Can not write to VFS device node.\n", __func__, __LINE__);
continue;
}
}
到此,TEE的OS是在哪里加载的,其实那部分不在teei_daemon中加载,系统起来时os镜像是有secure boot自动加载进来的,关于整个TEE的框架,之后再分析。
总结
从上文的分析,teei_daemon通过init.rc启动作为一个service,然后加载相关的TA和teei os。维护这部分的代码可能会修改相关的属性名称,所以我们在使用时,也要注意配置相关的属性值,当然,关于具体teei_daemon实现的操作细节还需在底层去深究 。