简介: 明天的故事配角,是一个被称为Flexible Launch Control的SGX平台个性。

前言

自从Intel内核开发人员Jarkko Sakkinen于2017年9月2日在intel-sgx-kernel-dev@lists.01.org邮件列表上收回v1版的SGX in-tree驱动以来,工夫曾经过来了3年多了。这期间这个驱动前前后后共批改了41个版本,终于在2020年11月13日,v41版本的补丁合入了5.11-rc1内核。Jarkko松了一口气,工作实现啦!不过,为什么合并一个一般的驱动模块会这么难?

事实上,因为SGX所代表的新的秘密计算畛域的特殊性,围绕着它的争议和探讨就从未进行过。甚至在最终的v41补丁中,也没能看到大佬们整齐划一的LGTM(社区黑话,Looks Good To Me的缩写,示意本人认可这个补丁),它仍旧存在一些问题,同时还有人在一直提出批改倡议。这不禁让人联想到另一个x86处理器个性FSGSBASE合入upstream时的命运多舛:后者的合入前后花了5年工夫,甚至最初都不是Intel的人合入的(当然也不是AMD的人合入的,大家能够猜猜是谁)。

明天的故事配角,是一个被称为Flexible Launch Control(简称FLC)的SGX平台个性。对这个个性的争议,最终导致SGX in-tree驱动无奈反对不具备FLC个性或敞开了FLC个性的所有SGX零碎。大白话是啥意思呢?意思就是一批较早的反对Intel SGX的机器用Linux内核自带的官网驱动是无奈加载和应用SGX的......纳尼!这个驱动居然不向下兼容!哎,当初让咱们先对FLC技术背景进行一个简略的介绍,而后再对其被社区摈弃的故事简略做个复盘,最初再给出咱们的思考,以及咱们的解决方案。

FLC的技术背景

情谊揭示:想听故事不想理解技术细节的同学请间接跳到下一节。

在执行SGX EINIT指令初始化enclave的时候,被初始化的enclave必须通过Launch Control机制的查看,因而Launch Control是一种用于管制enclave是否启动的安全检查机制。

被初始化的enclave分为两类:Launch Enclave和一般enclave。Launch Enclave与一般的enclave的不同之处在于其SECS.ATTRIBUTES.EINITTOKEN_KEY == 1,即具备通过执行SGX EGETKEY指令派生出einit token key的权限。Einit token实质上是一个带有CMAC签名的token,其中的CMAC是Launch Enclave用einit token key生成的,意在对einit token自身提供完整性爱护;在执行EINIT初始化一般enclave的时候,从Launch Enclave处返回的einit token须要作为输出参数的一部分,而后EINIT指令的微码会将einit token作为派生出einit token key的输出因子,最初用派生出的einit token key来验证输出的einit token中的CMAC,以确保einit token从生成到传给EINIT的过程中没有被篡改。

下面的流程中提到的einit token完整性检查实用于所有的一般enclave,而对于Launch Enclave,再执行EINIT初始化时有非凡解决。上面是在执行EINIT时残缺的Launch Control流程:

image.gifC05A1907-7AF2-47e3-B8C3-5F743C36AE8F.png

(下面的流程图是对Intel SDM手册中对于EINIT指令在微架构层的执行流程进行的总结;其中Launch Enclave验证两次IA32_SGXLEPUBKEYHASH的逻辑应该是冗余的,但咱们还是依照原始流程的逻辑把它给残缺地画进去了)

能够简略地将上述流程总结为以下两点规定:

1.只有在初始化enclave时能提供非法的einit token, 就能通过Launch Control的查看。

  1. 如果在初始化enclave时没有提供非法的einit token, 则enclave的MRSIGNER必须与IA32_SGXLEPUBKEYHASH的值统一。

此外,还能够从第二点规定推导出实用于Launch Enclave的非凡规定:

  1. Launch Enclave必须可能通过IA32_SGXLEPUBKEYHASH的校验能力被初始化。
  2. 通过EINIT初始化Launch Enclave的时候,能够不提供einit token。

