teei_daemon流程分析

2017/12/14 Android secure

前言

在开发过程中用到了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实现的操作细节还需在底层去深究 。

Search

    Table of Contents