diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 379bd4d675..1e87c9f6d2 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -318,6 +318,7 @@ list( ../common/kdf.c ../common/argv.c asym_keys.c + ecall_ids.c calls.c ocalls/log.c ocalls/ocalls.c diff --git a/host/calls.c b/host/calls.c index 65abb4503f..769302496a 100644 --- a/host/calls.c +++ b/host/calls.c @@ -5,21 +5,21 @@ #include #include "calls.h" +#include "ecall_ids.h" /* **============================================================================== ** -** oe_call_enclave_function() +** _call_enclave_function_impl() ** -** Call the enclave function specified by the given function-id in the -** function table. +** Call the enclave function specified by the given function-id. ** **============================================================================== */ -oe_result_t oe_call_enclave_function( +static oe_result_t _call_enclave_function_impl( oe_enclave_t* enclave, - uint32_t function_id, + uint64_t function_id, const void* input_buffer, size_t input_buffer_size, void* output_buffer, @@ -65,3 +65,47 @@ oe_result_t oe_call_enclave_function( done: return result; } +/* +**============================================================================== +** +** oe_call_enclave_function() +** +** Call the enclave function specified by the given function-id in the default +** function table. +** +**============================================================================== +*/ + +oe_result_t oe_call_enclave_function( + oe_enclave_t* enclave, + uint64_t* global_id, + const char* name, + const void* input_buffer, + size_t input_buffer_size, + void* output_buffer, + size_t output_buffer_size, + size_t* output_bytes_written) +{ + oe_result_t result = OE_UNEXPECTED; + uint64_t function_id = OE_UINT64_MAX; + + /* + * Look up the function id from the per-enclave table based on the + * global id. The global id is defined as a static variable in the + * oeedger8r-generated code. The function initializes the global id in + * the first invocation and uses the cached global id for the subsequent + * invocations. + */ + OE_CHECK(oe_get_ecall_ids(enclave, name, global_id, &function_id)); + + result = _call_enclave_function_impl( + enclave, + function_id, + input_buffer, + input_buffer_size, + output_buffer, + output_buffer_size, + output_bytes_written); +done: + return result; +} diff --git a/host/ecall_ids.c b/host/ecall_ids.c new file mode 100644 index 0000000000..f17eaf5532 --- /dev/null +++ b/host/ecall_ids.c @@ -0,0 +1,206 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include "ecall_ids.h" +#include +#include +#include "hostthread.h" + +// Initial size of ecall table mapping ecall names to global id. +// Most enclaves in OE SDK repo have fewer than 16 ecalls. +#define OE_ECALL_TABLE_INITIAL_SIZE 16 + +/* The maximum numer of different ecalls that an application can make is + * bounded. */ +static const char** _ecall_table; +static uint32_t _ecall_table_capacity; +static uint32_t _ecall_table_size; + +/* Mutex for assigning/looking up global ids in a thread-safe manner. */ +static oe_mutex _lock = OE_H_MUTEX_INITIALIZER; + +/* Cleanup memory during program terminaton */ +static void _free_ecall_table(void) +{ + oe_free((void*)_ecall_table); +} + +/* Get the global ecall id from the _ecall_table. Locking must be done by + * caller. */ +static oe_result_t _get_global_id(const char* name, uint64_t* global_id) +{ + oe_result_t result = OE_NOT_FOUND; + if (!name || !global_id) + OE_RAISE(OE_INVALID_PARAMETER); + + /* Search for id assigned for given name. */ + for (uint64_t i = 0; i < _ecall_table_size; i++) + { + if (strcmp(_ecall_table[i], name) == 0) + { + *global_id = i; + break; + } + } + + /* If the name is not found, adding it to the table. */ + if (*global_id == OE_GLOBAL_ECALL_ID_NULL) + { + // Resize table if needed. + if (_ecall_table_size == _ecall_table_capacity) + { + if (!_ecall_table) + { + _ecall_table_capacity = OE_ECALL_TABLE_INITIAL_SIZE; + atexit(_free_ecall_table); + } + else + { + _ecall_table_capacity *= 2; + } + _ecall_table = oe_realloc( + (void*)_ecall_table, _ecall_table_capacity * sizeof(char*)); + if (!_ecall_table) + OE_RAISE(OE_OUT_OF_MEMORY); + } + + _ecall_table[_ecall_table_size] = name; + *global_id = _ecall_table_size; + _ecall_table_size++; + } + + result = OE_OK; +done: + return result; +} + +oe_result_t oe_get_global_id(const char* name, uint64_t* global_id) +{ + oe_result_t result = OE_UNEXPECTED; + bool locked = false; + if (oe_mutex_lock(&_lock) != 0) + OE_RAISE(OE_FAILURE); + locked = true; + + result = _get_global_id(name, global_id); +done: + if (locked) + oe_mutex_unlock(&_lock); + return result; +} + +oe_result_t oe_get_ecall_ids( + oe_enclave_t* enclave, + const char* name, + uint64_t* global_id, + uint64_t* id) +{ + oe_result_t result = OE_FAILURE; + oe_ecall_id_t* ecall_id_table = NULL; + uint64_t ecall_id_table_size = 0; + + /* Validate parameters */ + if (!enclave || !global_id || !name || !id) + { + result = OE_INVALID_PARAMETER; + goto done; + } + + /* Initialize output parameter to NULL id */ + *id = OE_ECALL_ID_NULL; + + /* Fetch ecall_id_table using platform agnostic API */ + OE_CHECK( + oe_get_ecall_id_table(enclave, &ecall_id_table, &ecall_id_table_size)); + + /* Lookup/assign global id */ + if (*global_id == OE_GLOBAL_ECALL_ID_NULL) + { + /* The global_id variable is generated by edger8r, one global id + * variable per ecall. The same variable will be reused every time that + * ecall is made. Therefore, for an ecall, the following code will be + * executed only once. + */ + OE_CHECK(oe_get_global_id(name, global_id)); + } + + /* Look up function id based on global id. */ + if (*global_id >= ecall_id_table_size) + OE_RAISE(OE_NOT_FOUND); + + /* Look-up the ecall id from the per-enclave table. + * The ecall_id_table is expected to be set up during enclave creation + */ + *id = ecall_id_table[*global_id].id; + if (*id == OE_ECALL_ID_NULL) + OE_RAISE(OE_NOT_FOUND); + + result = OE_OK; +done: + return result; +} + +oe_result_t oe_register_ecalls( + oe_enclave_t* enclave, + const oe_ecall_info_t* ecall_info_table, + uint32_t num_ecalls) +{ + oe_result_t result = OE_UNEXPECTED; + oe_ecall_id_t* ecall_id_table = NULL; + uint64_t max_global_id = 0; + uint64_t ecall_id_table_size = 0; + bool locked = false; + + /* Validate parameters */ + if (!enclave || !ecall_info_table || !num_ecalls) + OE_RAISE(OE_INVALID_PARAMETER); + + if (oe_mutex_lock(&_lock) != 0) + OE_RAISE(OE_FAILURE); + locked = true; + + /* Iterate through the ecalls and assign global ids. + * Also find out the maximum global id for the enclave. */ + for (uint32_t i = 0; i < num_ecalls; i++) + { + uint64_t global_id = OE_GLOBAL_ECALL_ID_NULL; + const char* name = ecall_info_table[i].name; + + /* Assign a proper global id based on the global __ecall_table. */ + OE_CHECK(_get_global_id(name, &global_id)); + if (global_id > max_global_id) + max_global_id = global_id; + } + + /* Allocate ecall id table for the enclave */ + ecall_id_table_size = max_global_id + 1; + ecall_id_table = + (oe_ecall_id_t*)oe_malloc(sizeof(uint64_t) * ecall_id_table_size); + if (!ecall_id_table) + OE_RAISE(OE_OUT_OF_MEMORY); + + for (uint64_t i = 0; i < ecall_id_table_size; ++i) + ecall_id_table[i].id = OE_ECALL_ID_NULL; + + /* Fill the ecall id table */ + for (uint32_t i = 0; i < num_ecalls; i++) + { + uint64_t global_id = OE_GLOBAL_ECALL_ID_NULL; + const char* name = ecall_info_table[i].name; + uint64_t local_id = i; + + OE_CHECK(_get_global_id(name, &global_id)); + ecall_id_table[global_id].id = local_id; + } + + OE_CHECK( + oe_set_ecall_id_table(enclave, ecall_id_table, ecall_id_table_size)); + + result = OE_OK; + +done: + if (locked) + oe_mutex_unlock(&_lock); + + return result; +} diff --git a/host/ecall_ids.h b/host/ecall_ids.h new file mode 100644 index 0000000000..21de71210a --- /dev/null +++ b/host/ecall_ids.h @@ -0,0 +1,71 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#ifndef _OE_HOST_ECALLIDS_H +#define _OE_HOST_ECALLIDS_H + +#include +#include + +#define OE_ECALL_ID_NULL OE_UINT64_MAX +#define OE_MAX_ECALLS 256 + +OE_EXTERNC_BEGIN + +/** + * Id of an ecall. + */ +typedef struct _oe_ecall_id_t +{ + uint64_t id; +} oe_ecall_id_t; + +/** + * Get the global id for a given ecall name. + */ +oe_result_t oe_get_global_id( + const char* name, /* in */ + uint64_t* global_id); /* out */ + +/** + * Set the ecall id table for an enclave. + * This function is expected to be implemented as appropriate by + * host platform layers for various TEEs (SGX, OPTEE etc). + */ +oe_result_t oe_set_ecall_id_table( + oe_enclave_t* enclave, /* in */ + oe_ecall_id_t* ecall_id_table, /* in */ + uint64_t ecall_id_table_size); /* in */ + +/** + * Given an enclave, return its ecall id table. + * The ecall id table maps an ecall's global id to its function id. + * This function is expected to be implemented as appropriate by + * host platform layers for varios TEEs (SGX, OPTEE etc). + */ +oe_result_t oe_get_ecall_id_table( + oe_enclave_t* enclave, /* in */ + oe_ecall_id_t** ecall_id_table, /* out */ + uint64_t* ecall_id_table_size); /* out */ + +/** + * Get the ecall ids (global and local/function) of an ecall, given its + * name and enclave. + */ +oe_result_t oe_get_ecall_ids( + oe_enclave_t* enclave, /* in */ + const char* name, /* in */ + uint64_t* global_id, /* in/out */ + uint64_t* id); /* out */ + +/** + * Register the ecalls for a given enclave. + */ +oe_result_t oe_register_ecalls( + oe_enclave_t* enclave, /* in */ + const oe_ecall_info_t* ecall_info_table, /* in */ + uint32_t num_ecalls); /* in */ + +OE_EXTERNC_END + +#endif /* _OE_HOST_ECALL_IDS_H */ diff --git a/host/optee/linux/enclave.c b/host/optee/linux/enclave.c index e85383c5e6..a537fc2765 100644 --- a/host/optee/linux/enclave.c +++ b/host/optee/linux/enclave.c @@ -370,6 +370,40 @@ static oe_result_t _uuid_from_string(const char* uuid_str, TEEC_UUID* uuid) return OE_OK; } +oe_result_t oe_get_ecall_id_table( + oe_enclave_t* enclave, + oe_ecall_id_t** ecall_id_table, + uint64_t* ecall_id_table_size) +{ + oe_result_t result = OE_UNEXPECTED; + if (!enclave || !ecall_id_table || !ecall_id_table_size) + OE_RAISE(OE_INVALID_PARAMETER); + + *ecall_id_table = enclave->ecall_id_table; + *ecall_id_table_size = enclave->ecall_id_table_size; + result = OE_OK; + +done: + return result; +} + +oe_result_t oe_set_ecall_id_table( + oe_enclave_t* enclave, + oe_ecall_id_t* ecall_id_table, + uint64_t ecall_id_table_size) +{ + oe_result_t result = OE_UNEXPECTED; + if (!enclave || !ecall_id_table || !ecall_id_table_size) + OE_RAISE(OE_INVALID_PARAMETER); + + enclave->ecall_id_table = ecall_id_table; + enclave->ecall_id_table_size = ecall_id_table_size; + result = OE_OK; + +done: + return result; +} + oe_result_t oe_create_enclave( const char* enclave_path, oe_enclave_type_t enclave_type, @@ -378,6 +412,8 @@ oe_result_t oe_create_enclave( uint32_t setting_count, const oe_ocall_func_t* ocall_table, uint32_t ocall_count, + const oe_ecall_info_t* ecall_name_table, + uint32_t ecall_count, oe_enclave_t** enclave_out) { oe_result_t result = OE_UNEXPECTED; @@ -458,6 +494,10 @@ oe_result_t oe_create_enclave( enclave->ocalls = (const oe_ocall_func_t*)ocall_table; enclave->num_ocalls = ocall_count; + /* Register ecalls */ + enclave->num_ecalls = ecall_count; + oe_register_ecalls(enclave, ecall_name_table, ecall_count); + *enclave_out = enclave; result = OE_OK; @@ -524,6 +564,10 @@ oe_result_t oe_terminate_enclave(oe_enclave_t* enclave) /* Finalize the context against OP-TEE */ TEEC_FinalizeContext(&enclave->ctx); + /* Destroy the ecall id table */ + if (enclave->ecall_id_table) + free(enclave->ecall_id_table); + /* Destroy the concurrency mutex */ pthread_mutex_destroy(&enclave->mutex); diff --git a/host/optee/linux/enclave.h b/host/optee/linux/enclave.h index a9f25c18ba..5ce1189a44 100644 --- a/host/optee/linux/enclave.h +++ b/host/optee/linux/enclave.h @@ -10,6 +10,7 @@ #include #include +#include "../../ecall_ids.h" #define ENCLAVE_MAGIC 0x85ab45987c7ef1e3 @@ -39,6 +40,11 @@ struct _oe_enclave /* Array of ocall functions */ const oe_ocall_func_t* ocalls; size_t num_ocalls; + + /* Table of global to local ecall ids */ + oe_ecall_id_t* ecall_id_table; + size_t ecall_id_table_size; + size_t num_ecalls; }; #endif /* _OE_HOST_ENCLAVE_H */ diff --git a/host/sgx/create.c b/host/sgx/create.c index e86558909d..f9f17afdee 100644 --- a/host/sgx/create.c +++ b/host/sgx/create.c @@ -863,6 +863,40 @@ oe_result_t oe_sgx_build_enclave( return result; } +oe_result_t oe_get_ecall_id_table( + oe_enclave_t* enclave, + oe_ecall_id_t** ecall_id_table, + uint64_t* ecall_id_table_size) +{ + oe_result_t result = OE_UNEXPECTED; + if (!enclave || !ecall_id_table || !ecall_id_table_size) + OE_RAISE(OE_INVALID_PARAMETER); + + *ecall_id_table = enclave->ecall_id_table; + *ecall_id_table_size = enclave->ecall_id_table_size; + result = OE_OK; + +done: + return result; +} + +oe_result_t oe_set_ecall_id_table( + oe_enclave_t* enclave, + oe_ecall_id_t* ecall_id_table, + uint64_t ecall_id_table_size) +{ + oe_result_t result = OE_UNEXPECTED; + if (!enclave || !ecall_id_table || !ecall_id_table_size) + OE_RAISE(OE_INVALID_PARAMETER); + + enclave->ecall_id_table = ecall_id_table; + enclave->ecall_id_table_size = ecall_id_table_size; + result = OE_OK; + +done: + return result; +} + #if !defined(OEHOSTMR) /* ** This method encapsulates all steps of the enclave creation process: @@ -887,6 +921,8 @@ oe_result_t oe_create_enclave( uint32_t setting_count, const oe_ocall_func_t* ocall_table, uint32_t ocall_count, + const oe_ecall_info_t* ecall_name_table, + uint32_t ecall_count, oe_enclave_t** enclave_out) { oe_result_t result = OE_UNEXPECTED; @@ -1002,6 +1038,10 @@ oe_result_t oe_create_enclave( enclave->ocalls = (const oe_ocall_func_t*)ocall_table; enclave->num_ocalls = ocall_count; + /* Register ecalls */ + enclave->num_ecalls = ecall_count; + oe_register_ecalls(enclave, ecall_name_table, ecall_count); + /* Invoke enclave initialization. */ OE_CHECK(_initialize_enclave(enclave)); @@ -1061,6 +1101,10 @@ oe_result_t oe_terminate_enclave(oe_enclave_t* enclave) free(enclave->debug_enclave); } + /* Destroy the ecall id table */ + if (enclave->ecall_id_table) + free(enclave->ecall_id_table); + /* Once the enclave destructor has been invoked, the enclave memory * and data structures are freed on a best effort basis from here on */ diff --git a/host/sgx/enclave.h b/host/sgx/enclave.h index 69d7e15273..4a9d824a13 100644 --- a/host/sgx/enclave.h +++ b/host/sgx/enclave.h @@ -12,6 +12,7 @@ #include #include #include +#include "../ecall_ids.h" #include "../hostthread.h" #include "asmdefs.h" @@ -127,6 +128,11 @@ typedef struct _oe_enclave /* Manager for switchless calls */ oe_switchless_call_manager_t* switchless_manager; + + /* Table of global to local ecall ids */ + oe_ecall_id_t* ecall_id_table; + size_t ecall_id_table_size; + size_t num_ecalls; } oe_enclave_t; /* Get the event for the given TCS */ diff --git a/host/sgx/switchless.c b/host/sgx/switchless.c index 88df577b24..07b4922d6b 100644 --- a/host/sgx/switchless.c +++ b/host/sgx/switchless.c @@ -353,16 +353,15 @@ void oe_sgx_wake_switchless_worker_ocall(oe_host_worker_context_t* context) /* **============================================================================== ** -** oe_switchless_call_enclave_function() +** _switchless_call_enclave_function_impl() ** -** Switchlessly call the enclave function specified by the given function-id in -** the function table. +** Switchlessly call the enclave function specified by the given function-id. ** **============================================================================== */ -oe_result_t oe_switchless_call_enclave_function( +static oe_result_t _switchless_call_enclave_function_impl( oe_enclave_t* enclave, - uint32_t function_id, + uint64_t function_id, const void* input_buffer, size_t input_buffer_size, void* output_buffer, @@ -470,3 +469,40 @@ oe_result_t oe_switchless_call_enclave_function( done: return result; } + +/* +**============================================================================== +** +** oe_switchless_call_enclave_function() +** +** Switchlessly call the enclave function specified by the given function-id in +** the default function table. +** +**============================================================================== +*/ +oe_result_t oe_switchless_call_enclave_function( + oe_enclave_t* enclave, + uint64_t* global_id, + const char* name, + const void* input_buffer, + size_t input_buffer_size, + void* output_buffer, + size_t output_buffer_size, + size_t* output_bytes_written) +{ + oe_result_t result = OE_UNEXPECTED; + uint64_t function_id = OE_UINT64_MAX; + + OE_CHECK(oe_get_ecall_ids(enclave, name, global_id, &function_id)); + + result = _switchless_call_enclave_function_impl( + enclave, + function_id, + input_buffer, + input_buffer_size, + output_buffer, + output_buffer_size, + output_bytes_written); +done: + return result; +} diff --git a/include/openenclave/edger8r/host.h b/include/openenclave/edger8r/host.h index 3fb514f5a5..c651ff5fa9 100644 --- a/include/openenclave/edger8r/host.h +++ b/include/openenclave/edger8r/host.h @@ -30,6 +30,9 @@ OE_EXTERNC_BEGIN +#define OE_GLOBAL_ECALL_ID_NULL OE_UINT64_MAX +#define OE_ECALL_ID_NULL OE_UINT64_MAX + /** * Perform a high-level enclave function call (ECALL). * @@ -46,7 +49,8 @@ OE_EXTERNC_BEGIN * the call and not of the underlying function. The ECALL implementation must * define its own error reporting scheme via the arguments or return value. * - * @param function_id The id of the enclave function that will be called. + * @param global_id The global id of the enclave function that will be called. + * @param name The name of the function that will be called. * @param input_buffer Buffer containing inputs data. * @param input_buffer_size Size of the input data buffer. * @param output_buffer Buffer where the outputs of the host function are @@ -64,7 +68,8 @@ OE_EXTERNC_BEGIN */ oe_result_t oe_call_enclave_function( oe_enclave_t* enclave, - uint32_t function_id, + uint64_t* global_id, + const char* name, const void* input_buffer, size_t input_buffer_size, void* output_buffer, @@ -76,7 +81,8 @@ oe_result_t oe_call_enclave_function( */ oe_result_t oe_switchless_call_enclave_function( oe_enclave_t* enclave, - uint32_t function_id, + uint64_t* global_id, + const char* name, const void* input_buffer, size_t input_buffer_size, void* output_buffer, @@ -96,6 +102,18 @@ OE_INLINE void* oe_malloc(size_t size) return malloc(size); } +OE_INLINE +void oe_free(void* ptr) +{ + free(ptr); +} + +OE_INLINE +void* oe_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + OE_INLINE size_t oe_strlen(const char* s) { return strlen(s); diff --git a/include/openenclave/host.h b/include/openenclave/host.h index e1f05257e0..05f8fa4c3e 100644 --- a/include/openenclave/host.h +++ b/include/openenclave/host.h @@ -138,6 +138,14 @@ typedef struct _oe_enclave_setting } u; } oe_enclave_setting_t; +/** + * Structure describing an ecall. + */ +typedef struct _oe_ecall_info_t +{ + const char* name; +} oe_ecall_info_t; + /** * Create an enclave from an enclave image file. * @@ -167,6 +175,10 @@ typedef struct _oe_enclave_setting * * @param[in] ocall_count The number of functions in the **ocall_table**. * + * @param[in] ecall_name_table Table of ecall names. + * + * @param[i] ecall_count Number of ecalls. + * * @param[out] enclave This points to the enclave instance upon success. * * @returns Returns OE_OK on success. @@ -180,6 +192,8 @@ oe_result_t oe_create_enclave( uint32_t setting_count, const oe_ocall_func_t* ocall_table, uint32_t ocall_count, + const oe_ecall_info_t* ecall_name_table, + uint32_t ecall_count, oe_enclave_t** enclave); /** diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index abba82922a..46fdab1c89 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -88,6 +88,7 @@ if (UNIX add_subdirectory(custom_claims) add_subdirectory(debug-mode) add_subdirectory(ecall) + add_subdirectory(ecall_conflict) add_subdirectory(ecall_ocall) add_subdirectory(echo) add_subdirectory(enclaveparam) diff --git a/tests/ecall_conflict/CMakeLists.txt b/tests/ecall_conflict/CMakeLists.txt new file mode 100644 index 0000000000..d766195931 --- /dev/null +++ b/tests/ecall_conflict/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +if (BUILD_ENCLAVES) + add_subdirectory(enc1) + add_subdirectory(enc2) +endif () +add_subdirectory(host) + +add_enclave_test(tests/ecall_conflict ecall_conflict_host ecall_conflict_enc1 + enc/ecall_conflict_enc2) diff --git a/tests/ecall_conflict/common.edl b/tests/ecall_conflict/common.edl new file mode 100644 index 0000000000..a2de5a2258 --- /dev/null +++ b/tests/ecall_conflict/common.edl @@ -0,0 +1,38 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +enclave { + + // Define a struct to ensure that multiple definition error does not occur. + struct MyStruct { + int x; + int64_t y; + }; + + // Define a union to ensure that multiple definition error does not occur. + union MyUnion { + int x; + int64_t y; + }; + + // Define an enum to ensure that multiple definition error does not occur. + enum MyEnum { + RED, + GREEN = 10, + BLUE + }; + + trusted { + // Common ecalls. + public void enc_ecall1(MyStruct s); + public void enc_ecall2(MyUnion u); + public void enc_ecall3(MyEnum e); + }; + + untrusted { + // Common ocalls + void host_ocall1(MyStruct s); + void host_ocall2(MyUnion u); + void host_ocall3(MyEnum e); + }; +}; diff --git a/tests/ecall_conflict/enc1.edl b/tests/ecall_conflict/enc1.edl new file mode 100644 index 0000000000..557225aaa2 --- /dev/null +++ b/tests/ecall_conflict/enc1.edl @@ -0,0 +1,19 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +enclave { + // Import all functions. + from "common.edl" import *; + + from "openenclave/edl/logging.edl" import oe_write_ocall; + from "openenclave/edl/fcntl.edl" import *; +#ifdef OE_SGX + from "openenclave/edl/sgx/platform.edl" import *; +#else + from "openenclave/edl/optee/platform.edl" import *; +#endif + + trusted { + public int enc_local_ecall1(int val); + }; +}; diff --git a/tests/ecall_conflict/enc1/CMakeLists.txt b/tests/ecall_conflict/enc1/CMakeLists.txt new file mode 100644 index 0000000000..08d72ff2a8 --- /dev/null +++ b/tests/ecall_conflict/enc1/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +set(EDL_FILE enc1.edl) + +add_custom_command( + OUTPUT enc1_args.h enc1_t.h enc1_t.c + DEPENDS ../common.edl ../enc1.edl edger8r + COMMAND + edger8r --trusted ${EDL_FILE} --search-path ${PROJECT_SOURCE_DIR}/include + ${DEFINE_OE_SGX} --search-path ${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_enclave( + TARGET + ecall_conflict_enc1 + UUID + 71b0822f-42a3-4543-a97c-ca491f76b82c + SOURCES + enc.c + ${CMAKE_CURRENT_BINARY_DIR}/enc1_t.c) + +enclave_include_directories(ecall_conflict_enc1 PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) +enclave_link_libraries(ecall_conflict_enc1 oelibc) + +# Linux enclave build/windows host testing requires enclaves to be in enc folder +set_enclave_property( + TARGET ecall_conflict_enc1 PROPERTIES RUNTIME_OUTPUT_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}/../enc) diff --git a/tests/ecall_conflict/enc1/enc.c b/tests/ecall_conflict/enc1/enc.c new file mode 100644 index 0000000000..aba62947d4 --- /dev/null +++ b/tests/ecall_conflict/enc1/enc.c @@ -0,0 +1,38 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include +#include "enc1_t.h" + +void enc_ecall1(MyStruct s) +{ + OE_TEST(s.x == 5); + OE_TEST(s.y == 6); + OE_TEST(host_ocall1(s) == OE_OK); +} + +void enc_ecall2(MyUnion u) +{ + OE_TEST(u.y == 7); + OE_TEST(host_ocall2(u) == OE_OK); +} + +void enc_ecall3(MyEnum e) +{ + OE_TEST(e == GREEN); + OE_TEST(host_ocall3(e) == OE_OK); +} + +int enc_local_ecall1(int val) +{ + OE_TEST(val == 11); + return 12; +} + +OE_SET_ENCLAVE_SGX( + 1, /* ProductID */ + 1, /* SecurityVersion */ + true, /* Debug */ + 512, /* NumHeapPages */ + 512, /* NumStackPages */ + 1); /* NumTCS */ diff --git a/tests/ecall_conflict/enc2.edl b/tests/ecall_conflict/enc2.edl new file mode 100644 index 0000000000..5916061915 --- /dev/null +++ b/tests/ecall_conflict/enc2.edl @@ -0,0 +1,26 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +enclave { + // Selectively import calls and ocalls. + // All types are imported. + from "common.edl" import + enc_ecall2, + enc_ecall1, + host_ocall1, + host_ocall2; + + from "openenclave/edl/logging.edl" import oe_write_ocall; + from "openenclave/edl/fcntl.edl" import *; +#ifdef OE_SGX + from "openenclave/edl/sgx/platform.edl" import *; +#else + from "openenclave/edl/optee/platform.edl" import *; +#endif + + + + trusted { + public int enc_local_ecall2(int val); + }; +}; diff --git a/tests/ecall_conflict/enc2/CMakeLists.txt b/tests/ecall_conflict/enc2/CMakeLists.txt new file mode 100644 index 0000000000..a6b1efde58 --- /dev/null +++ b/tests/ecall_conflict/enc2/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +set(EDL_FILE enc2.edl) + +add_custom_command( + OUTPUT enc2_args.h enc2_t.h enc2_t.c + DEPENDS ../common.edl ../enc2.edl edger8r + COMMAND + edger8r --trusted ${EDL_FILE} --search-path ${PROJECT_SOURCE_DIR}/include + ${DEFINE_OE_SGX} --search-path ${CMAKE_CURRENT_SOURCE_DIR}/..) + +add_enclave( + TARGET + ecall_conflict_enc2 + UUID + 71b0822f-42a3-4543-a97c-ca491f76b82c + SOURCES + enc.c + ${CMAKE_CURRENT_BINARY_DIR}/enc2_t.c) + +enclave_include_directories(ecall_conflict_enc2 PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) +enclave_link_libraries(ecall_conflict_enc2 oelibc) + +# Linux enclave build/windows host testing requires enclaves to be in enc folder +set_enclave_property( + TARGET ecall_conflict_enc2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR}/../enc) diff --git a/tests/ecall_conflict/enc2/enc.c b/tests/ecall_conflict/enc2/enc.c new file mode 100644 index 0000000000..c360e113c6 --- /dev/null +++ b/tests/ecall_conflict/enc2/enc.c @@ -0,0 +1,32 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include +#include "enc2_t.h" + +void enc_ecall1(MyStruct s) +{ + OE_TEST(s.x == 8); + OE_TEST(s.y == 9); + OE_TEST(host_ocall1(s) == OE_OK); +} + +void enc_ecall2(MyUnion u) +{ + OE_TEST(u.y == 10); + OE_TEST(host_ocall2(u) == OE_OK); +} + +int enc_local_ecall2(int val) +{ + OE_TEST(val == 13); + return 14; +} + +OE_SET_ENCLAVE_SGX( + 1, /* ProductID */ + 1, /* SecurityVersion */ + true, /* Debug */ + 512, /* NumHeapPages */ + 512, /* NumStackPages */ + 1); /* NumTCS */ diff --git a/tests/ecall_conflict/host/CMakeLists.txt b/tests/ecall_conflict/host/CMakeLists.txt new file mode 100644 index 0000000000..68709644f8 --- /dev/null +++ b/tests/ecall_conflict/host/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) Open Enclave SDK contributors. Licensed under the MIT License. + +add_custom_command( + OUTPUT enc1_args.h enc1_u.h enc1_u.c enc2_args.h enc2_u.h enc2_u.c + COMMAND + edger8r --untrusted enc1.edl enc2.edl ${DEFINE_OE_SGX} --search-path + ${PROJECT_SOURCE_DIR}/include --search-path ${CMAKE_CURRENT_SOURCE_DIR}/.. + DEPENDS ../common.edl ../enc1.edl ../enc2.edl edger8r) + +add_executable(ecall_conflict_host enc1_u.c enc2_u.c host.cpp) + +target_include_directories(ecall_conflict_host + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(ecall_conflict_host oehost) diff --git a/tests/ecall_conflict/host/host.cpp b/tests/ecall_conflict/host/host.cpp new file mode 100644 index 0000000000..07a2bdaaa5 --- /dev/null +++ b/tests/ecall_conflict/host/host.cpp @@ -0,0 +1,238 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include + +#include +#include "../../../host/ecall_ids.h" +// Ensure that there are no multiple definition errors for user defined types. +#include "enc1_u.h" +#include "enc2_u.h" + +MyStruct g_s = {5, 6}; +MyUnion g_u = {7}; +MyEnum g_e = GREEN; + +void host_ocall1(MyStruct s) +{ + OE_TEST(s.x == g_s.x); + OE_TEST(s.y == g_s.y); +} + +void host_ocall2(MyUnion u) +{ + OE_TEST(u.y == g_u.y); +} + +void host_ocall3(MyEnum e) +{ + OE_TEST(e == g_e); +} + +int main(int argc, char** argv) +{ + oe_enclave_t* enc1 = NULL; + oe_enclave_t* enc2 = NULL; + + const uint32_t flags = oe_get_create_flags(); + uint64_t global_id = OE_GLOBAL_ECALL_ID_NULL; + uint64_t local_id = OE_UINT64_MAX; + int val; + + if (argc != 3) + { + fprintf(stderr, "Usage: %s ENCLAVE1_PATH ENCLAVE2_PATH\n", argv[0]); + return 1; + } + + OE_TEST( + oe_create_enc1_enclave( + argv[1], OE_ENCLAVE_TYPE_SGX, flags, NULL, 0, &enc1) == OE_OK); + + /* + * Use the internal APIs to test the global and local ids. + * At this point the expected global table should be: + * global id 0 - "enc_local_ecall1" + * global id 1 - "enc_ecall1" + * global id 2 - "enc_ecall2" + * global id 3 - "enc_ecall3" + * The local (per-enclave) table should be: + * [global id 0]: 0 + * [global id 1]: 1 + * [global id 2]: 2 + * [global id 3]: 3 + */ + OE_TEST(oe_get_global_id("enc_local_ecall1", &global_id) == OE_OK); + OE_TEST(global_id == 0); + OE_TEST(oe_get_global_id("enc_ecall1", &global_id) == OE_OK); + OE_TEST(global_id == 1); + OE_TEST(oe_get_global_id("enc_ecall2", &global_id) == OE_OK); + OE_TEST(global_id == 2); + OE_TEST(oe_get_global_id("enc_ecall3", &global_id) == OE_OK); + OE_TEST(global_id == 3); + + /* Look up by global id. The name should not be NULL. */ + global_id = 0; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_local_ecall1", &global_id, &local_id) == + OE_OK); + OE_TEST(local_id == 0); + global_id = 1; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_ecall1", &global_id, &local_id) == OE_OK); + OE_TEST(local_id == 1); + global_id = 2; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_ecall2", &global_id, &local_id) == OE_OK); + OE_TEST(local_id == 2); + global_id = 3; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_ecall3", &global_id, &local_id) == OE_OK); + OE_TEST(local_id == 3); + + /* Look up by name. The global id will be set. */ + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_local_ecall1", &global_id, &local_id) == + OE_OK); + OE_TEST(global_id == 0); + OE_TEST(local_id == 0); + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_ecall1", &global_id, &local_id) == OE_OK); + OE_TEST(global_id == 1); + OE_TEST(local_id == 1); + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_ecall2", &global_id, &local_id) == OE_OK); + OE_TEST(global_id == 2); + OE_TEST(local_id == 2); + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc1, "enc_ecall3", &global_id, &local_id) == OE_OK); + OE_TEST(global_id == 3); + OE_TEST(local_id == 3); + + OE_TEST( + oe_create_enc2_enclave( + argv[2], OE_ENCLAVE_TYPE_SGX, flags, NULL, 0, &enc2) == OE_OK); + + /* Assert id of last imported system ecall, Since the first enclave imports + * system edls, the system ecalls will take up the next few global ids. */ + uint64_t last_system_ecall_id = 0; + OE_TEST( + oe_get_global_id( + "oe_sgx_switchless_enclave_worker_thread_ecall", + &last_system_ecall_id) == OE_OK); + OE_TEST(last_system_ecall_id == 8); + + /* + * Use the internal APIs to test the global and local ids. + * After creating enc2, the expected global table should be: + * global id 0 - "enc_local_ecall1" + * global id 1 - "enc_ecall1" + * global id 2 - "enc_ecall2" + * global id 3 - "enc_ecall3" + * system ecalls ... + * global id 9 - "enc_local_ecall2" + * The local (per-enclave) table should be: + * [global id 0]: ECALL_ID_NULL + * [global id 1]: 2 + * [global id 2]: 1 + * [global id 3]: ECALL_ID_NULL + * ... (system ecalls) + * [global id 9]: 0 + */ + OE_TEST(oe_get_global_id("enc_local_ecall1", &global_id) == OE_OK); + OE_TEST(global_id == 0); + OE_TEST(oe_get_global_id("enc_ecall1", &global_id) == OE_OK); + OE_TEST(global_id == 1); + OE_TEST(oe_get_global_id("enc_ecall2", &global_id) == OE_OK); + OE_TEST(global_id == 2); + OE_TEST(oe_get_global_id("enc_ecall3", &global_id) == OE_OK); + OE_TEST(global_id == 3); + OE_TEST(oe_get_global_id("enc_local_ecall2", &global_id) == OE_OK); + OE_TEST(global_id == 9); + + /* + * Look up by global id. The name should not be NULL. + * The result of using "enc_local_ecall1" and "enc_ecall3" should + * return OE_NOT_FOUND. + */ + global_id = 0; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_local_ecall1", &global_id, &local_id) == + OE_NOT_FOUND); + OE_TEST(local_id == OE_ECALL_ID_NULL); + global_id = 1; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_ecall1", &global_id, &local_id) == OE_OK); + OE_TEST(local_id == 2); + global_id = 2; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_ecall2", &global_id, &local_id) == OE_OK); + OE_TEST(local_id == 1); + global_id = 3; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_ecall3", &global_id, &local_id) == + OE_NOT_FOUND); + OE_TEST(local_id == OE_ECALL_ID_NULL); + global_id = 9; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_local_ecall2", &global_id, &local_id) == + OE_OK); + OE_TEST(local_id == 0); + + /* Look up by name. The global id will be set. */ + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_local_ecall1", &global_id, &local_id) == + OE_NOT_FOUND); + OE_TEST(global_id == 0); + OE_TEST(local_id == OE_ECALL_ID_NULL); + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_ecall1", &global_id, &local_id) == OE_OK); + OE_TEST(global_id == 1); + OE_TEST(local_id == 2); + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_ecall2", &global_id, &local_id) == OE_OK); + OE_TEST(global_id == 2); + OE_TEST(local_id == 1); + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_ecall3", &global_id, &local_id) == + OE_NOT_FOUND); + OE_TEST(global_id == 3); + OE_TEST(local_id == OE_ECALL_ID_NULL); + global_id = OE_GLOBAL_ECALL_ID_NULL; + OE_TEST( + oe_get_ecall_ids(enc2, "enc_local_ecall2", &global_id, &local_id) == + OE_OK); + OE_TEST(global_id == 9); + OE_TEST(local_id == 0); + + /* Make the normal ecalls. */ + + // Call functions in enclave 1. + OE_TEST(enc_ecall1(enc1, g_s) == OE_OK); + OE_TEST(enc_ecall2(enc1, g_u) == OE_OK); + OE_TEST(enc_ecall3(enc1, g_e) == OE_OK); + + // Change values for enclave 2. + g_s = {8, 9}; + g_u.y = 10; + OE_TEST(enc_ecall1(enc2, g_s) == OE_OK); + OE_TEST(enc_ecall2(enc2, g_u) == OE_OK); + + OE_TEST(enc_local_ecall1(enc1, &val, 11) == OE_OK); + OE_TEST(val == 12); + OE_TEST(enc_local_ecall2(enc2, &val, 13) == OE_OK); + OE_TEST(val == 14); + + OE_TEST(oe_terminate_enclave(enc1) == OE_OK); + OE_TEST(oe_terminate_enclave(enc2) == OE_OK); + + printf("=== passed all tests (call_conflict)\n"); +} diff --git a/tests/oeedger8r/host/teststring.cpp b/tests/oeedger8r/host/teststring.cpp index 83c467ebdf..ce83e88d48 100644 --- a/tests/oeedger8r/host/teststring.cpp +++ b/tests/oeedger8r/host/teststring.cpp @@ -20,6 +20,8 @@ oe_result_t ecall_string_no_null_terminator_modified( { oe_result_t _result = OE_FAILURE; + static uint64_t global_id = OE_GLOBAL_ECALL_ID_NULL; + /* Marshalling struct */ ecall_string_no_null_terminator_args_t _args, *_pargs_in = NULL, *_pargs_out = NULL; @@ -82,7 +84,9 @@ oe_result_t ecall_string_no_null_terminator_modified( /* Call enclave function */ if ((_result = oe_call_enclave_function( enclave, - all_fcn_id_ecall_string_no_null_terminator, + &global_id, + __all_ecall_info_table[all_fcn_id_ecall_string_no_null_terminator] + .name, _input_buffer, _input_buffer_size, _output_buffer, @@ -126,6 +130,8 @@ oe_result_t ecall_wstring_no_null_terminator_modified( { oe_result_t _result = OE_FAILURE; + static uint64_t global_id = OE_GLOBAL_ECALL_ID_NULL; + /* Marshalling struct */ ecall_wstring_no_null_terminator_args_t _args, *_pargs_in = NULL, *_pargs_out = NULL; @@ -188,7 +194,9 @@ oe_result_t ecall_wstring_no_null_terminator_modified( /* Call enclave function */ if ((_result = oe_call_enclave_function( enclave, - all_fcn_id_ecall_wstring_no_null_terminator, + &global_id, + __all_ecall_info_table[all_fcn_id_ecall_wstring_no_null_terminator] + .name, _input_buffer, _input_buffer_size, _output_buffer, diff --git a/tools/oeedger8r-cpp b/tools/oeedger8r-cpp index 7ef01ca6c2..804e97fac2 160000 --- a/tools/oeedger8r-cpp +++ b/tools/oeedger8r-cpp @@ -1 +1 @@ -Subproject commit 7ef01ca6c20e849de27139ac44800a2475fb5cdb +Subproject commit 804e97fac221a481d6c25e006cc171ff32d58928