optee UTA加载

流程

在这里插入图片描述

动态TA按照存储位置的不同分为REE filesystem TA:存放在REE侧文件系统里的TA;
Early TA:被嵌入到optee os里的在supplicant启动之前就可用了。
这里我们讲的是常规的存放在REE侧文件系统里的TA。

通过GP标准调用的与TA通信的命令(opensession\invoke\closession)其实都是std smc call,该smc调用后,会进入到TEE中的tee_entry_std中。
在__tee_entry_std函数中调用就是opensession\invoke\closession的接口,调用到entry_open_session接口

  1. 动态TA最终会在tee_ta_init_user_ta_session函数里加载。
    tee_ta_init_user_ta_session里调用ldelf_load_ldelf函数,其实现大致为:
  2. 在代码编译的时候,optee-os下的ldelf目录下编译出ldelf.elf二进制文件,通过gen_ldelf_hex.py脚本将ldelf.elf二进制文件生成ldelf_hex.c文件,其二进制数据会被写入数组ldelf_data,还有代码段,数据段的大小
  3. ldelf_load_ldelf函数中将ldelf_data加载到内存中
    再通过ldelf_init_with_ldelf函数调用thread_enter_user_mode函数切换到用户模式el0,运行ldelf的代码
  • PTA最终tee_ta_init_pseudo_ta_session函数里加载

ldelf

elf格式的文件是一种可执行文件,ldelf就是加载elf文件的加载器。
而TA文件就是加了头的elf文件,所以ldelf其作用为load需要加载的TA。
调用ldelf → ta_elf_load_main → load_main加载TA的二进制文件。

optee_os\ldelf\start_a64.S

https://blog.csdn.net/qq_42878531/article/details/121783732

init_elf

验签、解密、加载TA二进制文件,并判断其是否是ELF格式。
sys_open_ta_bin
系统调用 ldelf_syscall_open_bin 函数,其功能是调用systemPTA,找到并打开TA文件,并返回句柄。
此函数会遍历注册的TA_STORE,调用open等操作函数。注册的是下面这个。

TEE_TA_REGISTER_TA_STORE(9) = {.description = "REE",.open = ree_fs_ta_open,.get_size = ree_fs_ta_get_size,.get_tag = ree_fs_ta_get_tag,.read = ree_fs_ta_read,.close = ree_fs_ta_close,
};

ree_fs_ta_open

  1. 先调用rpc_load:通过rpc调用ree侧的tee_supplicant ,传入uuid,ree侧将uuid对应的TA二进制文件加载到共享内存中,在rpc_load中包含两次TA加载的rpc请求,第一次参数里只有UUID,因为此时optee-os不知道加载的TA的image大小,tee supplicant接收到TA加载请求后由于解析出参数的image size为0,所以其通过UUID读取TA文件后计算出ta_size,发现传入大小不足,所以此时没有加载TA 并返回需要传入的size给到optee-os的rpc_load()
  2. 其得到size后通过rpc请求size大小的共享内存并得到地址,此时将uuid、共享内存地址、size传入作为第二次rpc加载TA请求,tee-suplicant收到后加载TA到对应的共享内存中。
/* Request TA from tee-supplicant */
res = rpc_load(uuid, &ta, &ta_size, &mobj);
shdr_alloc_and_copy

通过rpc_load()之后得到的TA加载的共享内存地址,因为TA镜像在签名时增加签名相关的头部文件shdr,在此函数中计算shdr的大小,struct shdr + hash_size + sig_size。然后申请此大小的内存并将TA镜像的shdr拷贝到申请的内存里。用于后面的验签流程。

/* Make secure copy of signed header */
shdr = shdr_alloc_and_copy(ta, ta_size);
shdr_verify_signature

执行验签工作。传入镜像头部文件shdr指针。shdr包括了magic、img_type、img_size、algo等参数。先检验代码中的magic与shdr中的是否一致,从前面提到的ta_pub_key.c中读取ta_pub_key_modulus,提取出pub_key,从shdr中提取hash和sig,使用rsa算法验签此shdr。

