Confidential Computing方向论文的阅读笔记
occlum
occlum策略
-
SGX(software guard extensions)创建一个用户私有的空间存储隐私数据,叫做enclaves(飞地)库操作系统(libos)被引入到SGX中,从而应用程序能够使用很少的更改就能够获得足够的安全性。SGX应该能够支持多线程,但是现存的SGX libos不能兼顾效率和安全。occlum是一种兼顾效率与安全的sgx-libos实现。
-
occlum由三部分组成:toolchain 工具链 verifier 验证器 libos 操作系统库 occlum验证器输入elf二进制文件,并且检查其是否符合mmdsfi规范
-
occlum将libos进程实现为SFI隔离进程(SIPS),SFI是一种软件指令技术,用于沙箱化不受信任的模块。occlum设计了一种新的基于MPX的多域SFI(MMDSFI)方案,并利用MMDSFI实现SIP的隔离。同时设计了独立的验证器保证mmdsfi的安全性。sips安全地共享单独enclaves的地址空间, libos因此实现了有效的多任务。
-
sgx的使用者需要将应用程序分为enclave和non-enclave两部分,导致了效率的降低
最成功的sgx目前是Graphene-SGX,libos进程被其实现为eips,每个eips需要一个libos实例托管,这造成它的速度很慢。occlum基于SFI的软件故障隔离机制,SFI是一种软件指令集技术用于沙箱化不受信任的模块(被称为domains)occlum不对SFI使用的地址空间和大小做出限制。occlum效率在微基准上效率大约是sgx的6600倍,应用程序水平上大约是sgx的500倍。 -
occlum中enclave的创建
enclave创建需要在页表项上标记,并且cpu生成保护,并在此区域进行大量运算
在sgx1.0中,enclave 生成后不能更改、删除、增加,2.0则无此限制。
enclave内部不允许分段,page tables 在sgx安全模型中也是不受信任的
多sgx线程能够在同一个enclave中运行,可以被硬件异常打断,这种打断称为aex,此时,cpu core的状态将会被自动存储,存储区域被称为状态保存区域SSA,恢复时根据SSA恢复。 -
occlum的兼容性
兼容性包括代码级别和二进制级别
对比haven scone panoply graphenesgx
haven graphenesgx时二进制级别
panoply和occlum时源码级别
haven的tcb比其余都大(此处指的是Trusted Computing Base) -
intel mpx
mpx是一组x86指令集,用于提供bound checking
检查用的寄存器有四个 bnd0 - bnd3
存储64位的值,bndcl和bndcu 用来检查低位和高位 -
SFI
SFI是沙箱化软件指令技术
sips假设在被libOS加载时是不安全的,存在着安全漏洞,occlum的目标是隔离enclave内的sips
包括两种隔离的方式:
进程间隔离
进程-libos 隔离,在sip中保护libos -
occlum考虑的攻击方式
occlum 不考虑iago攻击,iago可以通过orthogonal work来解决(类似sego)
不考虑拒绝服务攻击
不考虑side-channel攻击 -
sips和eips的比较
eip需要创建新的enclave,和其余enclave建立协议,在加密流上复制过程状态
IPC过程eips需要加密解密,sips不需要(因为eips在libos之间而sips在同一个libos中)
传统eips只读(为了避免数据共享的问题),sips可读可写 -
occlum中进程的创建方式
在occlum中,使用spawn代替了fork
fork因为需要子进程和父进程使用相同的地址空间,所以和单地址空间的os语义不符 -
Domain/SIP的组成
其中code权限是RWX,data权限是RW
data区域通过G1和G2区域包裹 -
occlum对于控制转移的检查
为了防止进入memguard的区域,所以需要对直接控制转移进行编译时检查,对间接控制转移进行运行时检查
因此MMDSFI对于控制流实行CFI(粗糙的控制流完整性检查) -
cfi_label 指令用于标志控制域,它的特征如下:
没有操作数,因此对于cpu没有影响
对齐,8字节对齐后四个字节是独一无二的域id 在插入域前被更改,cfi_label会插入到在每个间接控制转移之前
使用nopl指令实现 -
cfi_guard指令
实现了在寄存器中存放的目标地址的间接控制转移
首先,mov加载目标地址的value进入scratch寄存器
其次,比较寄存器和bnd1的值 -
MMDSFI的编译优化
冗余检查消除
在[x − Gi.size,x + Gi.size]范围内的regions 因为收到G1和G2的保护,因此不需要检查
循环检查的提升
如果在loop中操作数比Gi.size更小,所以mem_guard能够在循环之前被插入 -
occlum verifier的过程
1.完整分解
分解器扫描代码段得到所有的cfi_labels 用户程序必须从cfi_labels开始,
分解程序按照程序顺序和直接控制转移的顺序进行
间接控制转移只能以cfi_labels为目标(在第三阶段进行转移验证)
最终得到的集合R包含所有可到达指令
2.指令集验证
确保R不包含任何要求特权的危险指令
分为三种类型:
SGX指令集,
MPX指令集,
Miscellaneous指令集
改阶段只需要查找即可
3.验证控制转移
分为四种:
直接控制转移
基于寄存器的间接控制转移
基于内存的间接控制转移
基于返回值的间接控制转移
后两种直接拒绝
基于上述验证,可以提出引理5.1:任何在domain中基于寄存器的间接控制转移仅仅会跳到cfi_labels中,
4.地址访问验证
根据R构建CFG,之后进行CFG的编译优化(如上文所示)
之后按照五种分类进行地址访问的验证
直接地址偏移 拒绝
vector SIB 拒绝 (这种指令访问了多条非规定类别的地址)
Scale-Index-Base(SIB)检查地址在[D.begin - Gi.size, D.end + Gi.size)范围内
Implicit register-based 同上
RIP-relative 同上
libos
组成
- ELF loader
能够完成一般的Unix-like的基础工作,例如分析二进制文件,拷贝程序图像,初始化CPU状态等等。
除此之外,还有四个作用:
检查是否被verifier验证过
重写cfi_labels,将最后四个字节分配为域ID
启动器在进程图中插入一段跳到入口点的代码,这段代码是唯一跳出沙箱的方法
根据SIP domain的内存布局初始化MPX的边界寄存器 - Syscall interface 系统调用接口
完成system call并且回到SIP之前,libos将要先确定返回地址是对应正确SIP的cfi_label - Memory management
Occlum将会在enclave初始化期间预先分配可用的enclave pages并且设定优先级
不能够共享内存映射,因为SGX不能够映射EPC页面到多个虚拟地址 - Process management
Occlum提供spawn替代fork,来创建sips
这种threads是透明的,
这使得libos从进程调度中释放出来
sips的IPC通过libos之间的共享数据结构实现 - file system
基于SGX的protected file system,但是相比SGX,sips多了文件元数据和文件目录的加密 - network
依靠宿主os进行,需要用户级的网络加密,比如TLS
安全性分析
- 代码注入
SGX libos为了动态加载程序,因此预留了带有RWX权限的enclave pool
occlum能够免疫code injection attack
因为sip仅能向数据区域写内容,而且没有执行权限
只有occlum libos能够更改可执行的enclave页面
libos确保无法通过sips滥用system call,恶意 sip不会注入任意代码 - ROP攻击
通过MMDCFI执行的粗粒度的CFI防止了不信任的代码跳到任意的位置
(仅能跳到cfi_labels)
verifier已经验证并且覆盖了ROP攻击的可能性
实现
Occlum的libos由rust完成,toolchain由c++完成,verifier由python完成
toolchain基于llvm 7.0,在后端中加了两趟:单指令控制转移,访存指令分析和优化
更改了LLD,链接器因此生成与MMDSFI兼容的代码。
更改了musl libc ,posix_spawn使用occlum的spawn而不是vfork和execve
验证器使用了Zydis库,支持SGX和MPX指令
使用了PyVex库,将x86指令转换成为VEX IR
使用了基于FUSE的工具安装和操纵occlum 加密文件系统
libos目前只支持静态链接的ELF可执行文件。
sgx
简介
enclave中含有解密数据代码、计算代码和加密结果的代码
SGX留出一个内存区域称为Processor Reserved Memory(PRM),cpu保护prm免受非enclave内存访问的影响,包括内核,虚拟机。SMM访问,以及从外围设备的DMA访问
PRM由4KB的页面组成,存储enclave代码和数据。不受信任的系统软件负责将EPC(enclave页面缓存)分配给Enclave。CPU在Enclave页面缓存元数据(EPCM,§5.1.2)中跟踪每个EPC页面的状态,以确保每个EPC页面只属于一个Enclave。
enclave中的初始代码和数据由不受信任的系统软件加载,在加载阶段,系统软件要求CPU将数据从未受保护的内存(PRM外部)复制到EPC页面,并将页面分配给正在设置的enclave(§5.1.2)
将所有enclave页面加载到EPC后,系统软件要求CPU将enclave标记为已初始化,此时应用软件可以在enclave内运行代码。
当enclave加载时,其内容由CPU加密处理,当初始化完成时,其hash将会成为enclave的度量散列
执行流只能通过特殊的CPU指令访问,类似于从用户态到内核态的方式,enclave始终在ring 3的模式下运行,并且地址转换通过内核和管理程序进行。为了避免数据泄露,在中断、页错误、VM退出时,会首先形成enclave出口,将模式从enclave切换到ring 3,使用人造的值替换外部的CPU寄存器。EPC分配给enclaves通过ring 0的cpu指令交由os内核完成。sgx通过加密保护确保机密性和完整性。
Intel计算架构背景
留空
SGX的安全性背景
sgx的机密性通过Encryption保证
完整性通过MAC / Signatures保证
新鲜性通过Nonces + integrity保证
所谓的freshness就是防止旧的信息替换新的信息所引发的加密问题
机密性
对于对称性加密,公钥的发送通道必须同时保证机密性和完整性
而对称加密的通道则只需要保证完整性
对称密钥分组密码与操作模式相结合。大多数操作模式要求为每个加密消息生成随机初始化向量(IV)。
计数器(CTR)和密码块链接(CBC)是推荐的操作模式示例
非对称加密则一般和对称加密相结合,发送方生成一个一次性使用的对称密钥并且通过公钥加密
完整性
完整性保证通过安全哈希函数进行
要保证pre-image resistance,用于保护不被由于输出获取输入数据
对称加密一般使用MAC算法进行,使用所谓的HMAC哈希消息认证码完成计算和认证
非对称加密则使用签名的方法验证
新鲜性
新鲜性通过Nonces + integrity保证,使用同步时钟和数据库确保
加密构造
非对称加密通过CA机构保证不需要进行公钥传输,从而保证了安全性
分层CA结构最大限度地减少了根CA私钥的使用,减少了其被泄露的机会。根CA仅对中间CA的证书进行签名,中间CA对最终用户的证书进行签名。
密钥协议
3.2.2
留空
SGX编程模式
支持SGX的处理器通过将每个enclave的环境与enclave外部不受信任的软件隔离开来,并通过实施允许远程方对enclave内部运行的软件进行身份验证的软件认证方案,提供可信计算。SGX的隔离机制旨在保护enclave内执行的计算的一致性和完整性,使其免受来自同一台计算机上执行的恶意软件的攻击
飞地的代码和数据存储在处理器再服务内存(PRM)中,PRM是DRAM的一个子集,其他软件(包括系统软件和SMM代码)无法直接访问。CPU的集成内存控制器(§2.9.3)还拒绝以PRM为目标的DMA传输,从而保护其免受其他外围设备的访问。
PRM是一个连续的内存范围,其边界使用与可变内存类型范围(§2.11.4)具有相同语义的基址和掩码寄存器进行配置。因此,PRM的大小必须是2的整数次方,其起始地址必须与2的相同次方对齐。
Enclave的内容和相关数据结构存储在Enclave页面缓存(EPC)中,该缓存是PRM的子集。
SGX设计支持在一个系统上同时具有多个Enclave,这在多进程环境中是必需的。这是通过将EPC拆分为4 KB的页面来实现的,这些页面可以分配给不同的Enclave。EPC使用与体系结构地址转换功能相同的页面大小。这不是巧合,因为未来的部分将揭示SGX实现与地址转换实现紧密耦合。
opaque
这篇论文写的好烂,看不懂
-
为什么有opaque?
enclave虽然能够保证数据机密性和二进制执行安全,但是仍然有访问模式泄露(access pattern leakage)的问题。
所谓access pattern leakage,在内存层面指的是对于开放系统能够通过检测应用程序页面访问推断加密数据信息。经验表明,多次攻击能够从拼写检查程序的加密文件中提取几百kb的数据;在网络层面指的是当分布式设置时,(排序或者哈希分区)任务产生网络阻塞将会泄露加密数据(例如key skew)。一个攻击者发现网络的元数据能够在mapreduce计算中指出年龄组,亲缘状态,和数据库行数。所以为了保护数据,计算模式应该被忽略,不应该泄露任何访问模式。 -
什么是access pattern leakage
比如group by,在group by中,使用哈希桶从每个机器中查找指定记录放入指定的桶,然后shuffled放入相同的机器中。根据这种流量数据就能够发动攻击窃取数据 -
opaque在那一层实施?
如果在应用层则导致应用特定的结果,如果在执行层则导致无法超越执行图并且无法进行实现上的优化。之前的工作表明,关系模型能够广泛表现大数据负载,包括复杂的图分析和机器学习。所以在query层实现
-
opaque如何实现有效的访问模式保护的?
1.引入一个新的分布式关系操作,避免内存和网络访问模式泄露。包括join和group-by聚合操作,能够在分布式和并行环境中实现obliviousness。此处的挑战是处理边界值(当跨机器的值重复性的出现在一行时),这些操作也随着计算完整性的提出而产生,被称为自我验证计算,防止攻击者影响计算结果。
2.提供了新的query plan,包括基于规则的和基于费用的,能够更好的提升oblivoius计算的性能。在基于规则的情况下,opaque通过oblivious SQL语句生成opaque operators,一些操作可以在保留安全性的情况下删除。在基于花费的情况下,模型引入了安全性作为衡量的新维度,使用join来最小化oblivious操作的数量。opaque允许管理员指定敏感数据。在跨越敏感-非敏感信息表的时候,opaque使用被称为inference detection(推论检测)的方法基于域信息传播敏感信息。Additionally,Opaque propagates operator sensitivity as well for all operators that touch sensitive tables.(这句话没看懂)
3.opaque分为三种运行模式,encryption mode,oblivious mode(能够防止访问模式泄露问题),oblivious pad mode(能够防止size leakage,使用的是永远不减少输出的size的方式) -
在enclave中访问opaque代码是oblivious的吗?为什么
是的,这通过GhostRider这种工具或者使用enclave提供的oblivious内存实现。但是这种内存只有1.4MB左右。 -
opaque的架构是什么样的?
opaque将查询计划器移到了客户端一侧,因为恶意的云控制能够导致错误的结果。在给予一个任务之后,任务驱动器(query planner)将会输出一个DAG任务和一个标识符JID。对于EPC的oblivious部分有非oblivious部分、对于RAM以及整个网络的访问权。 -
opaque的安全性保证是什么样的?
在oblivious模式下,对于每一个敏感的SQL操作,opaque提供透明执行的强数据加密,着重于内存,磁盘,网络等。但是可能会泄露一些静态信息。
在oblivious pad模式下,通过推送filter和pad output的操作,掩盖了这些静态信息。
这一段没看懂
-
opaque加密模式
opaque使用远程策略确保加载正确的代码,使用密钥k来在客户端和enclave之间传输数据。在传输数据之前,enclave使用AUTHENC加密数据,AUTHENC在GCM模式下使用AES加密数据,这是一种高速模式,能够提供身份认证。如何确保输入的数据没有被占据?分片的输入数据的标识符是它的MAC地址。Spark RDD能够与验证方法相结合,抵御roolback attack。 -
什么是非记忆性的排序
非记忆性排序是SQL操作的基础,在机器内部如果能够加载进入OM,则快排然后重新加密,写出结果。如果不能够完全加载,则首先分块快排,之后进行块之间的bitonic sort;在机器外部,则进行column sort,这能够保证每个分块有相同数量的item,防止了leak。column sort是如下的过程:
-
什么是非记忆性操作 oblivious operators?
主要是filter、group by、join三种代数操作。
非记忆性的filter确保攻击者不能知道哪个加密的输入行通过了filter,采用的是0和1分别标记需要记录和需要过滤的行。
原生的group实现会导致leak,因为一些group会比其它的group含有更多的item,当reduce操作发送所有在同group中的行到单个machine时,攻击者能够知道详细信息。
非记忆性的group(大基数的)分为以下几个阶段:1. 基于组属性进行排序,2.scan一列,找到数量3.遍历分区,传递分区数据。做全局汇总4.标记当前分区的item属性,未统计完的标记为dummy5.过滤dummy数据
对于join操作,当使用外键时,维护相互指向的指针,指针的位置揭示了有多少行和哪些行相互连接,同样会泄露信息。这里使用基于sort-merge的equi-join算法解决这个问题。第一阶段:join和排序,第二阶段每个分片找出边界值,第三阶段将所有边界记录收集到同一分区,实现跨机器的调度,第四阶段类似于sort-merge,最初的记录来自于上一阶段的边界值,第五阶段排序并且过滤dummy。
opaque基于比较数据的大小而非内容构建比较的顺序,非记忆性的比较花费取决于两个方面:输入数据的数量和填充记录的尺寸。 -
cost model下数据的计算
当输入的数据在OM大小之内时,复杂度就是快排的复杂度;否则分片快排然后合并。 -
opaque的查询过程是什么样的?
-
opaque operators
-
opaque如何保护有关联的敏感表数据?
使用二次路径分析second path analysis,这通过敏感表之间的依赖分析进行。因此,需要在传统的SQL优化器中加入join的重排序,以减少运行的数量。
注意此处R指的是padding size的大小,而Medication关联表的大小这里也设定为|D|。
什么废话。。。 -
实现
opaque由7000行C++和3600行scala写成。
附录:rust
- trait object:不透明类型,实现了一集traits。这一集traits必须由对象安全的基础traits和任意的auto traits组成。dyn关键字是对于trait object对象类型的前缀,传递时类型已经被消除,由一个指针指向函数指针的方法调用名称映射。
- 对象安全的trait:1.其supertraits必须是对象安全的 2.Sized不是其supertrait 3.不能有任何的关联常量 4. 其关联函数可以从trait中分派或者显式地不分派
- rust借用检查器能够静态地检查确保引用指向有效对象
// This function takes ownership of the passed value
fn take_ownership(value: Box<i32>) {
println!("Destroying box that contains {}", value);
}
// This function borrows the value by reference
fn borrow(reference: &i32) {
println!("This is: {}", reference);
}
fn main() {
// Create a boxed and a stacked variable
let boxed = Box::new(5_i32);
let stacked = 6_i32;
// Borrow the contents of the box. Ownership is not taken,
// so the contents can be borrowed again.
borrow(&boxed);
borrow(&stacked);
{
// Take a reference to the data contained inside the box
let _ref_to_boxed: &i32 = &boxed;
// Error!
// Can't destroy `boxed` while the inner value is borrowed later in scope.
take_ownership(boxed);
// Attempt to borrow `_ref_to_boxed` after inner value is destroyed
borrow(_ref_to_boxed);
// `_ref_to_boxed` goes out of scope and is no longer borrowed.
}
// `boxed` can now give up ownership to `take_ownership` method and be destroyed
take_ownership(boxed);
}
Sqe
- 在Enum std::sync::atomic::Ordering中,SeqCst保证不指令重排;acquire意为:任何的变量读都不能重排序为在它之前发生;release意为:任何的变量写都不能重排序为在它之前发生;AcqRel则同时有acquire和release的功能。