在处理器复位时,IA32_SGXLEPUBKEYHASH的默认值是Intel的MRSIGNER。如果处理器不反对FLC,任何一般的enclave在初始化时,必须持有非法的einit token,而负责颁发einit token的Launch Enclave则能够制订本人的策略来决定是否给一个一般enclave颁发einit token。 具体到Intel在不反对FLC的SGX1上施行的策略则是:用户运行的enclave必须是由Intel受权的密钥签过的,这样能力失去Intel开发的Launch Enclave的受权,并取得einit token,否则用户无奈运行本人开发的一般enclave(严格讲是无奈运行产品级的一般enclave,debug级的一般enclave还是能够运行的)。

这就是利用Launch Control达成的管制成果:谁把握Launch Enclave,谁管制一般enclave的运行受权。

相同,如果处理器反对FLC且BIOS没有锁死IA32_SGXLEPUBKEYHASH,IA32_SGXLEPUBKEYHASH MSRs对系统软件不仅可见而且可写,配合SGX in-tree驱动就能够实现如下性能:每当加载任意enclave时,都无条件将其MRSIGNER写入到IA32_SGXLEPUBKEYHASH中,从而绕过Launch Control机制,也就是说所有一般enclave都能像Launch Enclave那样无需提供非法的einit token。FLC中的F,指的就是IA32_SGXLEPUBKEYHASH寄存器在某些状况下是可写的。 至于要不要利用它绕过Launch Control机制,则是具体的实现策略问题,而SGX in-tree驱动就恰好采取了绕过Launch Control的策略,起因是Linux kernel不心愿提供对配置锁定的零碎提供反对。

至于这种策略是否正确,咱们暂先不探讨。先劳动下,听听故事。

故事脉络

故事的导火索出自v22 SGX in-tree驱动。这里作者Jarkko定义了处理器是否反对FLC的bit,并对FLC的作用进行了阐明。注意作者的最初一段话:

“内核不会对某种被锁定的配置提供反对,因为这夺走了内核(对启动enclave)的启动控制权。”联合后面对于FLC的技术原理解说,这里的锁定指的就是如果BIOS锁死了IA32_SGXLEPUBKEYHASH,那么一般enclave的运行形式就要被Intel的Launch Enclave的受权策略所管制。这段形容引起了Reviewer Borislav的警惕,并给出了硬核回复:如果FEATURE_CONTROL_SGX_LE_WR位决定了IA32_SGXLEPUBKEYHASH是否被锁死,那么谁管制的FEATURE_CONTROL_SGX_LE_WR位?内核可能管制吗?我可不想让该死的BIOS去管制,真出点啥问题咱们本人能搞定,用不着看OEM的脸色。

这时候另一个作者Sean站进去答复了reviewer的问题:

“是的,就是BIOS管制着FEATURE_CONTROL_SGX_LE_WR位。这个咱们都想好了,FEATURE_CONTROL_SGX_LE_WR位如果为0,那咱们就把SGX性能齐全禁止掉。这个想法在第四个补丁里有具体实现。”到目前看起来还是失常的社区review流程,大家也比拟温和,直到reviewer看过了第四个补丁的内容。首先咱们本人先看下第4个补丁到底干了什么:

+static void __maybe_unused detect_sgx(struct cpuinfo_x86 *c)+{+  unsigned long long fc;++  rdmsrl(MSR_IA32_FEATURE_CONTROL, fc);...+  if (!(fc & FEATURE_CONTROL_SGX_ENABLE)) {+    pr_err_once("sgx: SGX is not enabled in IA32_FEATURE_CONTROL MSR\n");+    goto err_unsupported;+  }++  if (!cpu_has(c, X86_FEATURE_SGX1)) {+    pr_err_once("sgx: SGX1 instruction set is not supported\n");+    goto err_unsupported;+  }++  if (!(fc & FEATURE_CONTROL_SGX_LE_WR)) {+    pr_info_once("sgx: The launch control MSRs are not writable\n");+    goto err_msrs_rdonly;+  }++  return;++err_unsupported:+  setup_clear_cpu_cap(X86_FEATURE_SGX);+  setup_clear_cpu_cap(X86_FEATURE_SGX1);+  setup_clear_cpu_cap(X86_FEATURE_SGX2);++err_msrs_rdonly:+  setup_clear_cpu_cap(X86_FEATURE_SGX_LC);+}