/* Validate header signature */
res = shdr_verify_signature(shdr);

然后在ree_fs_ta_open()里还要取出TA镜像里的uuid与传入的uuid比较,并初始化hash_ctx。

sys_map_ta_bin

ldelf_syscall_map_bin,其功能是调用systemPTA,映射TA二进制文件的各种segment到安全内存中。
res = sys_map_ta_bin(&va, SMALL_PAGE_SIZE, flags, elf->handle, 0, 0, 0);
在init_elf中,此处是第一次调用,传入的长度是0x1000,最小页大小。目的为先将TA的从0到0x1000的数据映射到安全内存。主要作用先申请块安全内存,然后映射其地址

struct fobj *f = fobj_ta_mem_alloc(num_pages);
mobj = mobj_with_fobj_alloc(f, file);
res = vm_map_pad(uctx, va, num_rounded_bytes,TEE_MATTR_PRW, vm_flags, mobj, 0,pad_begin, pad_end, 0);

经过这几个步骤,其就会申请了大小为num_pages个pages的空间,并映射到va_range的地址空间里,调试出的信息就是申请的是phys安全内存物理地址,变为了va的虚拟地址(fobj_ta_mem_alloc)。
在这里插入图片描述

optee启动时已划分好
在这里插入图片描述

binh_copy_to

然后调用binh_copy_to函数,此函数调用注册的ree_fs_ta_read,将共享内存中的TA镜像加载到安全内存中。

/*此函数是根据binh句柄,其中记录了当前读取ELF文件的偏移,文件总大小的信息,来从offs_bytes在文件中的偏移,读取num_bytes长度的数据到va这个地址,其调用注册的read接口,也就是ree_fs_ta_read*/
static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va,size_t offs_bytes, size_t num_bytes)
{TEE_Result res = TEE_SUCCESS;size_t next_offs = 0;if (offs_bytes < binh->offs_bytes)return TEE_ERROR_BAD_STATE;if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs))return TEE_ERROR_BAD_PARAMETERS;if (offs_bytes > binh->offs_bytes) {/*此处需要读取文件的偏移已经大于了文件所处的偏移,因为ELF文件中的segment之间存在空的部分,如果不读取中见的信息,那么ree_fs_ta_read里更新hash_ctx就会出问题,导致校验hash不过,所以传入空的地址给read函数,只是为了读取空的部分更新hash_ctx,并不加载*/res = binh->op->read(binh->h, NULL,offs_bytes - binh->offs_bytes);if (res)return res;binh->offs_bytes = offs_bytes;}if (next_offs > binh->size_bytes) {/*这种情况就是需要读取的部分已经超过了文件的范围,所以此时直接将文件剩下的全部读取*/size_t rb = binh->size_bytes - binh->offs_bytes;res = binh->op->read(binh->h, (void *)va, rb);if (res)return res;memset((uint8_t *)va + rb, 0, num_bytes - rb);binh->offs_bytes = binh->size_bytes;} else {res = binh->op->read(binh->h, (void *)va, num_bytes);if (res)return res;binh->offs_bytes = next_offs;}return TEE_SUCCESS;
}
ree_fs_ta_read
static TEE_Result ree_fs_ta_read(struct user_ta_store_handle *h, void *data,size_t len)
{struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;/*获取TA镜像除去头之后的elf格式所在位置*/uint8_t *src = (uint8_t *)handle->nw_ta + handle->offs;size_t next_offs = 0;uint8_t *dst = src;TEE_Result res = TEE_SUCCESS;if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||next_offs > handle->nw_ta_size)return TEE_ERROR_BAD_PARAMETERS;/*判断TA类型*/if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {if (data) {dst = data; /* Hash secure buffer *//*解密len长度的数据到安全内存中,加载多长的数据就解密多长的数据*/res = tee_ta_decrypt_update(handle->enc_ctx, dst, src,len);if (res != TEE_SUCCESS)return TEE_ERROR_SECURITY;} else {size_t num_bytes = 0;size_t b_size = MIN(1024U, len);uint8_t *b = malloc(b_size);if (!b)return TEE_ERROR_OUT_OF_MEMORY;dst = NULL;while (num_bytes < len) {size_t n = MIN(b_size, len - num_bytes);res = tee_ta_decrypt_update(handle->enc_ctx, b,src + num_bytes, n);if (res)break;num_bytes += n;res = crypto_hash_update(handle->hash_ctx, b,n);if (res)break;}free(b);if (res != TEE_SUCCESS)return TEE_ERROR_SECURITY;}} else if (data) { /*不是加密的TA则直接拷贝*/dst = data; /* Hash secure buffer (shm might be modified) */memcpy(dst, src, len);}if (dst) {/*更新hash_ctx,以便后面计算出TA的hash值使用*/res = crypto_hash_update(handle->hash_ctx, dst, len);if (res != TEE_SUCCESS)return TEE_ERROR_SECURITY;}handle->offs = next_offs;/*将句柄的偏移更新*//*判断当前是否已经加载了所有的segment*/if (handle->offs == handle->nw_ta_size) {if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {/** Last read: time to finalize authenticated* decryption.*/res = tee_ta_decrypt_final(handle->enc_ctx,handle->ehdr, NULL, NULL, 0);if (res != TEE_SUCCESS)return TEE_ERROR_SECURITY;}/** Last read: time to check if our digest matches the expected* one (from the signed header)*//*加载所有segment之后进行hash校验与shdr里的比较*/res = check_digest(handle);if (res != TEE_SUCCESS)return res;if (handle->bs_hdr)res = check_update_version(handle->bs_hdr);}return res;
}

