Intel SGX程序編寫

1 背景知識

當程序在enclave裏和enclave外切換時,會發生上下文切換、保存CPU狀態,參考https://eprint.iacr.org/2016/086.pdf,因此會有一定的開銷。enclave內被視爲是可信的,enclave外被視爲是不可信的。從enclave外調用enclave內的程序爲ECALL,從enclave裏調用enclave外的程序爲OCALL,https://download.01.org/intel-sgx/linux-2.3/docs/Intel_SGX_Developer_Reference_Linux_2.3_Open_Source.pdf,具體如下圖所示。
在這裏插入圖片描述

2 代碼編寫

以安裝時SDK文件夾下Sample Code裏Sample Enclave工程代碼爲模板,進行修改,這裏參考了https://blog.csdn.net/cyLee_/article/details/90200470https://blog.csdn.net/qiu_pengfei/article/details/78803148

2.1 代碼結構

App文件夾
在這裏插入圖片描述
Enclave文件夾
在這裏插入圖片描述
其它文件
在這裏插入圖片描述
項目下的.settings是隱藏文件夾,裏面的language.settings.xml定義了一些與語言相關的信息。.cproject和.project是隱藏文件,我們也不用管它們。README.txt可以刪除。App文件夾下的Edger8rSyntax和TrustedLibrary文件夾及其中的文件在這個項目中是沒有用的,我們把它們刪除,同理Enclave文件夾下的Edger8rSyntax和TrustedLibrary文件夾在這個項目中也是沒有用的,我們把它們刪除。最後項目的目錄結構如下圖所示,參考https://blog.csdn.net/qiu_pengfei/article/details/78803148
在這裏插入圖片描述

App文件夾:該文件夾存放應用程序中的不可信代碼部分,共有2個文件,App.cpp文件和App.h文件。
App.cpp文件:該文件是應用程序中的不可信部分代碼,其中包括了創建Enclave及銷燬Enclave的代碼,也定義了一些相關的返回代碼供使用者查看Enclave程序的執行狀態。其中的main函數是整個項目的入口函數。是我們要修改的文件。
App.h文件:該文件是應用程序中的不可信部分代碼的頭文件,定義了一些宏常量和函數聲明。
Enclave文件夾:該文件夾存放應用程序中的可信代碼部分和可信與不可信代碼接口文件,共有6個文件,Enclave.config.xml文件、Enclave.cpp文件、Enclave.h文件、Enclave.edl文件、Enclave.lds文件和Enclave_private.pem文件
Enclave.config.xml文件:該文件是Enclave的配置文件,定義了Enclave的元數據信息,我們可以不用更改。
Enclave.cpp文件:該文件是應用程序中的可信部分代碼,包括了可信函數的實現,是我們要修改的文件。
Enclave.h文件:該文件是應用程序中的可信部分代碼的頭文件,定義了一些宏常量和函數聲明,是我們要修改的文件。
Enclave.edl文件:該文件是Enclave的接口定義文件,定義了不可信代碼調用可信代碼的ECALL函數接口和可信代碼調用不可信代碼的OECALL函數接口,trusted{}中定義了ECALL函數接口,untrusted{}中定義了OECALL函數接口是我們要修改的文件。
Enclave.lds文件:該文件定義了一些Enclave可執行文件信息,我們不用更改。
Enclave_private.pem文件:該文件是SGX生成的私鑰,我們不用更改。
Include文件夾:該文件夾存放被Enclave接口定義文件Enclave.edl使用的頭文件,包括一些宏定義,我們不用管它。共有一個文件,user_types.h文件。
user_types.h文件:該文件定義了用戶自定義的類型。
Makefile文件:該文件是項目的編譯文件,定義了項目的編譯信息,詳細說明還請參考https://blog.csdn.net/cyLee_/article/details/90200470

2.2 代碼修改

這裏以EmptyEcallHelloWorld工程爲例,這個工程的運行邏輯是App文件夾下的app.cpp調用Ecall_main()函數進入enclave,Ecall_main()函數調用enclave外的Ocall_print()函數,打印”Hello World!” ,然後返回到enclave,再從enclave返回。需要修改的文件包括:Enclave.edl文件、Enclave.cpp文件、Enclave.h文件、App.cpp文件、App.h文件和Makefile文件。
1.Enclave.edl。在該文件中人爲將與ECALL和OCALL相關的函數分爲trusted和untrusted部分。把與ECALL相關的函數放到trusted部分,把與OCALL相關的函數放到untrusted部分。因爲不需要Edger8rSyntax和TrustedLibrary,所以我們把與這兩部分相關的函數刪除,也就是把以下的代碼刪除。

