Run unmodified c++ program under the support of graphene-sgx
SGX 是 Intel 近几年来才有的硬件安全特性,可以将应用放在一段加密内存中保护起来。在 SGX 的保护下即使 VMM、Kernel 完全被攻击者挟持,也无法攻击其中的应用。
但是 SGX 有一套自己的编程规范,需要定义 edl
文件,并且需要比较细粒度的对应用进行切分,划分 Trust/Untrust
,这对编程人员来说造成了一定的困难。而 Graphene-SGX
则是 Graphene
的作者和 Intel 的专家合作开发的 libOS,可以在不修改应用的情况下将其运行在 SGX 中。
本文主要是记录我在学习使用 Graphene-SGX
时,第一次成功运行 c++ 的 hello-world 程序的过程。
安装 Graphene
Graphene 是 oscarlab 在 libOS 上的工作研究。在 EuroSys’14 上,该实验室发表了 Graphene 的相关研究成果。在 Intel SGX 出现后,在 ATC’17 上该实验室又和 Intel 合作发表了 Graphene-SGX 的相关研究成果。目前 Graphene 已经在 github 上开源,repo 地址:https://github.com/oscarlab/graphene
Graphene 的官方文档中对于如何使用介绍的内容比较少(也可能是我没读懂),我主要是通过学习其中的 example 摸索出如何使用这个 libOS。
根据文档的提示,首先下载 graphene ,可以通过 git clone https://github.com/oscarlab/graphene.git
的方式。
因为需要 graphene-sgx 的特性,因此 host 机器上必须安装 Intel-sgx-driver
,以记 Intel-sgxsdk
文档在这一块的说明比较详细,有以下几点需要注意:
按照文档的说明,graphene-sgx 需要 Linux kernel 开启
FSGSBASE
特性,因此可能需要编译更新 kernel, 打 patch。clone 下来的 graphene 有一个 submodule 引用了 graphene-sgx-driver , 因此需要运行
git submodule update --init -- Pal/src/host/Linux-SGX/sgx-driver/
。在文档
Quick Start
中的第 3 步中,注释提示,terminal 可能会要求我们输入 path to the Intel SGX driver code,这里其实就是输入sgx.h
头文件的目录所在,可以在Intel sgx driver
的安装目录找到sgx.h
,然后把目录复制过来就好。1
2
3
4cd $GRAPHENE_DIR
make SGX=1
# the console will prompt you for the path to the Intel SGX driver code
# (simply press ENTER if you use the in-kernel Intel SGX driver)
所有都编译成功后,运行 Quick Start
中的 test 也通过了,就说明安装成功了。
使用 Graphene-SGX
接下来就可以自己学习写一个 manifest,来运行我们的 c++ program。
第一次使用,我运行的程序比较简单,是 c++ 版的 hello-world
, 代码如下:
1 |
|
代码写好之后,我们就需要写一个 Makefile 文件,这里主要是需要参考 Examples/
目录下的示例。
Makefile 编写
1 | # Use one of these commands to build the manifest for Bash: |
第 11 行 - 第 26 行基本上是 Examples 中的公共部分,这里主要是定义了一些变量,后面将会使用。
在 SGX enabled 时,需要生成的目标文件一共有:*.manifest
, *.manifest.sgx
, *.sig
, *.token
, *
, pal_loader
*.manifest
: 该文件主要是定义了 graphene 创建隔离环境时需要挂载的文件、挂载的地方、环境变量等等。具体的将会在后一节内容详细介绍。
*.manifest.sgx
: 该文件是在 *.manifest
的基础上对依赖的 trusted_files
进行了签名,以用于加载到 enclave 时进行完整性检查。
*.sig
:
*.token
:
*.pal_loader
:
Manifest 编写
Manifest 中主要定义一些 Graphene 需要挂载的库、挂载的路径,环境变量,SGX 相关配置,SGX 信任的文件等等。
General 部分
1 | loader.argv0_override = "$(ARGV0_OVERRIDE)" |
第 1 行的 loader.argv0_override
是指在运行 ./pal_loader xxx
时,用 xxx
来代替 pal_loader
,也就是运行这个 xxx
程序的意思。
第 11 行的 loader.env.LD_LIBRARY_PATH
指定了程序运行时需要的库加载路径,我猜想,程序运行时应该需要到这些路径上去搜索库。
Mount 部分
1 | # Mounted FSes. The following "chroot" FSes mount a part of the host FS into the |
接下来就是挂载,可以看到,在这次使用中,我挂载了四个目录,之所以这样,是因为 hello-world
这个程序的依赖包含了不同路径的库。
要检查某个程序依赖哪些库,可以通过 ldd xxx
来查看,ldd xxx
的结果应该都需要挂载到 graphene 中。
manifest 中所有的 bash-like variable 都需要在 Makefile 中将其替换成字面量。这个也是 *.manifest
目标文件生成时所需要做的主要工作。可以看到,在这个 Makefile 中,主要是通过 sed -e 's|xx|'xx'|g'
来完成的。
SGX 部分
1 | # Set the virtual memory size of the SGX enclave. For SGX v1, the enclave |
最后,sgx 部分主要需要配置 enclave 的相关参数,这和 SGX 编程模型中的 xml
配置文件的配置基本一致。
sgx.trusted_files.[identifier]
是在程序运行时需要加载的库,可以通过 ldd
来查看,应该是每一个依赖都需要列举在此处。但是由于我是第一次使用,所以也只能凭感觉,如果有错误,希望大家能指出!
编译运行
编写好之后,就可以通过简单的命令直接运行我们的 hello-world
程序。
1 | SGX=1 make |
如果一些顺利,将会输出 Hello, test!
哈哈哈,这是很简单的一个program,但是成功输出的时候,真的很开心!