摘要
【tee新手的第一篇美文】keystone编码粗读 武汉大学信安在学,近期在通过自学Risc-v构架的可靠实行自然环境。(实验数据大多数是为了更好地交叉。临时起意写一篇blog,共享一些自身读编码的体会心得了解。)这篇內容由队与我友汇总而成,若有不正确热烈欢迎纠正沟通交流。 keystone是risc-v构架的开源系统tee。运用risc-v的pmp来防护页表,进一步变小了可靠基。runtime…
正文
【tee新手的第一篇美文】keystone编码粗读
武汉大学信安在学,近期在通过自学Risc-v构架的可靠实行自然环境。
(实验数据大多数是为了更好地交叉。临时起意写一篇blog,共享一些自身读编码的体会心得了解。)
这篇內容由队与我友汇总而成,若有不正确热烈欢迎纠正沟通交流。
keystone是risc-v构架的开源系统tee。
运用risc-v的pmp来防护页表,进一步变小了可靠基。
runtime和sm的解耦也很有趣:
能够 类似了解为:
将安全性作用集中化在sm中,做为保安人员。
runtime则给予edge call等各种各样与安全性没有太大的关系的服务项目,能够 了解为家庭保姆。
文件目录
一、Keystone架构及enclave运作全过程:
别的觉得较为关键的涵数
二、runtime和sdk的原理:
启用、回应线路
runtime中别的零零碎碎的物品
逐渐文章正文:
一、Keystone架构及enclave运作全过程
keystone的框图如上所显示
因此 host端(图上的untrusted)必须启用keystone相关服务的情况下,必须从U方式OS层,再从OS到SM层,随后SM启用opensbi插口进行对于存储器的改动等实际操作。
在编码构造上便是
sdk -> linux_kernel_driver -> sm -> opensbi
以host的enclave.run实际操作为例子,从高层往最底层查询启用全过程:
最先在host端启用enclave.run方式 :
这一涵数最后的实际效果应该是将程序运行流从host端转为eapp,而且储存存储器组,改动存储器组到eapp相匹配的值
host.cpp:
这一涵数最后启用了pDevce的run方式 :
里边运用了Ioctl涵数,和linux驱动器层开展通讯,将操作码request传入驱动器层。
此后程序流程流开展到OS驱动器层。
OS驱动器层在运行以前开展init复位:
以后用ioctl开展的通讯,会转至申请注册的keystone_ioctl涵数內部:
历经switch对cmd的归类,进到这一支系:
这一涵数內部,完成了对主要参数的储存和查验,以后进到sbi_sm_run_enclave涵数内
这一涵数最后启用sbi_ecall:
sbi_ecall应该是用以下建筑结构传送,由于extid实际数据信息一致,应该是依据这一项开展鉴别
(注:猜想这一sbi_ecall涵数应该是一个OpenSBI函数库,第一个主要参数意味着的是最底层具体编码ecall出现异常启用的a7的值,在riscv里边,承诺用a7传送出现异常种类,以后sm根据这一a7去分派出现异常处理函数。)
相匹配的申请注册涵数以下:
在sm复位的情况下进行
以后sbi_ecall会进到到sm层:
这一sbi_sm_run_enclave:
- run_enclave中,进行下列实际操作:
1.1改动存储器组的值,相匹配必须run的那一个enclave,而且把当今的存储器组的值保存
1.2旋转pmp的管理权限。
本人了解:针对host端而言高管理权限的pmp内容,针对eapp端而言就应该是低权程度。
比如eapp应当有着针对自身的enclave的全部管理权限,可是os对其应当沒有管理权限。
而host端来讲,os应当有着全部管理权限。
参照:http://docs.keystone-enclave.org/en/latest/Security-Monitor/index.html#pmp-internals
1.3储存一些信息内容,用以以后的一些实际操作,比如查验这类的。例如储存当今的hart(硬件配置进程)相匹配的eid,及其是不是在enclave中,用以以后的实际操作。
2.sbi_trap_exit:
这调用函数了opensbi的插口,作用是实行终断,而且重新加载存储器组regs。
由于在以前的涵数中改动了存储器组regs,配套设施到eapp,因此 实行完这一以后,实行流就到eapp之中。
此后enclave.run()实际操作完毕。
别的的enclave实际操作,例如enclave.init()等启用阶段相近。作用上面有一些不同点。
别的觉得较为关键的涵数:
/sm/pmp.c
主要参数:1.region_idx为以前根据必须配备的enclave的内存空间,提早储存出来的数据信息。
先mark一下Pmp体制的原理:
参照:https://zhuanlan.zhihu.com/p/139695407
pmp体制根据Pmp地址寄存器和Pmp配备存储器一同配备。
PMP配备存储器一方面决策了这一PMP内容下的管理权限,是不是可读,可写,可实行,一方面决策了地址寄存器决策详细地址的方法。一共有TOR,NA4,NAPOT,3种不一样方法。
实际方式如下图所显示
因此 依据这两个存储器能够 一同决策一个PMP内容决策的详细地址室内空间和所具备的管理权限。
pmp_set_keystone()涵数完成了2个事儿:
1.依据传到的region_idx相匹配的 pmp_region相匹配建筑结构的信息内容,测算必须载入PMP条目地PMP配备存储器和PMP地址寄存器的值。
2.分辨是不是必须好几个PMP内容来一同写这一个详细地址室内空间。
以后运用PMP_SET宏启用来写存储器,这一PMP_SET宏內部进行以后是OPENSBI的插口和RISCV的内联选编,用以写RISCV的情况存储器。。
二、runtime和sdk的原理
edge_common封裝了边沿启用的文件格式:
每一次启用都用一个建筑结构,要求size来限定访问限制。edge data和ret data都一样,是 表针 size的方式。
主要参数用偏移来找寻。
回到的数据信息独立界定一个建筑结构。
edge_call.c封裝了syscall的io文件格式、边沿查验。每一次edge call都必须查验表针实效性,在共享内存区中寻找相匹配的建筑结构,来进行edge call setup call。
runtime中的syscall 借助以上edge_call完成,设计原理:
(参照:https://rmheng.GitHub.io/2021/01/29/keystone-2020/)
runtime能够 了解为承担为eapp给予与安全性不相干的服务项目的一个代理商。由于仅仅将启用要求开展查验、封裝,再交到sbi用ecall选编解决,因此 说成代理商。
(handler syscall 用了pk的插口。没有keystone的范围。)
syscall借助edge_call完成:
dispatch edgecall ocall
dispatch edgecall syscall
各自进行ocall和syscall的启用,一同的大概步骤:
在shared mem的部位个edge call构造。在shared mem中取详细地址,寻找建筑结构的表针。取值call id,复制call data等运行内存。
边沿查验的全过程在造成表针时开展。
启用、回应线路:
启用时:
eapp进行syscall或ocall。
syscall:
被io_wrap封裝成以下系统进程:
eg:
代理商全过程便是:在io_wrap选用dispatch_edgecall_syscall涵数开展外派。
dispatch_edgecall_syscall实际工作中:
set up call,把共享内存区的一个表针变为一个安全性可以用的edge call建筑结构,取值在其中数据信息。
外派結果ret便是eapp要想了解的系统进程的传参。
ocall在handle_syscall中历经pk被外派出来 :
(handle_syscall这一涵数在pk里被启用,pk临时还没有科学研究)
dispatch_edgecall_ocall比syscall多一个复制客户运行内存的全过程。
最底层根据实际操作csr存储器来完成,还没有看。
回应时:
syscall:
由sdk进行对启用的回应。
每一个enclave建立时都需要把incoming dispatch申请注册到oFuncDispatch,含意便是,为即将来临的edge call留一个表针,那时候碰到边沿启用或是终断,就根据这一涵数来回应。这儿的涵数,主要参数全是表针,因此 回应时要根据call id来获知自身要做什么事情。
syscall dispatch.c文档中的incoming call dispatch开展查验:
查验call id。分辨是syscall 或是ocall或是失效。合理的call id必须在edge call table中申请注册。这儿的buffer是edge call建筑结构的表针,能够 了解为一个函数指针。
enclave中的registerOcallDispatch:
把一个涵数指针赋值给oFuncDispatch,事后在run的情况下,会启用oFuncDispatch,这一涵数的主要参数是个表针。
host处,开展取值,将edge call关联到一个表针上:
把上边讲过的incoming_call_dispatch取值给oFuncDispatch,该涵数会分析表针处的运行内存,得到call id分辨是syscall、ocall或是badcall,并开展相对应解决。
enclave::run的界定:
enclave的运作全过程。error是个枚举类型构造。意味着run的不一样結果。
运作交到pDevice后,host挂起来。检验到edge call host或是产生终断后进到while循环系统。然后进到if语句,分辨该启用是不是安全性。
enclave中的run涵数,启用了oFuncDispatch,这东西便是刚刚的edge call的表针,运作了这一edge call,就进行对call的回应:
edge call会自身把传参封裝为建筑结构,写进共享内存区。无需在这儿return。
解决完毕后,根据resume函数,将决策权归还enclave。eapp再次运作。
ocall要申请注册:
把函数指针写到edge call table里
回应步骤或是历经incoming_call_dispatch:
分辨为会员注册过的edge call以后就用edge call table表中的函数指针运作,buffer一样是共享内存区的表针,偏向了edge call。
edge call会自身把传参封裝为建筑结构,写进共享内存区。无需在这儿return。
runtime中别的零零碎碎的物品:
interrupt:
适用数字时钟终断:
linux_wrap封裝了适用的linux系统进程:
这种涵数会輸出syscall的結果,比如:
sbi.c
sbi.h
封裝了底层的sbi实际操作,根据ecall改动csr进行各种各样错误处理。
page_swap.c:
封裝了调页实际操作:
假如界定了页表数据加密,便会用aes256数据加密页表。
假如界定了页表hach,便会用merkle树检测页表是不是被不法修改过。采用的hash算法是sha256
二种密码算法优化算法都是在runtime文件夹名称中有c语言完成。
mm.c
mm.h
是代码优化
內容许多,但或是可以看个大约的。实际采用了在详说吧。
vm.c
vm.h
完成虚拟注册地址和物理地址的变换
paging.c
paging.h
段页式管理方法的完成,看上去还更费劲一些,由于有时不明白涵数名字。= =
freemem.c
freemem.h
free运行内存的涵数,spa是simple page allocator 。没细心看,可是编码易读性较为高,和以前看了的free完成较为相近。
再就没有什么关键的文档了,runtime的大概构造便是这种。
谢谢阅读文章  ̄▽ ̄ 热烈欢迎沟通交流!
第一次写文章赚钱,写的跟实验数据一样,较为简单,多多包涵哈
2021-05-17
没经容许,严禁转截 !
关注不迷路
扫码下方二维码,关注宇凡盒子公众号,免费获取最新技术内幕!
评论0