一句话形容这段代码的含意就是:如果FEATURE_CONTROL_SGX_LE_WR位为0(一种状况是BIOS锁死了IA32_SGXLEPUBKEYHASH,另一种状况是平台不反对FLC)的话,意味着MSR_IA32_SGXLEPUBKEYHASH{0, 1, 2, 3}这四个MSR寄存器对内核来说就是只读或者不可见的,那么内核也就无法控制一般enclave的启动,这是Linux upstream不想看到的状况。对此,代码会简略地分明掉FLC的cpu feature flag,但会保留其余SGX相干的cpu feature flag。

Borislav此刻的情绪必定是:(⇀‸↼‶) 这和你后面说的不一样啊?这哪里是你所谓的“把SGX性能齐全禁止掉”了??你明明只是革除了FLC cpu feature flag,没有齐全禁止SGX性能啊!!!难道是我的了解有问题吗?

作者Sean应该是晓得本人说错话了,没有回复这个问题;而Borislav此刻只想要一个货色:MSR_IA32_SGXLEPUBKEYHASH{0, 1, 2, 3}这四个MSR寄存器对内核来说必须可写!

而后作者Sean开始摆事实讲道理:还有好多不反对FLC或者禁用FLC(即BIOS可能非故意地锁死了IA32_SGXLEPUBKEYHASH)的SGX的平台啊!

Sean说这句话的时候是在2019年9月25日,其实现在来看这句话仍旧正确。

Borislav没有被压服,并且开始谈起BIOS是如许的“蹩脚”,并屡次提到不想提供对带有配置锁定的零碎的反对:

Linux以及开源社区一贯恶感各种配置锁定和DRM。笔者印象中早些年Win7刚进去时强行默认开UEFI Secure Boot且BIOS setup中不提供敞开选项导致无奈装置Linux,这让开源社区十分不爽,通过Linux Foundation、Intel和微软的交涉,才最终有了明天的shim bootloader。当然,终端用户不必本人去找微软签名bootloader,这是每个Linux发行版本本人找微软签名的事件了,而且这个默契也曾经继续很久了。

最初作者Sean认了,并且说咱们原本就是那么想的:

一口老血喷了进去!合着后面的迷之发言逗咱们玩呢???显然作者Sean的逻辑呈现了矛盾,他说他的本意其实是这样的:

“即便MSR_IA32_SGXLEPUBKEYHASH不可写,但咱们仍旧保留其余SGX cpu feature flag,好让用户明确到底是我的零碎不反对SGX硬件能力,还是因为短少FLC性能导致无奈运行一般的enclave,当初看起来可能是我想多了。” 对于Sean的这个论断,须要这样了解:尽管在不反对FLC或禁用FLC的平台上仍旧可能运,debug级的一般enclave,然而debug级的enclave是可能被sgx-gdb通过非凡的enclave debug指令拜访到enclave中的敏感数据的,因而debug级的enclave不适宜于生产环境;要运行不能被debug的产品级enclave,就必须要恪守Intel的Launch Enclave的受权策略,但这须要施行一些对常人来说不具可施行性的操作,这与个别用户想简略地就能运行一般enclave的需要的确相悖,因而大多数状况下,不反对FLC或禁用FLC就等价于用户无奈运行一般enclave,而cpu feature flag能够反映出起因。

最终,从v25开始,如果处理器不反对FLC,所有SGX个性都将无奈应用:

+update_sgx:+  if (!cpu_has(c, X86_FEATURE_SGX) || !cpu_has(c, X86_FEATURE_SGX_LC)) {+    clear_sgx_caps();+  } else if (!(msr & FEAT_CTL_SGX_ENABLED) ||+       !(msr & FEAT_CTL_SGX_LC_ENABLED)) {+    if (IS_ENABLED(CONFIG_INTEL_SGX))+      pr_err_once("SGX disabled by BIOS\n");+    clear_sgx_caps();+  }