继续执行init_elf

由此时传入的参数得知,此次的sys_map_ta_bin只是将TA的elf文件的头映射到了内存中。
有了头就可以根据elf头判断其基本信息了。
完成这些之后,程序会解析判断其elf格式

if (!IS_ELF(*(Elf32_Ehdr *)va))/*根据elf head magic判断*/err(TEE_ERROR_BAD_FORMAT, "TA is not an ELF");res = e32_parse_ehdr(elf, (void *)va);if (res == TEE_ERROR_BAD_FORMAT)res = e64_parse_ehdr(elf, (void *)va);/*解析elf head到elf结构体*/if (res)err(res, "Cannot parse ELF");if (MUL_OVERFLOW(elf->e_phnum, elf->e_phentsize, &sz) ||ADD_OVERFLOW(sz, elf->e_phoff, &sz))err(TEE_ERROR_BAD_FORMAT, "Program headers size overflow");if (sz > SMALL_PAGE_SIZE)err(TEE_ERROR_NOT_SUPPORTED, "Cannot read program headers");elf->phdr = (void *)(va + elf->e_phoff);

ELF格式的文件加载到安全内存之后,加载器会判断其是否是ELF格式的文件,以及头是否符合elf规范。
ELF格式分两种,32位和64位,基本一样。格式的基本信息包含在ELF的头里,这个是通用的,使用此结构体表示。

/** ELF header.*/
typedef struct {unsigned char	e_ident[EI_NIDENT];	/* File identification. */Elf64_Half	e_type;		/* File type. */Elf64_Half	e_machine;	/* Machine architecture. */Elf64_Word	e_version;	/* ELF format version. */Elf64_Addr	e_entry;	/* Entry point. */Elf64_Off	e_phoff;	/* Program header file offset. */Elf64_Off	e_shoff;	/* Section header file offset. */Elf64_Word	e_flags;	/* Architecture-specific flags. */Elf64_Half	e_ehsize;	/* Size of ELF header in bytes. */Elf64_Half	e_phentsize;	/* Size of program header entry. */Elf64_Half	e_phnum;	/* Number of program header entries. */Elf64_Half	e_shentsize;	/* Size of section header entry. */Elf64_Half	e_shnum;	/* Number of section header entries. */Elf64_Half	e_shstrndx;	/* Section name strings section. */
} Elf64_Ehdr;
elf head头后面就是程序头表program segment header,位置就是ELF头里的e_phnum值在的偏移。记录了每个Segment的相关信息,比如类型、对应文件的偏移、大小、属性等。用下面的结构体表示。
typedef struct {Elf64_Word  p_type;     /* Entry type. */Elf64_Word  p_flags;    /* Access permission flags. */Elf64_Off   p_offset;   /* File offset of contents. */Elf64_Addr  p_vaddr;    /* Virtual address in memory image. */Elf64_Addr  p_paddr;    /* Physical address (not used). */Elf64_Xword p_filesz;   /* Size of contents in file. */Elf64_Xword p_memsz;    /* Size of contents in memory. */Elf64_Xword p_align;    /* Alignment in memory and file. */
} Elf64_Phdr;

