【SGX系列教程】(三)Intel-SGX 官方示例分析(SampleCode)——Cxx11SGXDemo

    下面将给出一些sgx源码包中的示例分析,从中学习SGX的基本使用方法:
关于 SGX 开发运行环境的搭建可参考之前的一篇博客:【SGX系列教程】(一)

示例一. Cxx11SGXDemo

1.1 README

-----------------------
Purpose of Cxx11SGXDemo
-----------------------
The project demonstrates serveral C++11 features inside the Enclave:
- lambda expressions;
- rvalue references and move semantics;
- automatic type deduction with auto and decltype;
- nullptr type;
- strongly typed enum classes;
- Range-based for statements;
- static_assert keyword for compile-time assertion;
- initializer lists and uniform initialization syntax;
- New virtual function controls: override, final, default, and delete;
- delegating constructors;
- new container classes (unordered_set, unordered_map, unordered_multiset, and unordered_multimap);
- tuple class;
- function object wrapper;
- atomic, mutexes, condition_variables;
- new smart pointer classes: shared_ptr, unique_ptr;
- new c++ algorithms: all_of, any_of, none_of;
- variadic templates;
- SFINAE;

---------------------------------------------
How to Build/Execute the C++11 sample program
---------------------------------------------
1. Install Intel(R) Software Guard Extensions (Intel(R) SGX) SDK for Linux* OS
2. Enclave test key(two options):
    a. Install openssl first, then the project will generate a test key<Enclave_private_test.pem> automatically when you build the project.
    b. Rename your test key(3072-bit RSA private key) to <Enclave_private_test.pem> and put it under the <Enclave> folder.
3. Make sure your environment is set:
    $ source ${sgx-sdk-install-path}/environment
4. 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
5. Execute the binary directly:
    $ ./app
6. Remember to "make clean" before switching build mode

-------------------------------------------------
Launch token initialization
-------------------------------------------------
If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example,

sgx_launch_token_t launch_token = {
   0};
sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL);

    工程的主要功能是测试c++11的一些特性在enclave中的执行情况,根据上面README中的内容总结一下Cxx11SGXDemo的执行步骤如下:

  1. 首先需要安装SGX sdk,以及等等对SGX的支持测试,具体可参考之前的一篇博客:【SGX系列教程】(一)
  2. 安装openssl,目的是为enclave.so生成签名私钥:

openssl genrsa -out Enclave/Enclave_private_test.pem -3 3072

  1. 确保sdk路径生效(source),基本在安装sdk时会指定安装路径为:/opt/intel/sgxsdk
  2. 使用Makefile构建工程:
    • 硬件模式, Debug build:
      make
    • 硬件模式, Pre-release build:
      make SGX_PRERELEASE=1 SGX_DEBUG=0
    • 硬件模式, Release build:
      make SGX_DEBUG=0
    • 仿真模式, Debug build:
      make SGX_MODE=SIM
    • 仿真模式, Pre-release build:
      make SGX_MODE=SIM SGX_PRERELEASE=1 SGX_DEBUG=0
    • 仿真模式, Release build:
      make SGX_MODE=SIM SGX_DEBUG=0
  3. 执行:./app
  4. 在切换编译模式之前记得make clean

1.2 重点代码分析

    SGX工程的整个构建流程在上一篇文章中已经给出给出了详细教程:【SGX系列教程】(二)第一个 SGX 程序: HelloWorld,因此在此处仅给出部分重点代码分析,主要讲清楚enclave如何支持c++11的运行,并提供哪些支持,其他通用代码不做展开分析。

    文件目录如下图,主要关注图中框出来的两个文件,其中Enclave文件夹中的Libxx.cpp提供enclave中函数执行功能,是系统的核心功能文件(将在后面详细分析文件功能),并封装成ECALL函数由外部调用;而App文件夹中的Libxx.cpp负责调用上述的ECALL函数
在这里插入图片描述
    整个程序调用过程可先总结为下图:
在这里插入图片描述

1.2.1 App/App.cpp

#include <stdio.h>      // 标准输入输出库,提供如 printf 等函数
#include <string.h>     // 字符串处理函数库
#include <assert.h>     // 断言函数库,用于调试

# include <unistd.h>    // 提供对 POSIX 操作系统 API 的访问,包括文件和进程
# include <pwd.h>       // 提供对用户密码信息的访问
# define MAX_PATH FILENAME_MAX // 定义 MAX_PATH 为系统最大文件名长度

