Skip to content

Commit

Permalink
ECALL Implementation: Support global ids
Browse files Browse the repository at this point in the history
Design doc: https://github.com/openenclave/openenclave/blob/master/docs/DesignDocs/TEECallsRefactoring.md

Bring in @mingweishih's implementation of global ids for ECALLs.
With this change, ECALL dispatching will now work in case two enclaves
import system ECALLs in different order. Currently, ECALL dispatching would
fail at runtime in such a scenario.

Changes:
- Update edger8r submodule
- Implement functions to compute global ids for ECALLs based on name
- Update enclave structure and enclave initialization for both SGX and OPTEE
- Added test to lockdown global ids and local ids.

Signed-off-by: Anand Krishnamoorthi <[email protected]>
  • Loading branch information
anakrish committed Sep 3, 2020
1 parent 3392e9a commit 6797704
Show file tree
Hide file tree
Showing 24 changed files with 989 additions and 16 deletions.
1 change: 1 addition & 0 deletions host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 49 additions & 5 deletions host/calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
#include <openenclave/internal/raise.h>

#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,
Expand Down Expand Up @@ -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;
}
206 changes: 206 additions & 0 deletions host/ecall_ids.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright (c) Open Enclave SDK contributors.
// Licensed under the MIT License.

#include "ecall_ids.h"
#include <openenclave/internal/raise.h>
#include <stdlib.h>
#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;
}
71 changes: 71 additions & 0 deletions host/ecall_ids.h
Original file line number Diff line number Diff line change
@@ -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 <openenclave/edger8r/host.h>
#include <openenclave/host.h>

#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 */
Loading

0 comments on commit 6797704

Please sign in to comment.