blob: 656e3c0b48f528e7f0412fb79703d50a4b5c701a [file] [log] [blame]
(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{334:function(e,a,t){e.exports=t.p+"assets/img/2021-08-13-overview-of-teaclave-sgx-sdk-cn.24012888.png"},335:function(e,a,t){e.exports=t.p+"assets/img/2021-08-13-sgx-enable.4a8676dc.png"},384:function(e,a,t){"use strict";t.r(a);var s=t(11),n=Object(s.a)({},(function(){var e=this,a=e.$createElement,s=e._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("nav",{staticClass:"table-of-contents"},[s("ol",[s("li",[s("a",{attrs:{href:"#teaclave-sgx-sdk%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E7%AE%80%E4%BB%8B%E4%BB%A5%E5%8F%8A%E6%90%AD%E5%BB%BA"}},[e._v(" Teaclave SGX SDK应用开发环境简介以及搭建")]),s("ol",[s("li",[s("a",{attrs:{href:"#%E5%87%86%E5%A4%87%E6%9D%A1%E4%BB%B6"}},[e._v(" 准备条件")])]),s("li",[s("a",{attrs:{href:"#%E5%9F%BA%E4%BA%8E-docker-%E9%85%8D%E7%BD%AE-teaclave-sgx-sdk-%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83"}},[e._v(" 基于 docker 配置 Teaclave SGX SDK 开发环境")])])])]),s("li",[s("a",{attrs:{href:"#teaclave-sgx-sdk-%E7%A4%BA%E4%BE%8B-helloworld-%E5%89%96%E6%9E%90"}},[e._v(" Teaclave SGX SDK 示例 helloworld 剖析")]),s("ol",[s("li",[s("a",{attrs:{href:"#helloworld-%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84"}},[e._v(" helloworld 目录结构")])]),s("li",[s("a",{attrs:{href:"#%E9%87%8D%E8%A6%81%E4%BB%A3%E7%A0%81%E6%96%87%E4%BB%B6%E8%A7%A3%E6%9E%90"}},[e._v(" 重要代码文件解析")])]),s("li",[s("a",{attrs:{href:"#%E7%BC%96%E8%AF%91%E5%90%8E%E7%9A%84%E4%BB%A3%E7%A0%81%E7%9B%AE%E5%BD%95"}},[e._v(" 编译后的代码目录")])])])]),s("li",[s("a",{attrs:{href:"#%E5%BC%80%E5%8F%91%E8%80%85%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91%E8%87%AA%E5%B7%B1%E7%9A%84-rust-sgx-application"}},[e._v(" 开发者如何开发自己的 Rust SGX Application")]),s("ol",[s("li",[s("a",{attrs:{href:"#%E6%B7%BB%E5%8A%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E5%87%BD%E6%95%B0"}},[e._v(" 添加自定义的函数")])]),s("li",[s("a",{attrs:{href:"#%E8%B0%83%E7%94%A8-teaclave-sgx-sdk-%E6%8F%90%E4%BE%9B%E7%9A%84-crate"}},[e._v(" 调用 Teaclave SGX SDK 提供的 crate")])])])]),s("li",[s("a",{attrs:{href:"#%E6%80%BB%E7%BB%93"}},[e._v(" 总结")])]),s("li",[s("a",{attrs:{href:"#%E5%BB%B6%E4%BC%B8%E9%98%85%E8%AF%BB"}},[e._v(" 延伸阅读")])])])]),s("h2",{attrs:{id:"teaclave-sgx-sdk应用开发环境简介以及搭建"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#teaclave-sgx-sdk应用开发环境简介以及搭建"}},[e._v("#")]),e._v(" Teaclave SGX SDK应用开发环境简介以及搭建")]),e._v(" "),s("p",[e._v("Intel SGX (Software Guard Extension, 软件防护扩展) 因为其较为出色的性能和安全性,是目前最为学术界和工业界关注的 TEE (Trusted Execution Environment, 可信执行环境)。Intel SGX 在内存中划分了名为 enclave(飞地)的隔离区域,用来存放敏感数据和代码。通过提供该隔离的可信执行环境,enclave 在操作系统、BIOS 和虚拟机监控器等系统软件均不可信的情况下,仍然对 enclave 内部的代码和数据提供保护,保障用户的关键数据和代码的机密性和完整性。")]),e._v(" "),s("p",[e._v("但如果 Intel SGX 程序仍然使用 C/C++ 这类内存不安全的语言开发的话,就会和传统软件一样面临着内存破坏漏洞的问题。对于 enclave 来说,受到的危害会更为严重,因为 enclave 中保存的多是机密数据和代码。Teaclave SGX 的主要目标就是通过使用高效的内存安全语言 —— Rust 来支持 enclave 应用程序的开发,从而在保证 Intel SGX enclave 内存安全的同时不会带来显著的性能开销。")]),e._v(" "),s("p",[e._v("Teaclave SGX SDK 内部结构分为三层:")]),e._v(" "),s("ul",[s("li",[e._v("最底层是使用 C/C++ 和汇编实现的 Intel SGX SDK。")]),e._v(" "),s("li",[e._v("中间层是 Rust 对 C/C++ 的 FFI (Foreign function Interfaces, 外部函数接口)。")]),e._v(" "),s("li",[e._v("最高层是 Teaclave SGX SDK。")])]),e._v(" "),s("p",[s("img",{attrs:{src:t(334),alt:"Teaclave SGX SDK 概要图"}})]),e._v(" "),s("p",[e._v("Teaclave SGX SDK 应用程序开发者在进行开发时就只需要基于最上层的 Teaclave SGX SDK 来进行开发,底层的实现对于开发者来说是透明的。本文将从开发者的角度介绍基于 Teaclave SGX SDK 开发自己的应用程序的过程。")]),e._v(" "),s("h3",{attrs:{id:"准备条件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#准备条件"}},[e._v("#")]),e._v(" 准备条件")]),e._v(" "),s("ul",[s("li",[e._v("Ubuntu16.04 或者 18.04 或者 20.04 (Teaclave SGX SDK v1.1.3 中增加了对 Ubuntu 20.04 的支持)")]),e._v(" "),s("li",[e._v("docker 环境")])]),e._v(" "),s("p",[s("em",[e._v("本文基于 Teaclave SGX SDK v1.1.3 提交哈希值:d107bd0718f723221750a4f2973451b386cbf9d2")])]),e._v(" "),s("h3",{attrs:{id:"基于-docker-配置-teaclave-sgx-sdk-开发环境"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#基于-docker-配置-teaclave-sgx-sdk-开发环境"}},[e._v("#")]),e._v(" 基于 docker 配置 Teaclave SGX SDK 开发环境")]),e._v(" "),s("p",[e._v("首先需要用户机器 CPU 支持 Intel SGX 并且在 BIOS 上开启了 Intel SGX 支持。用户可以通过 "),s("a",{attrs:{href:"https://github.com/ayeks/SGX-hardware",rel:"noopener noreferrer"}},[e._v("SGX-hardware项目")]),e._v(" 或者在 "),s("a",{attrs:{href:"https://www.intel.com/content/www/us/en/products/details/processors.html",rel:"noopener noreferrer"}},[e._v("Intel 官网")]),e._v(" 中搜索自己的 CPU 型号查看是否支持 Intel SGX。下图以 Intel Core i7-7700K 处理器为例,如下图所示,该机型支持 SGX。")]),e._v(" "),s("p",[s("img",{attrs:{src:t(335),alt:"sgx-enable.png"}})]),e._v(" "),s("p",[e._v("当确定 CPU 支持 Intel SGX 之后,还需要开启 BIOS 中的 SGX 选项。CPU 上的 SGX 选项可能有 "),s("code",[e._v("enabled")]),e._v(" 或者 "),s("code",[e._v("software controlled")]),e._v("。具有 "),s("code",[e._v("enabled")]),e._v(" 选项的主机直接在 BIOS 上选择 "),s("code",[e._v("enabled")]),e._v(" 即可,而"),s("code",[e._v("software controlled")]),e._v(" 表示 SGX 的开启需要由软件触发,还需通过 Intel 官方提供的 "),s("a",{attrs:{href:"https://github.com/intel/sgx-software-enable",rel:"noopener noreferrer"}},[e._v("sgx-software-enable")]),e._v(" 开启。下载好 "),s("code",[e._v("sgx-software-enable")]),e._v(" 之后,运行 "),s("code",[e._v("Makefile")]),e._v(" 编译生成可执行代码 "),s("code",[e._v("sgx_enable")]),e._v(" ,执行 "),s("code",[e._v("sudo ./sgx_enable")]),e._v(" 顺利运行后重启主机,即可顺利开启 Intel SGX。")]),e._v(" "),s("p",[e._v("硬件条件准备完毕之后,还需要安装 "),s("a",{attrs:{href:"https://download.01.org/intel-sgx/sgx-linux/2.10/distro/ubuntu16.04-server/sgx_linux_x64_driver_2.6.0_602374c.bin",rel:"noopener noreferrer"}},[e._v("Linux SGX 驱动")]),e._v("(本实验环境的操作系统版本为 ubuntu16.04 ,安装时需要根据自己的操作系统版本号在 "),s("a",{attrs:{href:"https://download.01.org/intel-sgx/",rel:"noopener noreferrer"}},[e._v("官网")]),e._v(" 下载对应的 Intel SGX 驱动) ,安装完毕之后需要确认 "),s("code",[e._v("/dev/isgx")]),e._v(" 的存在。")]),e._v(" "),s("p",[e._v("下载 Teaclave SGX SDK 以及支持编译 SGX 设备的 docker image。")]),e._v(" "),s("p",[s("code",[e._v("$ https://github.com/apache/incubator-teaclave-sgx-sdk")])]),e._v(" "),s("p",[s("code",[e._v("$ docker pull baiduxlab/sgx-rust")])]),e._v(" "),s("p",[e._v("启动一个 docker,并且把 Teaclave SGX SDK 项目目录映射到 docker 中。")]),e._v(" "),s("p",[s("code",[e._v("$ docker run -v /your/absolute/path/to/incubator-teaclave-sgx-sdk:/root/sgx -ti --device /dev/isgx baiduxlab/sgx-rust")])]),e._v(" "),s("p",[e._v("在运行的 docker container 中启动 aesm 服务,"),s("strong",[e._v("White list update request successful for Version")]),e._v(" 语句意味着启动成功。")]),e._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("root@docker:/# LD_LIBRARY_PATH=/opt/intel/sgx-aesm-service/aesm/ /opt/intel/sgx-aesm-service/aesm/aesm_service &\naesm_service[17]: [ADMIN]White List update requested\naesm_service[17]: Failed to load QE3: 0x4004\naesm_service[17]: The server sock is 0x56096ab991c0\naesm_service[17]: [ADMIN]White list update request successful for Version: 103\n")])])]),s("p",[e._v("执行 Teaclave SGX SDK 中的简单实例 helloworld ,检查是否正常运行。")]),e._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("root@docker:~# cd sgx/samplecode/helloworld/\nroot@docker:~/sgx/samplecode/helloworld# make\nroot@docker:~/sgx/samplecode/helloworld# cd bin/\nroot@docker:~/sgx/samplecode/helloworld/bin# ./app\n[+] global_eid: 2\nThis is normal world string passed into enclave!\nThis is a Rust string!\n[+] say_something success ...\n")])])]),s("p",[e._v("至此,我们已经成功在自己的机器上跑起来了 Teaclave SGX SDK 的 helloworld 示例啦!")]),e._v(" "),s("h2",{attrs:{id:"teaclave-sgx-sdk-示例-helloworld-剖析"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#teaclave-sgx-sdk-示例-helloworld-剖析"}},[e._v("#")]),e._v(" Teaclave SGX SDK 示例 helloworld 剖析")]),e._v(" "),s("p",[e._v("接下来,我们通过阅读 helloworld 这个简单的例子来理解 Teaclave SGX SDK 应用程序的组织结构和运行方式。")]),e._v(" "),s("h3",{attrs:{id:"helloworld-目录结构"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#helloworld-目录结构"}},[e._v("#")]),e._v(" helloworld 目录结构")]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("helloworld/ \n├── app \n│   ├── app.c \n│   └── app.h \n├── bin \n│   └── readme.txt \n├── enclave \n│   ├── Cargo.toml \n│   ├── Enclave.config.xml \n│   ├── Enclave.edl \n│   ├── Enclave.lds \n│   ├── Enclave_private.pem \n│   ├── Makefile \n│   ├── src \n│   │   └── lib.rs \n│   ├── x86_64-unknown-linux-sgx.json \n│   └── Xargo.toml \n├── lib \n│   └── readme.txt \n└── Makefile \n")])])]),s("p",[e._v("helloworld 的目录结构和 Intel SGX 的 "),s("a",{attrs:{href:"https://github.com/intel/linux-sgx/blob/HEAD/SampleCode/SampleEnclave",rel:"noopener noreferrer"}},[e._v("SampleEnclave")]),e._v(" 目录结构非常类似。")]),e._v(" "),s("ul",[s("li",[e._v("app 目录中存放的是不可信部分代码,包括 "),s("code",[e._v("main")]),e._v(" 函数以及 "),s("code",[e._v("OCALL")]),e._v(" 函数具体逻辑实现。")]),e._v(" "),s("li",[e._v("enclave 目录中存放的是可信部分代码,主要是 "),s("code",[e._v("ECALL")]),e._v(" 函数具体逻辑实现。\n"),s("ul",[s("li",[e._v("不同于 SGX ,应用安全区的代码实现位于 "),s("strong",[s("code",[e._v("src/lib.rs")])]),e._v(", 该文件是整个 "),s("code",[e._v("helloworld")]),e._v(" 文件夹中唯一使用 Rust 编写的文件,程序员可以在该文件中增加需要的功能。")]),e._v(" "),s("li",[e._v("另外,enclave 文件夹下多了 "),s("code",[e._v("Cargo.toml")]),e._v(", "),s("code",[e._v("src/lib.rs")]),e._v(", "),s("code",[e._v("x86_64-unknown-linux-sgx.json")]),e._v(", "),s("code",[e._v("Xargo.toml")]),e._v(":\n"),s("ul",[s("li",[s("strong",[s("code",[e._v("Cargo.toml")])]),e._v(": 项目清单文件,包括项目名称、项目版本以及依赖项等。")]),e._v(" "),s("li",[s("strong",[s("code",[e._v("x86_64-unknown-linux-sgx.json")])]),e._v(" 和 "),s("strong",[s("code",[e._v("Xargo.toml")])]),e._v(" 描述了用于项目交叉编译的信息。")])])])])])]),e._v(" "),s("h3",{attrs:{id:"重要代码文件解析"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#重要代码文件解析"}},[e._v("#")]),e._v(" 重要代码文件解析")]),e._v(" "),s("ul",[s("li",[s("strong",[s("code",[e._v("Enclave.edl")])]),e._v(" "),s("br"),e._v("\n该文件规定了 Enclave 边界 "),s("code",[e._v("ECALL/OCALL")]),e._v(" 的定义。")])]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('enclave {\n from "sgx_tstd.edl" import *;\n from "sgx_stdio.edl" import *;\n from "sgx_backtrace.edl" import *;\n from "sgx_tstdc.edl" import *;\n\n trusted {\n /* define ECALLs here. */\n public sgx_status_t say_something([in, size=len] const uint8_t* some_string, size_t len);\n };\n\n untrusted {\n\n };\n};\n')])])]),s("p",[s("code",[e._v("trusted {...}")]),e._v(" 中声明 "),s("code",[e._v("ECALL")]),e._v(" 函数, "),s("code",[e._v("untrusted {...}")]),e._v(" 中声明 "),s("code",[e._v("OCALL")]),e._v(" 函数。本例中声明了一个 "),s("code",[e._v("ECALL")]),e._v(" 函数 "),s("code",[e._v("say_something")]),e._v(",该函数的具体实现在 "),s("code",[e._v("src/lib.rs")]),e._v(" 中,它的参数包括 "),s("code",[e._v("uint8_t *")]),e._v(" 类型的指针和长度参数 "),s("code",[e._v("len")]),e._v("。")]),e._v(" "),s("ul",[s("li",[s("strong",[s("code",[e._v("app/app.c")])])])]),e._v(" "),s("p",[e._v("在 "),s("code",[e._v("app/app.c")]),e._v(" 的 "),s("code",[e._v("main")]),e._v(" 函数中有一个完整的调用 "),s("code",[e._v("ECALL")]),e._v(" 的例子。")]),e._v(" "),s("div",{staticClass:"language-c extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("sgx_ret = say_something(global_eid,\n &enclave_ret,\n (const uint8_t *) str,\n len);\n")])])]),s("p",[e._v("这里的 "),s("code",[e._v("say_something")]),e._v(" 似乎和 "),s("code",[e._v("Enclave.edl")]),e._v(" 中的声明不太一样,ECALL传递参数时多了两个隐参数:"),s("code",[e._v("enclave_eid")]),e._v(" 和 "),s("code",[e._v("say_something")]),e._v(" 的返回值 "),s("code",[e._v("&enclave_ret")]),e._v("。而 "),s("code",[e._v("sgx_ret")]),e._v(" 表示的是 ECALL 执行是否成功,是 SGX 的返回值。")]),e._v(" "),s("ul",[s("li",[s("strong",[s("code",[e._v("enclave/")]),e._v("文件夹部分")])])]),e._v(" "),s("p",[s("code",[e._v("enclave/Cargo.toml")]),e._v(" 中声明了这是一个 "),s("code",[e._v("staticlib")]),e._v(",表明 Enclave 在最后会被编译成一个 "),s("code",[e._v(".a")]),e._v(" 文件,该文件会和 Intel 提供的 "),s("code",[e._v("sgx_tstdc.a")]),e._v(" 等文件链接形成 "),s("code",[e._v("enclave.so")]),e._v(",再经由 "),s("code",[e._v("sgx_sign")]),e._v(" 工具配合 "),s("code",[e._v("Enclave.config.xml")]),e._v(" 配置文件、"),s("code",[e._v("Enclave_private.pem")]),e._v(" 签名私钥做签名并计算 "),s("code",[e._v("measurement")]),e._v(" ,最后生成 "),s("code",[e._v("enclave.signed.so")]),e._v(",这是 Enclave 的完全体。")]),e._v(" "),s("ul",[s("li",[s("strong",[s("code",[e._v("enclave/src/lib.rs")])])])]),e._v(" "),s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('pub extern "C" fn say_something(some_string: *const u8, some_len: usize) -> sgx_status_t {\n\n let str_slice = unsafe { slice::from_raw_parts(some_string, some_len) };\n let _ = io::stdout().write(str_slice);\n\n // A sample &\'static string\n let rust_raw_string = "This is a ";\n // An array\n let word:[u8;4] = [82, 117, 115, 116];\n // An vector\n let word_vec:Vec<u8> = vec![32, 115, 116, 114, 105, 110, 103, 33];\n\n // Construct a string from &\'static string\n let mut hello_string = String::from(rust_raw_string);\n\n // Iterate on word array\n for c in word.iter() {\n hello_string.push(*c as char);\n }\n\n // Rust style convertion\n hello_string += String::from_utf8(word_vec).expect("Invalid UTF-8")\n .as_str();\n\n // Ocall to normal world for output\n println!("{}", &hello_string);\n\n sgx_status_t::SGX_SUCCESS\n}\n')])])]),s("p",[e._v("该函数实现了一个简单的将 "),s("code",[e._v("&[u8]")]),e._v(" 数组转化为字符串输出的函数,注意在函数的最后调用的 "),s("code",[e._v("println!")]),e._v(" 函数是一个 "),s("code",[e._v("OCALL")]),e._v("。 "),s("code",[e._v("println!")]),e._v(" 的具体实现中加入了内置的 "),s("code",[e._v("OCALL")]),e._v(",并定义了内置的 "),s("code",[e._v("edl")]),e._v(" ,import到了 "),s("code",[e._v("Enclave.edl")]),e._v(" 中。")]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('enclave {\n from "sgx_tstd.edl" import *;\n from "sgx_stdio.edl" import *;\n from "sgx_backtrace.edl" import *;\n from "sgx_tstdc.edl" import *;\n')])])]),s("h3",{attrs:{id:"编译后的代码目录"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#编译后的代码目录"}},[e._v("#")]),e._v(" 编译后的代码目录")]),e._v(" "),s("p",[e._v("经过编译之后的代码目录如下所示,这里省略了 "),s("code",[e._v("release")]),e._v(" 文件夹下的内容。")]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("├── app \n│   ├── app.c \n│   ├── app.h \n│   ├── app.o #[generate] \n│   ├── Enclave_u.c #[generate] \n│   ├── Enclave_u.h #[generate] \n│   └── Enclave_u.o #[generate] \n├── bin \n│   ├── app #[generate] \n│   ├── enclave.signed.so #[generate] \n│   └── readme.txt \n├── enclave \n│   ├── Cargo.lock #[generate] \n│   ├── Cargo.toml \n│   ├── Enclave.config.xml \n│   ├── Enclave.edl \n│   ├── Enclave.lds \n│   ├── Enclave_private.pem \n│   ├── enclave.so #[generate] \n│   ├── Enclave_t.c #[generate] \n│   ├── Enclave_t.h #[generate] \n│   ├── Enclave_t.o #[generate] \n│   ├── Makefile \n│   ├── src \n│   │   └── lib.rs \n│   ├── target #[generate] \n│   │   ├── CACHEDIR.TAG #[generate] \n│   │   └── release #[generate] \n│   ├── x86_64-unknown-linux-sgx.json \n│   └── Xargo.toml \n├── lib \n│   ├── libenclave.a #[generate] \n│   ├── libsgx_ustdc.a #[generate] \n│   └── readme.txt \n└── Makefile \n")])])]),s("p",[e._v("helloworld 编译的基本流程类似于 Intel SGX:")]),e._v(" "),s("ul",[s("li",[s("code",[e._v("edger8r")]),e._v(" 将输入的 "),s("code",[e._v("EDL")]),e._v(" 在 "),s("code",[e._v("app/")]),e._v(" 目录下生成不可信代码 "),s("code",[e._v("Enclave_u.h")]),e._v(" 和 "),s("code",[e._v("Enclave_u.c")]),e._v(";")]),e._v(" "),s("li",[e._v("编译不可信部分生成 "),s("code",[e._v("bin/app")]),e._v(";")]),e._v(" "),s("li",[s("code",[e._v("edger8r")]),e._v(" 在 "),s("code",[e._v("enclave/")]),e._v(" 目录下生成可信代码 "),s("code",[e._v("Enclave_t.h")]),e._v(" 和 "),s("code",[e._v("Enclave_t.c")]),e._v(";")]),e._v(" "),s("li",[e._v("编译并签名生成可信动态链接库 "),s("code",[e._v("enclave.signed.so")]),e._v("。")])]),e._v(" "),s("h2",{attrs:{id:"开发者如何开发自己的-rust-sgx-application"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#开发者如何开发自己的-rust-sgx-application"}},[e._v("#")]),e._v(" 开发者如何开发自己的 Rust SGX Application")]),e._v(" "),s("p",[e._v("同样类似于开发 Intel SGX Application,用户可以通过改写 Teaclave SGX SDK 所提供的 "),s("code",[e._v("samplecode")]),e._v(",在这里,我以一个简单的例子抛砖引玉。")]),e._v(" "),s("h3",{attrs:{id:"添加自定义的函数"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#添加自定义的函数"}},[e._v("#")]),e._v(" 添加自定义的函数")]),e._v(" "),s("p",[e._v("假设用户希望在 Teaclave SGX SDK 中实现一个简单的求两个数组的交集的函数,只需要直接在 "),s("code",[e._v("src/lib.rs")]),e._v(" 中添加实现的函数。下面的示例代码 "),s("code",[e._v("intersection")]),e._v(" 函数是希望添加的求交集函数,注意这里求到的交集结果是无重复元素的。传入的两个参数是需要求交集的 "),s("code",[e._v("i32")]),e._v(" 向量,最后返回的是两个向量的交集。其具体的实现是通过一个额外的散列集,记录 "),s("code",[e._v("num1")]),e._v(" 出现的元素,再对 "),s("code",[e._v("num2")]),e._v(" 进行遍历,如果 "),s("code",[e._v("num2")]),e._v(" 出现了散列集中的元素,则将该值 "),s("code",[e._v("push")]),e._v(" 到交集数组中,并将散列表中的对应元素移除。当 "),s("code",[e._v("num2")]),e._v(" 遍历完毕之后,返回交集数组。")]),e._v(" "),s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("pub fn intersection(nums1: Vec<i32>, nums2: Vec<i32>) -> Vec<i32> {\n use std::collections::HashSet;\n let mut set: HashSet<i32> = HashSet::new();\n let mut vec: Vec<i32> = Vec::new();\n\n for i in nums1.iter() {\n set.insert(*i);\n }\n\n for i in nums2.iter() {\n if set.contains(i) {\n vec.push(*i);\n set.remove(i);\n }\n }\n return vec;\n }\n")])])]),s("p",[e._v("考虑一个比较现实的场景,两个用户分别将自己的向量作为参数传入 enclave 中进行计算,这时候数据需要从不可信代码区域复制到可信代码区域。\n首先,需要在 "),s("code",[e._v("Enclave.edl")]),e._v(" 文件中修改 "),s("code",[e._v("say_something")]),e._v(" 函数的定义,输入参数为两个用户的向量指针以及对应的向量大小。")]),e._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("public sgx_status_t say_something([in, size=len1] size_t* num1, size_t len1,\n [in, size=len2] size_t* num2, size_t len2);\n")])])]),s("p",[e._v("接着,在 "),s("code",[e._v("app.c")]),e._v(" 文件中声明需要求交集的数组以及大小并仿照示例调用 "),s("code",[e._v("say_something")]),e._v("。")]),e._v(" "),s("div",{staticClass:"language-c extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v(" size_t nums1[10] = {0,1,2,3,4,5,6,7,8,9};\n size_t nums2[10] = {5,6,7,8,9,10,11,12,13,14};\n size_t len1 = sizeof(nums1);\n size_t len2 = sizeof(nums2);\n\n sgx_ret = say_something(global_eid, \n &enclave_ret,\n nums1,\n len1,\n nums2,\n len2);\n")])])]),s("p",[e._v("回到 "),s("code",[e._v("enclave/src/lib.rs")]),e._v(","),s("code",[e._v("say_something")]),e._v(" 传进来的是两个向量的起始地址以及大小。")]),e._v(" "),s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('pub extern "C" fn say_something(nums1: *mut usize, len1: usize, nums2: *mut usize, len2: usize) -> sgx_status_t \n')])])]),s("p",[e._v("由于数据是从非安全区复制到安全区的,还需要对 "),s("code",[e._v("intersection")]),e._v(" 函数进行部分改写。传进来的参数是数组指针,以指针地址为起始地址,根据大小参数限制迭代范围并获得一个用于循环的序号变量 "),s("code",[e._v("i")]),e._v(",在 "),s("code",[e._v("for")]),e._v(" 循环中使用 "),s("code",[e._v("offset")]),e._v(" 偏移指针,解引用它,读出 "),s("code",[e._v("nums1")]),e._v(" 和 "),s("code",[e._v("nums2")]),e._v(" 的元素值。")]),e._v(" "),s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("pub fn intersection(nums1: *mut usize, len1: usize, nums2: *mut usize, len2: usize) -> Vec<usize> {\n use std::collections::HashSet;\n let mut set: HashSet<usize> = HashSet::new();\n let mut vec: Vec<usize> = Vec::new();\n\n for i in 0..len1/mem::size_of::<usize>() {\n let mut val_nums1 = 0;\n unsafe {\n val_nums1 = *nums1.offset(i as isize);\n }\n set.insert(val_nums1); \n }\n \n for i in 0..len2/mem::size_of::<usize>() {\n let mut val_nums2 = 0;\n unsafe {\n val_nums2 = *nums2.offset(i as isize);\n }\n if set.contains(&val_nums2) {\n vec.push(val_nums2);\n set.remove(&val_nums2);\n }\n }\n return vec;\n}\n")])])]),s("p",[e._v("完整的 "),s("code",[e._v("say_something")]),e._v(" 函数如下所示。")]),e._v(" "),s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('#[no_mangle]\npub extern "C" fn say_something(nums1: *mut usize, len1: usize, nums2: *mut usize, len2: usize) -> sgx_status_t {\n let vec: Vec<usize> = intersection(nums1, len1, nums2, len2); \n println!("intersection set is {:?}", vec);\n sgx_status_t::SGX_SUCCESS\n}\n')])])]),s("p",[e._v("重新编译并运行,得到运行结果:")]),e._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("[+] global_eid: 2\nintersection set is [5, 6, 7, 8, 9]\n[+] say_something success ...\n")])])]),s("p",[e._v("我们基于 Teaclave SGX SDK 的 helloworld 实现了自己的求交集函数。")]),e._v(" "),s("h3",{attrs:{id:"调用-teaclave-sgx-sdk-提供的-crate"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#调用-teaclave-sgx-sdk-提供的-crate"}},[e._v("#")]),e._v(" 调用 Teaclave SGX SDK 提供的 "),s("code",[e._v("crate")])]),e._v(" "),s("p",[e._v("Teaclave SGX SDK 重写了很多 SGX 的库,当我们需要用某个库时,可以先在仓库中查看是否有相应的 "),s("code",[e._v("crate")]),e._v(" 实现以及对应的 "),s("a",{attrs:{href:"https://teaclave.apache.org/api-docs/crates-enclave/",rel:"noopener noreferrer"}},[e._v("doc")]),e._v("。比如当我们希望生成一个随机数时,在 "),s("code",[e._v("C++")]),e._v(" 或者 "),s("code",[e._v("Rust")]),e._v(" 环境下,会想到使用 "),s("code",[e._v("rand")]),e._v(" 库。自然而然地,Teaclave SGX SDK 也用 Rust 重写了 "),s("a",{attrs:{href:"https://github.com/apache/incubator-teaclave-sgx-sdk/tree/master/sgx_rand",rel:"noopener noreferrer"}},[s("code",[e._v("sgx_rand")])]),e._v(" 库。")]),e._v(" "),s("p",[e._v("首先在 "),s("code",[e._v("enclave/Cargo.toml")]),e._v(" 中的 "),s("code",[e._v("[target.'cfg(not(target_env = \"sgx\"))'.dependencies]")]),e._v(" 部分添加 "),s("code",[e._v("sgx_rand")]),e._v(" 库的地址。")]),e._v(" "),s("div",{staticClass:"language-toml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v('[target.\'cfg(not(target_env = "sgx"))\'.dependencies]\nsgx_rand = {git = "https://github.com/apache/teaclave-sgx-sdk.git" }\n')])])]),s("p",[e._v("现在万事俱备,只欠调用。回到 "),s("code",[e._v("lib.rs")]),e._v(" 文件中,链接到 "),s("code",[e._v("sgx_rand")]),e._v(" "),s("code",[e._v("crate")]),e._v(",导入其中的所有项,声明需要使用的模块。")]),e._v(" "),s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("extern crate sgx_rand;\nuse sgx_rand::Rng;\nuse sgx_rand::os::SgxRng;\n")])])]),s("p",[e._v("调用 "),s("code",[e._v("gen_range")]),e._v(" 函数生成 0-10 之间的随机数。")]),e._v(" "),s("div",{staticClass:"language-rust extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[e._v("let random = rng.gen_range(0, 10);\n")])])]),s("p",[e._v("这样就可以在 Teaclave SGX SDK 中的 enclave 中通过调用官方 "),s("code",[e._v("crate")]),e._v(" 随机生成一个随机数。")]),e._v(" "),s("h2",{attrs:{id:"总结"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#总结"}},[e._v("#")]),e._v(" 总结")]),e._v(" "),s("p",[e._v("本文首先介绍了 Teaclave SGX SDK 项目的基本结构,然后以 "),s("code",[e._v("helloworld")]),e._v(" 为例子,介绍了一个简单的 Teaclave SGX SDK 的示例的组织结构和编译过程,最后,以在 "),s("code",[e._v("helloworld")]),e._v(" 中实现 "),s("code",[e._v("intersection")]),e._v(" 函数为例,介绍了如何基于提供的 SampleCode 进行 Teaclave SGX SDK 应用程序的开发。")]),e._v(" "),s("h2",{attrs:{id:"延伸阅读"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#延伸阅读"}},[e._v("#")]),e._v(" 延伸阅读")]),e._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://github.com/dingelish/SGXfail/blob/master/01.md",rel:"noopener noreferrer"}},[e._v("一份主观的 SGX 导读:运行第一个 SGX 程序")])]),e._v(" "),s("li",[s("a",{attrs:{href:"http://teaclave.apache.org",rel:"noopener noreferrer"}},[e._v("Teaclave 官网")])]),e._v(" "),s("li",[s("a",{attrs:{href:"https://dl.acm.org/citation.cfm?id=3354241",rel:"noopener noreferrer"}},[e._v("Teaclave SGX SDK 项目论文:《Towards Memory Safe Enclave Programming with Rust-SGX》")])])])])}),[],!1,null,null,null);a.default=n.exports}}]);