#include "sgx_urts.h"   // SGX 用户运行时库,提供 SGX 相关 API
#include "App.h"        // 应用程序相关的头文件
#include "Enclave_u.h"  // Untrusted Enclave 的接口头文件

/* 全局 EID 由多个线程共享 */
sgx_enclave_id_t global_eid = 0;  // 定义一个全局的 SGX enclave ID

/* 错误代码结构体 */
typedef struct _sgx_errlist_t {
   
    sgx_status_t err;    // 错误码
    const char *msg;     // 错误信息
    const char *sug;     // 错误建议
} sgx_errlist_t;

/* 由 sgx_create_enclave 返回的错误代码 */
static sgx_errlist_t sgx_errlist[] = {
     // 错误列表,包含常见的 SGX 错误码及其信息
    {
   
        SGX_ERROR_UNEXPECTED,
        "Unexpected error occurred.",
        NULL
    },
    {
   
        SGX_ERROR_INVALID_PARAMETER,
        "Invalid parameter.",
        NULL
    },
    {
   
        SGX_ERROR_OUT_OF_MEMORY,
        "Out of memory.",
        NULL
    },
    {
   
        SGX_ERROR_ENCLAVE_LOST,
        "Power transition occurred.",
        "Please refer to the sample \"PowerTransition\" for details."
    },
    {
   
        SGX_ERROR_INVALID_ENCLAVE,
        "Invalid enclave image.",
        NULL
    },
    {
   
        SGX_ERROR_INVALID_ENCLAVE_ID,
        "Invalid enclave identification.",
        NULL
    },
    {
   
        SGX_ERROR_INVALID_SIGNATURE,
        "Invalid enclave signature.",
        NULL
    },
    {
   
        SGX_ERROR_OUT_OF_EPC,
        "Out of EPC memory.",
        NULL
    },
    {
   
        SGX_ERROR_NO_DEVICE,
        "Invalid SGX device.",
        "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards."
    },
    {
   
        SGX_ERROR_MEMORY_MAP_CONFLICT,
        "Memory map conflicted.",
        NULL
    },
    {
   
        SGX_ERROR_INVALID_METADATA,
        "Invalid enclave metadata.",
        NULL
    },
    {
   
        SGX_ERROR_DEVICE_BUSY,
        "SGX device was busy.",
        NULL
    },
    {
   
        SGX_ERROR_INVALID_VERSION,
        "Enclave version was invalid.",
        NULL
    },
    {
   
        SGX_ERROR_INVALID_ATTRIBUTE,
        "Enclave was not authorized.",
        NULL
    },
    {
   
        SGX_ERROR_ENCLAVE_FILE_ACCESS,
        "Can't open enclave file.",
        NULL
    },
    {
   
        SGX_ERROR_NDEBUG_ENCLAVE,
        "The enclave is signed as product enclave, and can not be created as debuggable enclave.",
        NULL
    },
    {
   
        SGX_ERROR_MEMORY_MAP_FAILURE,
        "Failed to reserve memory for the enclave.",
        NULL
    },
};

/* 打印错误信息 */
void print_error_message(sgx_status_t ret)
{
   
    size_t idx = 0;  // 循环索引
    size_t ttl = sizeof sgx_errlist / sizeof sgx_errlist[0];  // 错误列表的总长度
    // 遍历错误列表,查找对应的错误
    for (idx = 0; idx < ttl; idx++) {
   
        if (ret == sgx_errlist[idx].err) {
     // 找到对应的错误码
            if (NULL != sgx_errlist[idx].sug)  // 如果存在建议,打印建议
                printf("Info: %s\n", sgx_errlist[idx].sug);
            printf("Error: %s\n", sgx_errlist[idx].msg);  // 打印错误信息
            break;
        }
    }
    if (idx == ttl)  // 如果遍历后未找到相应错误码,打印未预期的错误发生
        printf("Error: Unexpected error occurred.\n");
}

/* 初始化信任域:
 * 调用 sgx_create_enclave 来初始化一个信任域实例
 */
