Enclave.edl
import Edger8rSyntax/Types.edl
/* Enclave.edl - Top EDL file. */
enclave {
include "user_types.h" /* buffer_t */
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 *;
/*
* ocall_print_string - invokes OCALL to display string buffer inside the enclave.
* [in]: copy the string buffer to App outside.
* [string]: specifies 'str' is a NULL terminated buffer.
*/
untrusted {
void ocall_print_string([in, string] const char *str);
};
};
Types.edl defines ecalls with different parameter type
trusted {
public void ecall_type_char(char val);
public void ecall_type_int(int val);
// other functions omitted
Use sgx_edger8r generate App/Enclave_u.c App/Enclave_u.h
cd App && /opt/intel/sgxsdk/bin/x64/sgx_edger8r --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path /opt/intel/sgxsdk/include
Enclave_u.c
We can find that all trusted functions compiled to the function with same name, but add parameter sgx_enclave_id_t eid
.
All trusted functions call sgx_ecall with first parameter indicates the enclave id, the second parameter is generated function id. Other parameters will be interpreted soon.
sgx_status_t ecall_type_char(sgx_enclave_id_t eid, char val)
{
sgx_status_t status;
ms_ecall_type_char_t ms;
ms.ms_val = val;
status = sgx_ecall(eid, 0, &ocall_table_Enclave, &ms);
return status;
}
sgx_status_t ecall_type_enum_union(sgx_enclave_id_t eid, enum enum_foo_t val1, union union_foo_t* val2)
{
sgx_status_t status;
ms_ecall_type_enum_union_t ms;
ms.ms_val1 = val1;
ms.ms_val2 = val2;
status = sgx_ecall(eid, 7, &ocall_table_Enclave, &ms);
return status;
}
The third parameter of sgx_ecall is ocall_table_Enclave
, which include all the functions untrusted, for example Enclave_ocall_print_string
in Enclave.edl
, added prefix Enclave_
.
ocall_table_Enclave = {
11,
{
(void*)Enclave_ocall_print_string,
(void*)Enclave_ocall_pointer_user_check,
(void*)Enclave_ocall_pointer_in,
(void*)Enclave_ocall_pointer_out,
(void*)Enclave_ocall_pointer_in_out,
(void*)Enclave_ocall_function_allow,
(void*)Enclave_sgx_oc_cpuidex,
(void*)Enclave_sgx_thread_wait_untrusted_event_ocall,
(void*)Enclave_sgx_thread_set_untrusted_event_ocall,
(void*)Enclave_sgx_thread_setwait_untrusted_events_ocall,
(void*)Enclave_sgx_thread_set_multiple_untrusted_events_ocall,
}
};
The forth and last parameter is ms
. Every trusted function has a struct to encapsulate all the parameters, for exmaple, function ecall_type_char
has struct ms_ecall_type_char_t
.
typedef struct ms_ecall_type_char_t {
char ms_val;
} ms_ecall_type_char_t;
Parameters in and out
Pointers
/*
* Following keywords/attributes are supported for pointers in Edger8r:
* in, out, user_check,
* string, wstring,
* const, size, count, isptr, readonly
*/
[user_check]
- EDL Definition
/*
* [user_check]:
* the pointer won't be validated, and the buffer pointed by
* 'val' is not copied into the enclave either. But Enclave
* can modify the memory pointed by 'val'.
*/
public size_t ecall_pointer_user_check([user_check] void *val, size_t sz);
- Enclave Definition
size_t ecall_pointer_user_check(void* val, size_t sz)
{
/* check if the buffer is allocated outside */
if (sgx_is_outside_enclave(val, sz) != 1)
abort();
/*fence after sgx_is_outside_enclave check*/
sgx_lfence();
char tmp[100] = { 0 };
size_t len = sz > 100 ? 100 : sz;
/* copy the memory into the enclave to make sure 'val'
* is not being changed in checksum_internal() */
memcpy(tmp, val, len);
int32_t sum = checksum_internal((char*)tmp, len);
printf("Checksum(0x%p, %zu) = 0x%x\n",
val, len, (unsigned int)sum);
/* modify outside memory directly */
memcpy(val, "SGX_SUCCESS", len > 12 ? 12 : len);
return len;
}
- App Definition
char c[128] = {0};
size_t len = 0;
memset(c, 0xe, 128);
ret = ecall_pointer_user_check(global_eid, &len, &c, 128);
if (ret != SGX_SUCCESS)
abort();
assert(strcmp(c, "SGX_SUCCESS") == 0);
[in]
- EDL Definition
/*
* [in]:
* buffer with the same size will be allocated inside the enclave,
* content pointed by 'val' will be copied into the new allocated
* memory inside. Any changes performed inside the enclave will not
* affect the buffer outside.
*/
public void ecall_pointer_in([in] int *val);
- Enclave Definition
/* ecall_pointer_in:
* the buffer of val is copied to the enclave.
*/
void ecall_pointer_in(int* val)
{
if (sgx_is_within_enclave(val, sizeof(int)) != 1)
abort();
*val = 1234;
}
- App Definition
val = 0;
ret = ecall_pointer_in(global_eid, &val);
if (ret != SGX_SUCCESS)
abort();
assert(val == 0);
[out]
- EDL Definition
/*
* [out]:
* buffer with the same size will be allocated inside the enclave,
* but the content pointed by 'val' won't be copied. But after return,
* the buffer inside the enclave will copied into outside 'val'.
*/
public void ecall_pointer_out([out] int *val);
- Enclave Definition
/* ecall_pointer_out:
* the buffer of val is copied to the untrusted side.
*/
void ecall_pointer_out(int* val)
{
if (sgx_is_within_enclave(val, sizeof(int)) != 1)
abort();
assert(*val == 0);
*val = 1234;
}
- App Definition
val = 0;
ret = ecall_pointer_out(global_eid, &val);
if (ret != SGX_SUCCESS)
abort();
assert(val == 1234);
[in, out]
- EDL Definition
/*
* [in, out]:
* buffer with the same size will be allocated inside the enclave,
* the content pointed by 'val' will be copied either. After return,
* the buffer inside the enclave will by copied into outside 'val' again.
*/
public void ecall_pointer_in_out([in, out] int *val);
- Enclave Definition
/* ecall_pointer_in_out:
* the buffer of val is double-copied.
*/
void ecall_pointer_in_out(int* val)
{
if (sgx_is_within_enclave(val, sizeof(int)) != 1)
abort();
*val = 1234;
}
- App Definition
val = 0;
ret = ecall_pointer_in_out(global_eid, &val);
if (ret != SGX_SUCCESS)
abort();
assert(val == 1234);
[string]
- EDL Definition
/*
* [string]:
* the attribute tells Edger8r 'str' is NULL terminated string, so strlen
* will be used to count the length of buffer pointed by 'str'.
*/
public void ecall_pointer_string([in, out, string] char *str);
- Enclave Definition
/* ecall_pointer_string:
* [string] defines a string.
*/
void ecall_pointer_string(char* str)
{
strncpy(str, "0987654321", strlen(str));
}
- App Definition
char str1[] = "1234567890";
ret = ecall_pointer_string(global_eid, str1);
if (ret != SGX_SUCCESS)
abort();
assert(strlen(str1) == 10 && memcmp(str1, "0987654321", strlen(str1)) == 0);
[const]
- EDL Definition
/*
* [const]:
* the attribute tells Edger8r the buffer pointed by 'str' cannot be modified,
* so users cannot decorate 'str' with [out] attribute anymore.
*/
public void ecall_pointer_string_const([in, string] const char *str);
- Enclave Definition
/* ecall_pointer_string_const:
* const [string] defines a string that cannot be modified.
*/
void ecall_pointer_string_const(const char* str)
{
char* temp = new char[strlen(str)];
strncpy(temp, str, strlen(str));
delete[] temp;
}
- App Definition
const char str2[] = "1234567890";
ret = ecall_pointer_string_const(global_eid, str2);
if (ret != SGX_SUCCESS)
abort();
assert(strlen(str2) == 10 && memcmp(str2, "1234567890", strlen(str2)) == 0);
[size]
- EDL Definition
/*
* [size]:
* the attribute tells Edger8r the length of buffer in byte pointed by 'ptr'
* (shall be copied or not).
* Note: Users shall not specify [size] on [string] parameters.
*/
public void ecall_pointer_size([in, out, size=len] void *ptr, size_t len);
- Enclave Definition
/* ecall_pointer_size:
* 'len' needs to be specified to tell Edger8r the length of 'str'.
*/
void ecall_pointer_size(void* ptr, size_t len)
{
strncpy((char*)ptr, "0987654321", len);
}
- App Definition
char str3[] = "1234567890";
ret = ecall_pointer_size(global_eid, (void*)str3, strlen(str3));
if (ret != SGX_SUCCESS)
abort();
assert(strlen(str3) == 10 && memcmp(str3, "0987654321", strlen(str3)) == 0);
[count]
- EDL Definition
/*
* [count]:
* the attribute tells Edger8r the number of integers to be copied from 'arr'.
*/
public void ecall_pointer_count([in, out, count=cnt] int *arr, size_t cnt);
- Enclave Definition
/* ecall_pointer_count:
* 'cnt' needs to be specified to tell Edger8r the number of elements in 'arr'.
*/
void ecall_pointer_count(int* arr, size_t count)
{
int cnt = (int)count;
for (int i = (cnt - 1); i >= 0; i--)
arr[i] = (cnt - 1 - i);
}
- App Definition
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ret = ecall_pointer_count(global_eid, arr, 10);
if (ret != SGX_SUCCESS)
abort();
for (int i = 0; i < 10; i++)
assert(arr[i] == (9 - i));
[isptr]
- EDL Definition
/*
* [isptr]:
* tells Edger8r the user defined type is a pointer;
* [readonly]:
* forbids the buffer allocated inside the enclave to be copied back to App
* (cannot use with [out]).
*/
public void ecall_pointer_isptr_readonly([in, isptr, readonly, size=len] buffer_t buf, size_t len);
- Enclave Definition
/* ecall_pointer_isptr_readonly:
* 'buf' is user defined type, shall be tagged with [isptr].
* if it's not writable, [readonly] shall be specified.
*/
void ecall_pointer_isptr_readonly(buffer_t buf, size_t len)
{
strncpy((char*)buf, "0987654321", len);
}
- App Definition
char str4[] = "1234567890";
ret = ecall_pointer_isptr_readonly(global_eid, (buffer_t)str4, strlen(str4));
if (ret != SGX_SUCCESS)
abort();
assert(strlen(str4) == 10 && memcmp(str4, "1234567890", strlen(str4)) == 0);
public functions and private function in edl
Edl Definition
trusted {
/*
* [public]:
* public ECALL can be called directly in App.
*/
public void ecall_function_public(void);
/*
* [private]:
* private ECALL cannot be called directly in App.
*/
int ecall_function_private(void);
};
Enclave Definition
/* ecall_function_public:
* The public ECALL that invokes the OCALL 'ocall_function_allow'.
*/
void ecall_function_public(void)
{
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
ret = ocall_function_allow();
if (ret != SGX_SUCCESS)
abort();
return;
}
/* ecall_function_private:
* The private ECALL that only can be invoked in the OCALL 'ocall_function_allow'.
*/
int ecall_function_private(void)
{
return 1;
}
App Definition
/* No need to implement memccpy here! */
/* edger8r_function_attributes:
* Invokes ECALL declared with calling convention attributes.
* Invokes ECALL declared with [public].
*/
void edger8r_function_attributes(void)
{
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
ret = ecall_function_public(global_eid);
if (ret != SGX_SUCCESS)
abort();
/* user shall not invoke private function here */
int runned = 0;
ret = ecall_function_private(global_eid, &runned);
if (ret != SGX_ERROR_ECALL_NOT_ALLOWED || runned != 0)
abort();
}
/* ocall_function_allow:
* The OCALL invokes the [allow]ed ECALL 'edger8r_private'.
*/
void ocall_function_allow(void)
{
int runned = 0;
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
ret = ecall_function_private(global_eid, &runned);
if (ret != SGX_SUCCESS || runned != 1)
abort();
}