diff --git a/src/enclave/enclave_oe.c b/src/enclave/enclave_oe.c index 2662d0893..85cf05ae0 100644 --- a/src/enclave/enclave_oe.c +++ b/src/enclave/enclave_oe.c @@ -302,11 +302,25 @@ static void _read_eeid_config() const oe_eeid_t* eeid = (oe_eeid_t*)__oe_get_eeid(); const char* config_json = (const char*)eeid->data; - sgxlkl_enclave_config_t* cfg = oe_malloc(sizeof(sgxlkl_enclave_config_t)); - if (!cfg) - sgxlkl_fail("out of memory, cannot allocate enclave config.\n"); - sgxlkl_read_enclave_config(config_json, cfg, true); - sgxlkl_enclave_state.config = cfg; + size_t num_pages = 0; + const sgxlkl_enclave_config_page_t* cfg_pages = + sgxlkl_read_enclave_config(config_json, true, &num_pages); + + /* Make the config pages read-only */ + for (size_t i = 0; i < num_pages; i++) + { + int mprotect_ret; + sgxlkl_host_syscall_mprotect( + &mprotect_ret, + (void*)&cfg_pages[i], + sizeof(sgxlkl_enclave_config_t), + PROT_READ); + + if (mprotect_ret != 0) + sgxlkl_warn("Could not protect memory pages for config\n"); + } + + sgxlkl_enclave_state.config = &cfg_pages->config; } static void _copy_shared_memory(const sgxlkl_shared_memory_t* host) diff --git a/src/include/shared/oe_compat.h b/src/include/shared/oe_compat.h index 2ca0262b1..cbacb4215 100644 --- a/src/include/shared/oe_compat.h +++ b/src/include/shared/oe_compat.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #define malloc oe_malloc @@ -21,11 +22,13 @@ #define strtok_r oe_strtok_r #define snprintf oe_snprintf #define strtoul oe_strtoul +#define memalign oe_memalign #else #include #include +#include #include #include #include diff --git a/src/include/shared/sgxlkl_enclave_config.h b/src/include/shared/sgxlkl_enclave_config.h index 669cb9925..1f2d38a69 100644 --- a/src/include/shared/sgxlkl_enclave_config.h +++ b/src/include/shared/sgxlkl_enclave_config.h @@ -7,14 +7,23 @@ /* Maximum path length of mount points for secondary disks */ #define SGXLKL_DISK_MNT_MAX_PATH_LEN 255 +#include + #include -void sgxlkl_read_enclave_config( +struct config_page +{ + sgxlkl_enclave_config_t config; +} __attribute__((__aligned__(OE_PAGE_SIZE))); + +typedef struct config_page sgxlkl_enclave_config_page_t; + +const sgxlkl_enclave_config_page_t* sgxlkl_read_enclave_config( const char* from, - sgxlkl_enclave_config_t* to, - bool enforce_format); + bool enforce_format, + size_t* num_pages); -void sgxlkl_free_enclave_config(sgxlkl_enclave_config_t* enclave_config); +void sgxlkl_free_enclave_config_page(sgxlkl_enclave_config_page_t* config_page); /* Check if a disk is configured for encrypted operation */ bool is_encrypted(sgxlkl_enclave_mount_config_t* cfg); diff --git a/src/main-oe/sgxlkl_run_oe.c b/src/main-oe/sgxlkl_run_oe.c index 68ebad2da..d459c17ea 100644 --- a/src/main-oe/sgxlkl_run_oe.c +++ b/src/main-oe/sgxlkl_run_oe.c @@ -1467,7 +1467,9 @@ void enclave_config_from_file(const char* filename) if (ret < 0) sgxlkl_host_fail("Failed to read %s: %s.\n", filename, strerror(errno)); - sgxlkl_read_enclave_config(buf, &sgxlkl_host_state.enclave_config, false); + const sgxlkl_enclave_config_page_t* config_page = + sgxlkl_read_enclave_config(buf, false, NULL); + sgxlkl_host_state.enclave_config = *(sgxlkl_enclave_config_t*)config_page; } void override_enclave_config( diff --git a/src/shared/sgxlkl_enclave_config.c b/src/shared/sgxlkl_enclave_config.c index f751d87e3..9e39a132e 100644 --- a/src/shared/sgxlkl_enclave_config.c +++ b/src/shared/sgxlkl_enclave_config.c @@ -8,32 +8,34 @@ #define WARN sgxlkl_host_warn #endif +#include + #include #include #include #include #include -#define CHECKMEM(C) \ - if (!C) \ - FAIL("out of memory\n"); - // Duplicate a string (including NULL) -static int strdupz(char** to, const char* from) +static int strdupz( + char** to, + const char* from, + uint8_t** bytes, + size_t* bytes_remaining) { if (!to) return 1; else if (!from) - { *to = NULL; - return 0; - } else { - size_t l = strlen(from); - *to = malloc(l + 1); - CHECKMEM(*to); - memcpy(*to, from, l + 1); + size_t sz = strlen(from) + 1; + if (*bytes_remaining < sz) + FAIL("out of memory\n"); + memcpy(*bytes, from, sz); + *to = (char*)*bytes; + *bytes_remaining -= sz; + *bytes += sz; } return 0; } @@ -44,6 +46,9 @@ typedef struct json_callback_data unsigned long index; string_list_t* seen; bool enforce_format; + + uint8_t* bytes; + size_t bytes_remaining; } json_callback_data_t; static char* make_path(json_parser_t* parser) @@ -67,8 +72,13 @@ static char* make_path(json_parser_t* parser) } } - char* r = NULL; - strdupz(&r, tmp); + size_t sz = strlen(tmp) + 1; + char* r = malloc(sz); + if (!r) + FAIL("out of memory\n"); + char* t = r; + if (strdupz(&r, tmp, (uint8_t**)&t, &sz) != 0) + return NULL; return r; } @@ -124,10 +134,16 @@ static char* make_path(json_parser_t* parser) return JSON_OK; \ } -#define JSTRING(PATH, DEST) \ - JPATH2T(PATH, JSON_TYPE_STRING, JSON_TYPE_NULL, { \ - if (strdupz(&(DEST), un ? un->string : NULL)) \ - return JSON_FAILED; \ +#define JSTRING(PATH, DEST) \ + JPATH2T(PATH, JSON_TYPE_STRING, JSON_TYPE_NULL, { \ + json_callback_data_t* cbd = \ + (json_callback_data_t*)parser->callback_data; \ + if (strdupz( \ + &(DEST), \ + un ? un->string : NULL, \ + &cbd->bytes, \ + &cbd->bytes_remaining)) \ + return JSON_FAILED; \ }); static json_result_t decode_safe_uint64_t( @@ -229,10 +245,13 @@ static json_result_t decode_uint32_t( else \ { \ DEST##_len = l / 2; \ - DEST = calloc(1, DEST##_len); \ - CHECKMEM(DEST); \ + if (data->bytes_remaining < DEST##_len) \ + return JSON_OUT_OF_MEMORY; \ + DEST = data->bytes; \ for (size_t i = 0; i < DEST##_len; i++) \ DEST[i] = hex_to_int(un->string + 2 * i, 2); \ + data->bytes_remaining -= DEST##_len; \ + data->bytes += DEST##_len; \ } \ } \ }); @@ -243,12 +262,16 @@ static json_result_t decode_uint32_t( #define JU64(P, D) JPATH(P, return decode_uint64_t(parser, type, un, &D)); #define JU32(P, D) JPATH(P, return decode_uint32_t(parser, type, un, &D)); -#define ALLOC_ARRAY(N, A, T) \ - do \ - { \ - data->config->N = un->integer; \ - data->config->A = calloc(un->integer, sizeof(T)); \ - CHECKMEM(data->config->A); \ +#define ALLOC_ARRAY(N, A, T) \ + do \ + { \ + data->config->N = un->integer; \ + size_t sz = un->integer * sizeof(T); \ + if (data->bytes_remaining < sz) \ + return JSON_OUT_OF_MEMORY; \ + data->config->A = (T*)data->bytes; \ + data->bytes_remaining -= sz; \ + data->bytes += sz; \ } while (0) static sgxlkl_enclave_mount_config_t* _mount( @@ -382,13 +405,25 @@ static json_result_t json_read_callback( JSTRING("cwd", cfg->cwd); JPATHT("args", JSON_TYPE_STRING, { - strdupz(&cfg->args[i], un->string); + strdupz( + &cfg->args[i], + un->string, + &data->bytes, + &data->bytes_remaining); }); JPATHT("env", JSON_TYPE_STRING, { - strdupz(&cfg->env[i], un->string); + strdupz( + &cfg->env[i], + un->string, + &data->bytes, + &data->bytes_remaining); }); JPATHT("host_import_env", JSON_TYPE_STRING, { - strdupz(&cfg->host_import_env[i], un->string); + strdupz( + &cfg->host_import_env[i], + un->string, + &data->bytes, + &data->bytes_remaining); }); JPATHT("exit_status", JSON_TYPE_STRING, { @@ -488,10 +523,10 @@ void check_required_elements(string_list_t* seen) } } -void sgxlkl_read_enclave_config( +const sgxlkl_enclave_config_page_t* sgxlkl_read_enclave_config( const char* from, - sgxlkl_enclave_config_t* to, - bool enforce_format) + bool enforce_format, + size_t* num_pages_out) { // Catch modifications to sgxlkl_enclave_config_t early. If this fails, // the code above/below needs adjusting for the added/removed settings. @@ -502,23 +537,35 @@ void sgxlkl_read_enclave_config( if (!from) FAIL("No config to read\n"); - if (!to) - FAIL("No config to write to\n"); + size_t num_pages = (strlen(from) / OE_PAGE_SIZE) + 1; + sgxlkl_enclave_config_page_t* config_page = + memalign(OE_PAGE_SIZE, num_pages * OE_PAGE_SIZE); + memset(config_page, 0, OE_PAGE_SIZE); + if (!config_page) + FAIL("out of memory\n"); + config_page->config = sgxlkl_enclave_config_default; - *to = sgxlkl_enclave_config_default; + if (num_pages_out) + *num_pages_out = num_pages; json_parser_t parser; json_parser_options_t options; options.allow_whitespace = !enforce_format; json_result_t r = JSON_UNEXPECTED; - json_callback_data_t callback_data = {.config = to, - .index = 0, - .seen = NULL, - .enforce_format = enforce_format}; + size_t config_size = sizeof(sgxlkl_enclave_config_t); + json_callback_data_t callback_data = { + .config = &config_page->config, + .index = 0, + .seen = NULL, + .enforce_format = enforce_format, + .bytes = (uint8_t*)(&config_page->config) + config_size, + .bytes_remaining = OE_PAGE_SIZE - config_size}; // parser destroys `from`, so we copy it first. size_t json_len = strlen(from); char* json_copy = malloc(sizeof(char) * (json_len + 1)); + if (!json_copy) + FAIL("out of memory\n"); memcpy(json_copy, from, json_len); json_allocator_t allocator = {.ja_malloc = malloc, .ja_free = free}; @@ -544,61 +591,15 @@ void sgxlkl_read_enclave_config( if (enforce_format) check_required_elements(callback_data.seen); - check_config(to); + check_config(&config_page->config); string_list_free(callback_data.seen, true); + return config_page; } -#define NONDEFAULT_FREE(X) \ - if (config->X != default_config->X) \ - free(config->X); - -void sgxlkl_free_enclave_config(sgxlkl_enclave_config_t* config) +void sgxlkl_free_enclave_config_page(sgxlkl_enclave_config_page_t* config_page) { - const sgxlkl_enclave_config_t* default_config = - &sgxlkl_enclave_config_default; - - NONDEFAULT_FREE(net_ip4); - NONDEFAULT_FREE(net_gw4); - NONDEFAULT_FREE(net_mask4); - NONDEFAULT_FREE(hostname); - - NONDEFAULT_FREE(wg.ip); - for (size_t i = 0; i < config->wg.num_peers; i++) - { - free(config->wg.peers[i].key); - free(config->wg.peers[i].allowed_ips); - free(config->wg.peers[i].endpoint); - } - NONDEFAULT_FREE(wg.peers); - - NONDEFAULT_FREE(kernel_cmd); - NONDEFAULT_FREE(sysctl); - NONDEFAULT_FREE(cwd); - - for (size_t i = 0; i < config->num_args; i++) - free(config->args[i]); - NONDEFAULT_FREE(args); - - for (size_t i = 0; i < config->num_env; i++) - free(config->env[i]); - NONDEFAULT_FREE(env); - - for (size_t i = 0; i < config->num_host_import_env; i++) - free(config->host_import_env[i]); - NONDEFAULT_FREE(host_import_env); - - NONDEFAULT_FREE(root.key); - NONDEFAULT_FREE(root.key_id); - NONDEFAULT_FREE(root.roothash); - - for (size_t i = 0; i < config->num_mounts; i++) - { - free(config->mounts[i].key); - free(config->mounts[i].key_id); - free(config->mounts[i].roothash); - } - NONDEFAULT_FREE(mounts); - free(config); + /* frees the entire config, including all strings */ + free(config_page); } bool is_encrypted(sgxlkl_enclave_mount_config_t* cfg)