optee example的一个TA的elf读出其program header:
aarch64-linux-gnu-readelf -l xxx.elf
在这里插入图片描述

init_elf函数结束

总结:找到TA文件,验签成功则解密0x1000头部数据,加载0x1000字节到内存,判断其是否是elf以及是否合法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/685229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AIGC】Stable Diffusion的ControlNet参数入门

Stable Diffusion 中的 ControlNet 是一种用于控制图像生成过程的技术&#xff0c;它可以指导模型生成特定风格、内容或属性的图像。下面是关于 ControlNet 的界面参数的详细解释&#xff1a; 低显存模式 是一种在深度学习任务中用于处理显存受限设备的技术。在这种模式下&am…

Vue的一些基础设置

1.浏览器控制台显示Vue 设置找到扩展&#xff0c;搜索Vue 下载这个 然后 点击扩展按钮 点击详细信息 选择这个&#xff0c;然后重启一下就好了 ——————————————————————————————————————————— 2.优化工程结构 src的components里要…

MySQL数据库基础第四篇(多表查询与事务)

文章目录 一、多表关系二、多表查询三、内连接查询四、外连接查询五、自连接查询六、联合查询 union, union all七、子查询1.标量子查询2.列子查询3.行子查询4.表子查询 八、事务八、事务的四大特性九、并发事务问题十、事务隔离级级别 在这篇文章中&#xff0c;我们将深入探讨…

数据结构之队的实现

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

用HTML5 Canvas创造视觉盛宴——动态彩色线条效果

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- 声明文档类型为XHTML 1.0 Transitional -…

Python四级考试笔记

Python四级考试笔记【源源老师】 四级标准 一、 理解函数及过程、函数的参数、函数的返回值、变量作用域等概念。 二、 能够创建简单的自定义函数。 三、 理解算法以及算法性能、效率的概念&#xff0c;初步认识算法优化 效率的方法。 四、 理解基本算法中递归的概念。 五、 掌…

【开源】SpringBoot框架开发独居老人物资配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询社区4.2 新增物资4.3 查询物资4.4 查询物资配送4.5 新增物资配送 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的独居老人物资配送系统&#xff0c;包含了社区档案、…

win7自带截图工具保存失效解决办法

今日发现一台远航技术的win7中自带的截图工具使用时正常&#xff0c;保存图片时没有弹出保存位置的对话窗口&#xff0c;无法正常保存图片。解决方案如下&#xff1a; 1、进入注册表编辑器。开始-搜索程序和文件-输入 regedit 按下回车键&#xff0c;打开注册表&#xff1b; 2、…

多模态基础---BERT

1. BERT简介 BERT用于将一个输入的句子转换为word_embedding&#xff0c;本质上是多个Transformer的Encoder堆叠在一起。 其中单个Transformer Encoder结构如下&#xff1a; BERT-Base采用了12个Transformer Encoder。 BERT-large采用了24个Transformer Encoder。 2. BERT的…

静态时序分析:SDC约束命令set_clock_transition详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 在静态时序分析&#xff1a;SDC约束命令create_clock详解一文的最后&#xff0c;我们谈到了针对理想(ideal)时钟&#xff0c;可以使用set_clock_transition命令直…

数据结构与算法:双向链表