不过这个做法真的对么?难道不反对FLC或禁用FLC的平台就不应该失去SGX in-tree驱动的反对吗?

思考

答复这个问题前,咱们先看下目前Intel对SGX驱动的反对状况。

除了SGX in-tree驱动,Intel在开源社区还提供了SGX Legacy驱动。这个SGX驱动是因为漫长的review流程而逐步昌盛起来的副产物,目标是在规范内核尚不反对SGX的状况下满足用户对SGX平台的撑持需要。这个SGX Legacy驱动反对没有FLC的平台,也是目前反对SGX1平台的惟一抉择。能够预感,在SGX in-tree驱动合入到upstream后,这个驱动会逐渐退出历史的舞台,那么问题也来了。

首先,即便具备大量EPC内存的SGX2机器曾经上线了(能够参考阿里云的SGX2邀测申请链接:https://pages.aliyun.com/aliy... ),然而仍有一批存量SGX1平台正在退役;此外,采纳Intel client platform的CPU很多都反对SGX但不反对FLC,难道这些平台的用户未来就只能用着短少新个性反对的SGX Legacy驱动吗?

其次,有些人肯定曾经提前思考到须要将现有业务利用拿到基于SGX in-tree驱动的环境里跑一跑,测一测SGX in-tree驱动自身的性能和稳定性,因而在不足SGX2平台的状况下,也须要SGX in-tree驱动可能反对SGX1平台。

最初,不反对FLC和禁用FLC其实是两码事。被社区真正诟病的是老的SGX1平台不反对FLC,进而只能被逼施行不具可施行性的Launch Enclave运行受权;到了反对FLC平台个性的时代,即使禁用了FLC,但只有锁定的内容是用户可控的,或者是施行一种更为宽松的Launch Enclave运行受权,那么这种配置锁定也是无益的。 就拿云租户应用裸金属服务器的场景为例:即便CSP在BIOS里禁用了FLC,只有CSP在本人定制的Launch Enclave中确保非法的云租户能失常运行该租户本人签的enclave就能够了,而这其实这反倒是为租户多减少了一重爱护。如果像当初SGX in-tree驱动的这种实现形式,包含胜利入侵到零碎的攻击者都能够任意运行本人编写的歹意Enclave了。

那咱们该怎么办呢?

解决方案

咱们的观点还是想大家之所想,急大家之所急。依据目前的理论状况,Inclavare Containers开源项目组( https://github.com/alibaba/in... )编写了几个补丁,目标就是让不反对FLC或禁用FLC的零碎可能运行SGX in-tree驱动。补丁的应用和验证办法详见:https://github.com/alibaba/in...

目前咱们曾经在SGX1机型中胜利部署了这种运行形式,并理论利用于Inclavare Containers开源我的项目的CI/CD测试中。

此外,Inclavare Containers开源我的项目会研发一个反对用户自定义策略的Launch Enclave;目标是晋升用户管制的平台的安全性,即只容许运行用户预期的一般enclave,杜绝攻击者在用户平台上运行歹意enclave的状况呈现。

最初有几个要害概念的关系要再次廓清,重点揭示下大家:

  1. 是否反对FLC和CPU是否反对SGX1/2没有关系;SGX1/2是处理器SGX架构的指令集个性;FLC是平台个性。
  2. 之所以强调SGX1和FLC的关系,是因为FLC是在SGX1和SGX2之间呈现的平台个性,因而很多SGX1平台都短少FLC个性。
  3. 即便是在反对FLC的平台,只有在BIOS中禁用了FLC(不论是出于平安起因禁用,还是BIOS不反对FLC,或是被CSP锁定),都会像不反对FLC的SGX1平台那样遇到雷同的问题。兴许到了咱们能把这个问题像下面提到的那样做到真正的精细化解决,即可能明确辨别出“平台控制权民主化”和“非预期的平台配置锁定”并为前者提供切实的平安解决方案的时候,咱们会再给社区发送一组patch,以容许SGX in-tree驱动反对那些用户明确心愿禁用FLC的平台。(完)

原文链接
本文为阿里云原创内容,未经容许不得转载。