diff --git a/include/compartment.h b/include/compartment.h index ccd53ef..6d0dd12 100644 --- a/include/compartment.h +++ b/include/compartment.h @@ -180,6 +180,10 @@ struct Compartment void *mem_top; bool mapped; + // Environ + char **environ_ptr; + size_t environ_sz; + // Scratch memory void *scratch_mem_base; size_t scratch_mem_size; diff --git a/src/comp_utils.c b/src/comp_utils.c index 50a8a7e..bcb2ee5 100644 --- a/src/comp_utils.c +++ b/src/comp_utils.c @@ -68,6 +68,12 @@ realloc(void *to_realloc, size_t new_size) return new_alloc; } +void * +reallocarray(void *to_realloc, size_t elem_count, size_t elem_size) +{ + return realloc(to_realloc, elem_count * elem_size); +} + void tls_lookup_stub() { diff --git a/src/compartment.c b/src/compartment.c index 85c6d93..035ccac 100644 --- a/src/compartment.c +++ b/src/compartment.c @@ -4,6 +4,10 @@ const char *libs_path_env_var = "COMP_LIBRARY_PATH"; const char *tls_rtld_dropin = "tls_lookup_stub"; const char *comp_utils_soname = "libcomputils.so"; +extern char **proc_env_ptr; +extern const size_t max_env_sz; +extern const unsigned short max_env_count; + /******************************************************************************* * Forward declarations ******************************************************************************/ @@ -34,6 +38,10 @@ find_in_dir(const char *, char *); static void init_comp_scratch_mem(struct Compartment *); static void +adjust_comp_scratch_mem(struct Compartment *, size_t); +static void +setup_environ(struct Compartment *); +static void resolve_comp_tls_regions(struct Compartment *); static void @@ -157,6 +165,7 @@ comp_from_elf(char *filename, char **entry_points, size_t entry_point_count, assert(entry_point_count > 0); init_comp_scratch_mem(new_comp); + setup_environ(new_comp); find_comp_entry_points(entry_points, entry_point_count, new_comp); resolve_rela_syms(new_comp); resolve_comp_tls_regions(new_comp); @@ -223,6 +232,27 @@ comp_map(struct Compartment *to_map) err(1, "Error mapping compartment %zu scratch memory", to_map->id); } + /* Copy over environ variables + // + // We need a pointer to an array of string pointers, so we synthetically + // create one. We don't expect this pointer to move, as the maximum allowed + // size for the `environ` array is already allocated + */ + *to_map->environ_ptr = (char *) (to_map->environ_ptr + 1); + to_map->environ_ptr += 1; + + // Copy over prepared `environ` data from manager + memcpy(to_map->environ_ptr, proc_env_ptr, max_env_sz); + for (unsigned short i = 0; i < max_env_count; ++i) + { + if (*(to_map->environ_ptr + i) == 0x0) + { + break; + } + // Update entry offsets relative to compartment address + *(to_map->environ_ptr + i) += (uintptr_t) to_map->environ_ptr; + } + size_t tls_allocd = 0x0; for (size_t i = 0; i < to_map->libs_count; ++i) { @@ -758,17 +788,7 @@ parse_lib_rela(Elf64_Shdr *rela_shdr, Elf64_Ehdr *lib_ehdr, int lib_fd, // Filter out some `libc` symbols we don't want to handle // TODO at least right now - if (!strcmp(&dyn_str_tbl[curr_rela_sym.st_name], "environ")) - { - warnx("Currently not relocating symbol `environ` from " - "library " - "%s - " - "using within a container might cause a crash.", - lib_dep->lib_name); - continue; - } - else if (!strcmp( - &dyn_str_tbl[curr_rela_sym.st_name], "__progname")) + if (!strcmp(&dyn_str_tbl[curr_rela_sym.st_name], "__progname")) { warnx("Currently not relocating symbol `__progname` from " "library %s " @@ -900,6 +920,13 @@ resolve_rela_syms(struct Compartment *new_comp) continue; } + if (curr_rela_map->rela_name + && !strcmp(curr_rela_map->rela_name, "environ")) + { + curr_rela_map->target_func_address = new_comp->environ_ptr; + continue; + } + struct LibSymSearchResult found_sym = find_lib_dep_sym_in_comp(curr_rela_map->rela_name, new_comp, curr_rela_map->rela_sym_type); @@ -1061,6 +1088,23 @@ init_comp_scratch_mem(struct Compartment *new_comp) assert(new_comp->scratch_mem_size % 16 == 0); } +static void +adjust_comp_scratch_mem(struct Compartment *new_comp, size_t to_adjust) +{ + new_comp->scratch_mem_size += to_adjust; + new_comp->mem_top = (char *) new_comp->mem_top + to_adjust; +} + +static void +setup_environ(struct Compartment *new_comp) +{ + assert(proc_env_ptr != NULL); // TODO consider optional check + new_comp->environ_sz + = align_up(max_env_sz, new_comp->page_size) + new_comp->page_size; + new_comp->environ_ptr = new_comp->mem_top; + adjust_comp_scratch_mem(new_comp, new_comp->environ_sz); +} + static void resolve_comp_tls_regions(struct Compartment *new_comp) { @@ -1072,7 +1116,7 @@ resolve_comp_tls_regions(struct Compartment *new_comp) // TODO currently we only support one thread new_comp->libs_tls_sects->region_count = 1; - new_comp->libs_tls_sects->region_start = new_comp->scratch_mem_stack_top; + new_comp->libs_tls_sects->region_start = new_comp->mem_top; new_comp->libs_tls_sects->libs_count = 0; unsigned short *lib_idxs @@ -1098,8 +1142,7 @@ resolve_comp_tls_regions(struct Compartment *new_comp) intptr_t total_tls_size = comp_tls_size * new_comp->libs_tls_sects->region_count; - new_comp->scratch_mem_size += total_tls_size; - new_comp->mem_top = (char *) new_comp->mem_top + total_tls_size; + adjust_comp_scratch_mem(new_comp, total_tls_size); new_comp->libs_tls_sects->region_size = comp_tls_size; assert((uintptr_t) new_comp->libs_tls_sects->region_start % 16 == 0); diff --git a/src/manager.c b/src/manager.c index 21f6ac6..c602f43 100644 --- a/src/manager.c +++ b/src/manager.c @@ -15,12 +15,21 @@ void *__capability manager_ddc = 0; const char *comp_config_suffix = ".comp"; +char **proc_env_ptr = NULL; +const unsigned short avg_sz_per_env_entry = 128; // TODO +const unsigned short max_env_count = 128; // TODO +const size_t max_env_sz + = max_env_count * sizeof(char *) + avg_sz_per_env_entry * max_env_count; +extern char **environ; + static struct CompEntryPointDef * parse_compartment_config(char *, size_t *, bool); static struct CompEntryPointDef * make_default_entry_point(); static struct CompEntryPointDef get_entry_point(char *, struct CompEntryPointDef *, size_t); +static void +prepare_compartment_environ(); static void * prepare_compartment_args(char **args, struct CompEntryPointDef); @@ -78,6 +87,11 @@ get_next_comp_addr(void) struct Compartment * register_new_comp(char *filename, bool allow_default_entry) { + if (!proc_env_ptr) + { + prepare_compartment_environ(); + } + size_t new_comp_ep_count; struct CompEntryPointDef *new_cep = parse_compartment_config( filename, &new_comp_ep_count, allow_default_entry); @@ -145,6 +159,9 @@ clean_all_comps() clean_comp(comps[i]->comp); } free(comps); + + free(proc_env_ptr); + proc_env_ptr = NULL; } void @@ -324,6 +341,28 @@ get_entry_point( errx(1, "Did not find entry point for function %s!\n", entry_point_fn); } +static void +prepare_compartment_environ() +{ + proc_env_ptr = malloc(max_env_sz); + memset(proc_env_ptr, 0, max_env_sz); + char **prov_env_vals = proc_env_ptr + max_env_count * sizeof(char *); + + size_t envs_parsed = 0; + size_t envs_parsed_sz = 0; + const uintptr_t vals_offset = max_env_count * sizeof(char *); + for (char **curr_env = environ; *curr_env; curr_env++) + { + // We only save offsets for the pointers, since they'll be relocated + // relative to the compartment base address + proc_env_ptr[envs_parsed] = (char *) (vals_offset + envs_parsed_sz); + strcpy((char *) proc_env_ptr + vals_offset + envs_parsed_sz, *curr_env); + + envs_parsed += 1; + envs_parsed_sz += strlen(*curr_env) + 1; + } +} + static void * prepare_compartment_args(char **args, struct CompEntryPointDef cep) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ce658b3..25c6af1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -124,6 +124,7 @@ set(comp_binaries "simple_call_internal" "simple_call_internal_static" "simple_call_internal_weak" + "simple_environ" "simple_external" "simple_fopen" "simple_fputs" @@ -142,8 +143,8 @@ set(comp_binaries "simple_time" "simple_va_args" - #"lua_simple" - #"lua_script" + "lua_simple" + "lua_script" "args_simple" #"test_two_comps-comp1" @@ -156,6 +157,7 @@ set(tests "simple_call_internal" "simple_call_internal_static" "simple_call_internal_weak" + "simple_environ" "simple_fopen" "simple_fputs" "simple_global_var" @@ -170,8 +172,8 @@ set(tests "simple_time" "simple_va_args" - #"lua_simple" - #"lua_script" + "lua_simple" + "lua_script" "test_map" #"test_args_near_unmapped" @@ -217,9 +219,9 @@ new_dependency(simple_global_var $) target_link_libraries(simple_thrloc_var PRIVATE simple_thrloc_var-external) new_dependency(simple_thrloc_var $) -#new_dependency(test_map $) +new_dependency(test_map $) -#new_dependency(lua_script ${CMAKE_CURRENT_SOURCE_DIR}/hello_world.lua) +new_dependency(lua_script ${CMAKE_CURRENT_SOURCE_DIR}/hello_world.lua) #new_dependency(test_args_near_unmapped $) #new_dependency(test_args_near_unmapped ${CMAKE_CURRENT_SOURCE_DIR}/args_simple.comp) diff --git a/tests/lua_script.c b/tests/lua_script.c index 55f606f..4193723 100644 --- a/tests/lua_script.c +++ b/tests/lua_script.c @@ -42,7 +42,7 @@ do_script() } int -main(int argc, char **argv) +main() { do_script_arg("./hello_world.lua"); return 0; diff --git a/tests/lua_simple.c b/tests/lua_simple.c index e7c384b..b638bab 100644 --- a/tests/lua_simple.c +++ b/tests/lua_simple.c @@ -15,5 +15,5 @@ main(void) lua_Integer len = luaL_len(L, 1); lua_close(L); - return (len == strlen(test_string) ? 0 : 1); + return ((unsigned long) len == strlen(test_string) ? 0 : 1); } diff --git a/tests/simple_environ.c b/tests/simple_environ.c new file mode 100644 index 0000000..9007bb2 --- /dev/null +++ b/tests/simple_environ.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +extern char **environ; + +int +main() +{ + size_t i = 0; + for (char **curr_env = environ; *curr_env; ++curr_env) + { + printf("ENV -- %s\n", *curr_env); + ++i; + } + printf("---- COUNT - %zu\n", i); + + char *lang = getenv("LANG"); + assert(lang); + printf("getenv -- environ['LANG'] == %s\n", lang); + + char *term = getenv("TERM"); + assert(term); + printf("getenv -- environ['TERM'] == %s\n", term); + + char *no = getenv("DOESNTEXIST"); + assert(no == NULL); + + const char *set_name = "TRYENV"; + const char *set_val = "Hello Env"; + int set_check = setenv(set_name, set_val, 1); + assert(set_check == 0); + char *set_get = getenv(set_name); + printf("setenv -- environ['%s'] == %s\n", set_name, set_get); + assert(!strcmp(set_get, set_val)); + + set_check = putenv("TRYENV=Goodbye Env"); + assert(set_check == 0); + set_get = getenv(set_name); + printf("putenv -- environ['%s'] == %s\n", set_name, set_get); + assert(!strcmp(set_get, "Goodbye Env")); + + return 0; +}