int initialize_enclave(void)
{
   
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;  // 初始化错误状态
    /* 调用 sgx_create_enclave 来初始化一个信任域实例 */
    /* 调试支持:将第二个参数设置为 1 */   
    ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL);
    if (ret != SGX_SUCCESS) {
     // 如果初始化失败,打印错误信息
        print_error_message(ret);
        return -1;  // 返回错误状态
    }
    return 0;  // 成功初始化,返回0
}

/* OCall 函数,由enclave.cpp中函数调用:ocall_print_string(buf) */
void ocall_print_string(const char *str)
{
   
    printf("%s", str);
}

/* 主应用程序main入口 */
int SGX_CDECL main(int argc, char *argv[])
{
   
    (void)(argc);  // 防止未使用参数警告
    (void)(argv);   
    /* 初始化信任域 */
    if (initialize_enclave() < 0) {
     // 如果信任域初始化失败,打印信息并退出
        printf("Enter a character before exit ...\n");
        getchar();  // 等待用户输入
        return -1;  
    }
    /* 使用信任库函数,定义在App/TrustedLibrary/Libcxx.cpp文件中*/
    ecall_libcxx_functions();  // 调用 ECALL 函数,利用受信任的 C++11库
    /* 销毁信任域 */
    sgx_destroy_enclave(global_eid);  // 销毁信任域实例

    printf("Info: Cxx11DemoEnclave successfully returned.\n");  
    // 打印成功信息
    //printf("Enter a character before exit ...\n");
    //getchar();  // 此行代码被注释掉,仅供调试时使用
    return 0;  // 返回0,表示程序正常退出
}

    上述实现了一个简单的SGX应用程序,主要功能包括:初始化SGX信任域、调用受信任代码、打印错误信息和与主机间通信。用于展示如何在C++中利用Intel SGX进行安全函数的调用和管理。可以看出函数ecall_libcxx_functions()是核心功能函数。下面介绍该函数。

1.2.2 App/TrustedLibrary/Libcxx.cpp

#include <stdio.h>
#include "../App.h"
#include "Enclave_u.h"
#include <thread>

// 该函数调用了标准的C++11功能。
// 这个函数是互斥锁演示的一部分
void demo_counter_without_mutex()
{
   
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用不使用保护的互斥锁计数演示
    ret = ecall_mutex_demo_no_protection(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 这个函数是互斥锁演示的一部分
void demo_counter_mutex()
{
   
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用使用保护的互斥锁计数演示
    ret = ecall_mutex_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 这个函数是条件变量演示的处理线程使用
void demo_cond_var_run()
{
   
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用条件变量运行演示
    ret = ecall_condition_variable_run(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 这个函数是条件变量演示的加载线程使用
void demo_cond_var_load()
{
   
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用条件变量加载演示
    ret = ecall_condition_variable_load(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 示例展示了C++11库和编译器特性,被App.cpp中main函数调用
void ecall_libcxx_functions(void)
{
   
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // lambda函数特性的示例
    ret = ecall_lambdas_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // auto特性的示例
    ret = ecall_auto_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // decltype特性的示例
    ret = ecall_decltype_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 强类型枚举特性的示例
    ret = ecall_strongly_typed_enum_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 基于范围的for循环特性的示例
    ret = ecall_range_based_for_loops_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 静态断言特性的示例
    ret = ecall_static_assert_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 虚函数控制特性的示例:override, final, default, and delete
    ret = ecall_virtual_function_control_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 委派构造函数特性的示例
    ret = ecall_delegating_constructors_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // std::function特性的示例
    ret = ecall_std_function_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 算法特性的示例(std::all_of, std::any_of, std::none_of)
    ret = ecall_cxx11_algorithms_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 可变参数模板特性的示例
    ret = ecall_variadic_templates_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // SFINAE特性的示例
    ret = ecall_SFINAE_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 初始化列表特性的示例
    ret = ecall_initializer_list_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 右值引用特性的示例
    ret = ecall_rvalue_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // nullptr特性的示例
    ret = ecall_nullptr_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 枚举类特性的示例
    ret = ecall_enum_class_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 新容器类特性的示例(unordered_set, unordered_map, unordered_multiset, 和 unordered_multimap)
    ret = ecall_new_container_classes_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 元组特性的示例
    ret = ecall_tuple_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // shared_ptr特性的示例
    ret = ecall_shared_ptr_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 原子操作特性的示例
    ret = ecall_atomic_demo(global_eid);
    if (ret != SGX_SUCCESS)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tutu-hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值