【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:

  1. 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条)

刀客源码 游客评论