from "Edger8rSyntax/Types.edl" import *;
from "Edger8rSyntax/Pointers.edl" import *;
from "Edger8rSyntax/Arrays.edl" import *;
from "Edger8rSyntax/Functions.edl" import *;
from "TrustedLibrary/Libc.edl" import *;
from "TrustedLibrary/Libcxx.edl" import ecall_exception, ecall_map;
from "TrustedLibrary/Thread.edl" import *;

由於這裏Ecall_main()與Ocall_print()函數並未涉及返回值,所以定義爲void類型,而與ECALL相關的函數需要定義爲public類型,放入trusted部分;Ocall_print()函數放入untrusted部分。如果涉及到返回值,需要指明方向屬性,,並通過指針傳遞返回值,可以參考https://download.01.org/intel-sgx/linux-2.3/docs/Intel_SGX_Developer_Reference_Linux_2.3_Open_Source.pdf裏關於direction attribute的介紹。修改完的代碼如下圖。
在這裏插入圖片描述
2. Enclave.cpp。只需要在該文件裏實現Ecall_main()函數即可,由於不需要void printf(const char *fmt, ...)函數,故刪除Enclave.cpp文件中的void printf(const char *fmt, ...)函數,並將以下代碼添加到Enclave.cpp文件中。

void Ecall_main(){}

修改完的代碼如下圖所示。
在這裏插入圖片描述
4. Enclave.h。這裏只需要聲明Ecall_main()函數即可。刪除Enclave.h文件中的void printf(const char *fmt, ...);函數聲明,並將以下代碼添加到Enclave.h文件中。

void Ecall_main();

修改後的代碼如下圖。
在這裏插入圖片描述
5. App.cpp。我們在該文件中自定義OcallPrint()函數打印”Hello World!“。由於我們不需要Edger8rSyntax和TrustedLibrary,所以我們把main函數中與這兩部分相關的函數調用刪除,也就是把下面部分刪除.

/* Utilize edger8r attributes */
    edger8r_array_attributes();
    edger8r_pointer_attributes();
    edger8r_type_attributes();
    edger8r_function_attributes();
    /* Utilize trusted libraries */
    ecall_libc_functions();
    ecall_libcxx_functions();
	ecall_thread_functions();

由於我們不需要void ocall_print_string(const char *str)函數,所以我們把該函數刪除,也就是把下面部分刪除。

/* OCall functions */
void ocall_print_string(const char *str)
{
    /* Proxy/Bridge will check the length and null-terminate 
     * the input string to prevent buffer overflow. 
     */
    printf("%s", str);
}

需要實現我們的不可信函數Ocall_print(),該函數的功能是打印”Hello World!“,將以下代碼放到main函數之前。

void Ocall_print (){
        printf("Hello World\n");
    }

我們在main函數中的Enclave創建和銷燬之間通過代碼Ecall_main(global_eid);調用進入enclave,也就是把這句代碼放到sgx_destroy_enclave(global_eid);之前。global_eid參數是是enclave的id。在main函數裏,先初始化enclave,然後調用Ecall_main();進入創建的enclave裏,最後銷燬該enclave。
修改完的main函數如下圖所示。
在這裏插入圖片描述
5. App.h。在該頭文件裏聲明Ocall_print()函數,刪除其中的與Edger8rSyntax和TrustedLibrary相關的函數聲明,也就是將以下語句刪除。

void edger8r_array_attributes(void);
void edger8r_type_attributes(void);
void edger8r_pointer_attributes(void);
void edger8r_function_attributes(void);
void ecall_libc_functions(void);
void ecall_libcxx_functions(void);
void ecall_thread_functions(void);

添加以下代碼。

void Ocall_print();

修改完的app.h如下圖所示。
在這裏插入圖片描述

2.3 代碼測試

以2.3中的EmptyEcallHelloWorld工程爲例,運行代碼。
首先cd EmptyEcallHelloWorld,進入到項目路徑下。
ls列出當前文件夾下的文件。
在這裏插入圖片描述
make clean清除上次make生成的文件。
make對當前工程編譯(如果是在模擬模式下編譯,則make SGX_MODE=SIM)
命令行會打印出編譯的信息,包括項目所佔內存。
在這裏插入圖片描述
在最後會生成一個enclave.signed.so文件,並提示The project has been built in debug hardware mode,即工程是在硬件模式下編譯的。
在這裏插入圖片描述
ls可以看到項目下生成了一個app可執行文件。

./app

命令行打印出“Hello World!”程序運行成功!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章