朋友们大家好啊&#xff0c;在上节完成单链表的讲解后&#xff0c;我们本篇文章来对带头循环双向链表进行讲解 双向链表 双向链表、头节点和循环的介绍构建双向链表节点的构建初始化双向循环链表&#xff08;空链表&#xff09;销毁双向链表 链表的打印双向链表头尾的插与删尾插…

Medical Boundary Diffusion Modelfor Skin Lesion Segmentation

皮肤病灶分割的医学边界扩散模型 摘要 由于多尺度边界关注和特征增强模块的进步&#xff0c;皮肤镜图像中的皮肤病变分割最近取得了成功。然而&#xff0c;现有的方法依赖于端到端学习范式&#xff0c;直接输入图像和输出分割图&#xff0c;经常与极其困难的边界作斗争&#…

B端系统升级方案模板:针对美观性和体验性升级(总体方案)

大家好&#xff0c;我是大美B端工场&#xff0c;专注于前端开发和UI设计&#xff0c;有需求可以私信。本篇从全局分享如何升级B端系统&#xff0c;搞B端系统升级的有个整体思维&#xff0c;不是说美化几个图标&#xff0c;修改几个页面就能解决的&#xff0c;这个方案模板&…

Spring AMQP(3.1.1)设置ConfirmCallback和ReturnsCallback

文章目录 一、起因二、代码1. 定义exchange和queue2. RabbitTemplate3. EnhancedCorrelationData4. 发送消息 环境如下 VersionSpringBoot3.2.1spring-amqp3.1.1RabbitMq3-management 一、起因 老版本的spring-amqp在CorrelationData上设置ConfirmCallback。但是今天却突然发…

非常详细!操作系统【IO核心子系统】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;OS从基础到进阶 &#x1f3c6;&#x1f3c6;本文完整PDF源文件请翻阅至文章底部下载。&#x1f3c6;&#x1f3c6; 1 I/O核心子系统——概述1.1 核心子系统要完成的功能1.1.1 假脱机技术1…

Python 异常处理及程序调试

Python 是一门功能强大而又易于学习的编程语言&#xff0c;它提供了丰富的工具和库来帮助开发者编写高效、稳定的程序。然而&#xff0c;在编写复杂的应用程序时&#xff0c;错误和异常是难以避免的。本文将介绍 Python 中的异常处理机制以及程序调试技巧&#xff0c;帮助读者提…

JavaScript中什么是事件委托

JavaScript 中的事件委托&#xff08;Event delegation&#xff09;是一种重要的编程技术&#xff0c;它能够优化网页中的事件处理&#xff0c;提高程序的性能和可维护性。本文将详细介绍事件委托的概念、工作原理&#xff0c;并提供示例代码来说明其实际应用。 事件委托是基于…

Linux版Black Basta勒索病毒针对VMware ESXi服务器

前言 Black Basta勒索病毒是一款2022年新型的勒索病毒&#xff0c;最早于2022年4月被首次曝光&#xff0c;主要针对Windows系统进行攻击&#xff0c;虽然这款新型的勒索病毒黑客组织仅仅才出来短短两个多月的时间&#xff0c;就已经在其暗网平台上已经公布了几十个受害者之多&…

【案例8】用户中心实现涉及内容和过程

图1 如图1是用盒子模型内容实现的&#xff0c;但是需要了解一些内容。 一.内容知识引入 1.内边距属性&#xff08;padding&#xff09; 为了调整盒子在网页中的显示位置&#xff0c;常常需要为元素设置内边距。内边距也被称为内填充&#xff0c;是指元素内容和边框之间的距离…

linux安装mysql8且初始化表名忽略大小写

mysql8下载地址 MySQL8.0安装步骤 1、把安装包上传到linux系统&#xff0c;解压、重命名并移动到/usr/local/目录&#xff1a; cd ~ tar -xvf mysql-8.0.32-linux-glibc2.12-x86_64.tar.xz mv mysql-8.0.32-linux-glibc2.12-x86_64/ mysql80/ mv mysql80/ /usr/local/2、在M…