首页 » 软件优化 » 使用SGX开发一个简单的Hello World程序(代码安全区创建的是胶合)

使用SGX开发一个简单的Hello World程序(代码安全区创建的是胶合)

神尊大人 2024-10-30 00:56:55 0

扫一扫用手机浏览

文章目录 [+]

不管是学习哪种编程语言,入门都喜欢写一个Hello World程序。
这里就看看怎么写一个SGX的Hello World。
对于SGX来说,首先程序在逻辑上要分为安全区和非安全区。

在这个示例程序中,安全区生成一段Hello World字符串,非安全区通过ECALL调用非安全区代码,获得字符串然后打印到界面上。

文件组织如下

使用SGX开发一个简单的Hello World程序(代码安全区创建的是胶合) 软件优化
(图片来自网络侵删)

├── App│ ├── App.cpp # 创建│ ├── App.h # 创建│ ├── App.o│ ├── Enclave_u.c # 胶合代码│ ├── Enclave_u.h # 胶合代码│ └── Enclave_u.o├── Enclave│ ├── Enclave.config.xml # 创建│ ├── Enclave.cpp # 创建│ ├── Enclave.edl # 创建│ ├── Enclave.h # 创建│ ├── Enclave.lds # 创建│ ├── Enclave.o│ ├── Enclave_private.pem # 创建│ ├── Enclave_t.c # 胶合代码│ ├── Enclave_t.h # 胶合代码│ └── Enclave_t.o├── enclave.signed.so├── enclave.so├── hello_world└── Makefile # 创建```

标注创建的文件是需要自己创建的,标注胶合代码是通过sgx_edger8r工具生成的接口代码。
App下包含的是untrusted的代码,Enclave下包含的是trusted的代码。

Makefile从其它示例代码中拷贝过来即可用(结构、文件名不变即可)

EDL

首先要创建一个edl文件(Enclave Description Language),它用于描述trusted和untrusted的接口。
这个Hello world只定义了一个ECALL:

enclave { trusted { public void ecall_hello_from_enclave([out, size=len] char buf, size_t len); };};

edl有自己的描述格式。

有了edl以后,就可以通过sgx_edger8r工具生成接口描述文件,比较像Wrapper代码这种东西。

$ sgx_edger8r --trusted --trusted-dir Enclave/ Enclave/Enclave.edl$ sgx_edger8r --untrusted --untrusted-dir App/ Enclave/Enclave.edlEnclave_t.h

就是一个函数声明。

#ifndef ENCLAVE_T_H__#define ENCLAVE_T_H__ #include <stdint.h>#include <wchar.h>#include <stddef.h>#include "sgx_edger8r.h" / for sgx_ocall etc. /#include <stdlib.h> / for size_t /#define SGX_CAST(type, item) ((type)(item))#ifdef __cplusplusextern "C" {#endifvoid ecall_hello_from_enclave(char buf, size_t len);#ifdef __cplusplus}#endif / __cplusplus /#endifEnclave_t.c

生成了一些框架代码和宏,最终调用的是Enclave.cpp里的我们需要实现的函数。

