百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

使用SGX开发一个简单的Hello World程序

bigegpt 2024-08-10 12:05 11 浏览

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

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

文件组织如下

├── 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.edl

Enclave_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 __cplusplus
extern "C" {
#endif

void ecall_hello_from_enclave(char* buf, size_t len);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif

Enclave_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_world
Tue Dec 28 16:26:59 2021
Hello world
Tue Dec 28 16:27:00 2021
Hello world
Tue Dec 28 16:27:01 2021
Hello world
Tue Dec 28 16:27:02 2021
Hello world
Tue Dec 28 16:27:03 2021
Hello world
^C

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

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

相关推荐

5分钟调色大片的方法(5分钟调色大片的方法有哪些)

哈喽大家好。在大家印象中一定觉得ps非常难学非常难。大家不要着急,小编的教学都是针对ps零基础的同学的,而且非常实用哦。只要大家跟着图文练习一两遍,保证大家立马学会~!好了,废话少说,下面开始我们今天...

闪白特效原来是这么用的(闪白特效怎么使用)

作者|高艳侠订阅|010-86092062闪白特效是影视作品中应用比较多的效果之一,那么具体该在哪些场景使用闪白特效?具体该如何操作?下面就以AdobePremiere(以下简称PR)为例,...

ppt常用小图标去哪里找?3个矢量素材网站推荐!

ppt是一个注重可视化表达的演示载体,除了高清图片,ppt中另一类常用的素材是各种小图标,也叫矢量图标,巧妙运用小图标能提升整体美观度和表现力,那么ppt常用小图标去哪里找呢?为方便各位快速找到合适的...

有什么好用的截图录屏工具?试试这9款

经常有朋友反馈苦于缺乏截屏和录屏的趁手工具,本期我们分享几个相当好用的截屏和录屏工具,希望能帮到大家。ScreenToGifScreenToGif是一款免费且开源的录屏工具。此款工具最大的特点是可以...

配色苦手福音!专业快速色环配色PS插件

今天橘子老师给的大家介绍的是一款快速配色的插件,非常强大配色苦手福音来啦!(获取方式见文末)【插件介绍】配色在后期设计中占有主导地位,好的配色能让作品更加抢眼Coolorus这款专业的配色插件,能够...

如何用PS抠主体?(ps怎么抠主体)

1.主体法抠图-抠花苞和花梗导入一张荷花苞的照片,点击上图中顶部“选择”菜单栏,下拉单击“主体”。可以看到,只有花苞被选中,但是花梗并没有被选中。接下来单击上图中左侧工具栏的“快速选择工具”,上图中顶...

2799元的4K电视,有保障吗?(买4k电视机哪个品牌好)

在上一期《电脑报》的3·15专题报道中,我们揭露了一款不靠谱的42英寸4K智能电视——TCLD42A561U。这款售价2699元的4K智能电视不仅4K画质方面存在严重问题,而且各种功能和应用体验也不理...

苹果电脑的Touch Bar推出一段时间了 这款工具可以帮你开发适用于它的APP

距离苹果推出带有TouchBar的MacBookPro已经有一段时间了,除了那些像Adobe、Google和Microsoft大公司在开发适用于TouchBar的应用之外,其实还有很多独立的开...

如魔法般吸取颜色的桌灯(如魔法般吸取颜色的桌灯叫什么)

色彩为生活带来的感官刺激,逐渐被视为理所当然。一盏桌灯运用它的神奇力量,将隐藏于物件中的颜色逐一释放,成为装点环境的空间魔法师。ColorUp是一款可以改变颜色的吸色台灯,沿用传统灯泡的造型,融入了拾...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

ps拾色器快捷键是什么?(ps2019拾色器快捷键)

ps拾色器快捷键是什么?文章末尾有获取方式,按照以下步骤就能自动获得!学会制作PS特效需要一定程度的耐心和毅力。初学者可以从基本的工具和技术开始学习,逐渐提高他们的技能水平。同时,观看更多优秀的特效作...

免费开源的 Windows 截图录屏工具,支持 OCR 识别和滚动截图等

功能很强大、安装很小巧的免费截图、录屏工具,提供很多使用的工具来帮我么能解决问题,推荐给大家。关于ShareXShareX是一款免费的windows工具,起初是一个小巧的截图工具,经过多年的迭...

入门到精通系列PS教程:第13篇 · 拾色器、颜色问题说明及补充

入门到精通系列PS教程:第13篇·拾色器、颜色问题说明及补充作者|侯潇问题说明我的第12篇教程里,有个小问题没有说清楚。要说是错误,又不算是错误,只是没有说准确。写完那篇教程后,因为已经到了深...

PS冷知识:用吸管工具吸取屏幕上的任意颜色

今天,我们给大家介绍PS中的一个冷知识:用吸管工具可以吸取屏幕上的任意颜色。其实,操作起来是非常简单的。大多数情况下,我们认为,PS的吸管工具只能吸取PS软件作图区域范围内的颜色,最多加上画布四周的...

Windows 11 将提供内置颜色选择器工具

Windows11内置了颜色选择器,可以扫描并识别屏幕上的颜色并生成颜色代码。此外,微软还利用人工智能技术,让屏幕上的文本扫描和选择变得更加便捷。这两项功能均已在SnippingToolv1...