#include "Enclave_t.h"#include "sgx_trts.h" / for sgx_ocalloc, sgx_is_outside_enclave /#include "sgx_lfence.h" / for sgx_lfence /#include <errno.h>#include <mbusafecrt.h> / for memcpy_s etc /#include <stdlib.h> / for malloc/free etc /#define CHECK_REF_POINTER(ptr, siz) do { \ if (!(ptr) || ! sgx_is_outside_enclave((ptr), (siz))) \ return SGX_ERROR_INVALID_PARAMETER;\} while (0)#define CHECK_UNIQUE_POINTER(ptr, siz) do { \ if ((ptr) && ! sgx_is_outside_enclave((ptr), (siz))) \ return SGX_ERROR_INVALID_PARAMETER;\} while (0)#define CHECK_ENCLAVE_POINTER(ptr, siz) do { \ if ((ptr) && ! sgx_is_within_enclave((ptr), (siz))) \ return SGX_ERROR_INVALID_PARAMETER;\} while (0)#define ADD_ASSIGN_OVERFLOW(a, b) ( \ ((a) += (b)) < (b) \) typedef struct ms_ecall_hello_from_enclave_t { char ms_buf; size_t ms_len;} ms_ecall_hello_from_enclave_t;static sgx_status_t SGX_CDECL sgx_ecall_hello_from_enclave(void pms){ CHECK_REF_POINTER(pms, sizeof(ms_ecall_hello_from_enclave_t)); // // fence after pointer checks // sgx_lfence(); ms_ecall_hello_from_enclave_t ms = SGX_CAST(ms_ecall_hello_from_enclave_t, pms); sgx_status_t status = SGX_SUCCESS; char _tmp_buf = ms->ms_buf; size_t _tmp_len = ms->ms_len; size_t _len_buf = _tmp_len; char _in_buf = NULL; CHECK_UNIQUE_POINTER(_tmp_buf, _len_buf); // // fence after pointer checks // sgx_lfence(); if (_tmp_buf != NULL && _len_buf != 0) { if ( _len_buf % sizeof(_tmp_buf) != 0) { status = SGX_ERROR_INVALID_PARAMETER; goto err; } if ((_in_buf = (char)malloc(_len_buf)) == NULL) { status = SGX_ERROR_OUT_OF_MEMORY; goto err; } memset((void)_in_buf, 0, _len_buf); } ecall_hello_from_enclave(_in_buf, _tmp_len); // 重要 if (_in_buf) { if (memcpy_s(_tmp_buf, _len_buf, _in_buf, _len_buf)) { status = SGX_ERROR_UNEXPECTED; goto err; } }err: if (_in_buf) free(_in_buf); return status;}SGX_EXTERNC const struct { size_t nr_ecall; struct {void ecall_addr; uint8_t is_priv; uint8_t is_switchless;} ecall_table[1];} g_ecall_table = { 1, { {(void)(uintptr_t)sgx_ecall_hello_from_enclave, 0, 0}, }}; SGX_EXTERNC const struct { size_t nr_ocall;} g_dyn_entry_table = { 0,};Enclave.cpp

安全区的实现,把Hello World字符串拷到缓冲区里。

#include "Enclave.h"#include "Enclave_t.h" / print_string /#include <string.h>void ecall_hello_from_enclave(char buf, size_t len){ const char hello = "Hello world"; size_t size = len; if(strlen(hello) < len) { size = strlen(hello) + 1; } memcpy(buf, hello, size - 1); buf[size-1] = '\0';}

Enclave.h是空,就不贴了

Enclave_u.cpp

Enclave_u.cpp封装了安全区的接口调用。

#include "Enclave_u.h"#include <errno.h>typedef struct ms_ecall_hello_from_enclave_t { char ms_buf; size_t ms_len;} ms_ecall_hello_from_enclave_t;static const struct { size_t nr_ocall; void table[1];} ocall_table_Enclave = { 0, { NULL },};sgx_status_t ecall_hello_from_enclave(sgx_enclave_id_t eid, char buf, size_t len){ sgx_status_t status; ms_ecall_hello_from_enclave_t ms; ms.ms_buf = buf; ms.ms_len = len; status = sgx_ecall(eid, 0, &ocall_table_Enclave, &ms); return status;}App.cpp

App.cpp是非安全区的业务代码,从代码来看,先要创建一个enclave,加载的是一个签名过的动态库。

#include <stdio.h>#include <string.h>#include <assert.h>#include <time.h>#include <ctime># include <unistd.h># include <pwd.h># define MAX_PATH FILENAME_MAX#include "sgx_urts.h"#include "App.h"#include "Enclave_u.h"/ Global EID shared by multiple threads /sgx_enclave_id_t global_eid = 0;int initialize_enclave(void){ sgx_status_t ret = SGX_ERROR_UNEXPECTED; char enclavefile[256]; getcwd(enclavefile, sizeof(enclavefile)); strcat(enclavefile, "/enclave.signed.so"); // so文件名 / Call sgx_create_enclave to initialize an enclave instance / / Debug Support: set 2nd parameter to 1 / ret = sgx_create_enclave(enclavefile, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL); // 重要 if (ret != SGX_SUCCESS) { printf("Failed to create enclave, ret code: %d, enclave file: %s\n", ret, enclavefile); return -1; } return 0;}tm get_time() { time_t rawtime; struct tm timeinfo; time ( &rawtime ); timeinfo = localtime ( &rawtime ); return timeinfo;}/ Application entry /int SGX_CDECL main(int argc, char argv[]){ (void)(argc); (void)(argv); const size_t max_buf_len = 100; char buffer[max_buf_len] = {0}; / Initialize the enclave / if(initialize_enclave() < 0){ printf("Enter a character before exit ...\n"); getchar(); return -1; } / Enclave calls / while(1) { ecall_hello_from_enclave(global_eid, buffer, max_buf_len); // 重要 printf("%s%s\n", asctime(get_time()), buffer); fflush(stdout); sleep(1); } / Destroy the enclave / sgx_destroy_enclave(global_eid); printf("Info: SampleEnclave successfully returned.\n"); printf("Enter a character before exit ...\n"); getchar(); return 0;}Enclave.config.xml/Enclave.lds/Enclave_private.pem

要让程序可编译,还需要生成几个文件,这个XML是enclave的配置文件,包含堆大小,栈大小,是否开启调试等。

<EnclaveConfiguration> <ProdID>0</ProdID> <ISVSVN>0</ISVSVN> <StackMaxSize>0x40000</StackMaxSize> <HeapMaxSize>0x100000</HeapMaxSize> <TCSNum>10</TCSNum> <TCSPolicy>1</TCSPolicy> <!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release --> <DisableDebug>0</DisableDebug> <MiscSelect>0</MiscSelect> <MiscMask>0xFFFFFFFF</MiscMask></EnclaveConfiguration>

Enclave.lds是链接脚本。

enclave.so{ global: g_global_data_sim; g_global_data; enclave_entry; g_peak_heap_used; local: ;};

Enclave_private.pem就是一个普通的RSA密钥,示例是用 openssl genrsa -out Enclave_private.pem -3 3072 生成,Enclave.signed.so就是用该密钥签名的。

编译和运行

make执行编译,sdk支持模拟方式。

make SGX_MODE=SIM 可以在不支持SGX的系统上编译并运行SGX程序。

SDK示范代码的README中有几种编译模式的详细描述。

3. Build the project with the prepared Makefile: a. Hardware Mode, Debug build: $ make b. Hardware Mode, Pre-release build: $ make SGX_PRERELEASE=1 SGX_DEBUG=0 c. Hardware Mode, Release build: $ make SGX_DEBUG=0 d. Simulation Mode, Debug build: $ make SGX_MODE=SIM e. Simulation Mode, Pre-release build: $ make SGX_MODE=SIM SGX_PRERELEASE=1 SGX_DEBUG=0 f. Simulation Mode, Release build: $ make SGX_MODE=SIM SGX_DEBUG=0

enclave的库是静态的

$ ldd enclave.signed.so statically linked

app侧会有一些sgx的依赖

$ ldd hello_world linux-vdso.so.1 (0x00007ffd7effe000) libsgx_urts_sim.so => /home/kaifeng/intel/sgxsdk/sdk_libs/libsgx_urts_sim.so (0x00007f6461149000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6460965000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f6460761000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f6460542000) libcrypto.so.1.1 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007f6460077000) libsgx_uae_service_sim.so => /home/kaifeng/intel/sgxsdk/sdk_libs/libsgx_uae_service_sim.so (0x00007f6461121000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f645fcee000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f645fad6000) /lib64/ld-linux-x86-64.so.2 (0x00007f6460f59000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f645f738000)

运行可以得到预期行为

$ ./hello_worldTue Dec 28 16:26:59 2021Hello worldTue Dec 28 16:27:00 2021Hello worldTue Dec 28 16:27:01 2021Hello worldTue Dec 28 16:27:02 2021Hello worldTue Dec 28 16:27:03 2021Hello world^C

以Hardware方式编译的程序,在开启SGX的系统上能够运行。

目标系统也需要安装sdk的库,这些需要集成到标准路径下。

标签:

相关文章