From 7df6feee9abfc509ebb2f8430fc4944d5a49e91e Mon Sep 17 00:00:00 2001 From: Andrei Lascu Date: Wed, 20 Mar 2024 12:04:12 +0000 Subject: [PATCH] Update internal `malloc` and others * Provide a `malloc` and friends compartment library to be used internally, overriding the previous interception implementation. We use the DDC capability to get the are of memory that is designated as heap space. This is done in a new library, `libcomputils.so`, to be loaded in a compartment. This means further libraries loaded will also use our own internal `malloc` implementation; * Due to the above change, we also remove old intercept stuff, as that has been completely outdated by newer features (might come back for inter-compartment calls); * Fix setting improper bounds for compartment DDC capabilities (i.e., ensure the capability encompasses only the memory region designated for a compartment), and now set the offset to match the start of the compartment heap, to use for internal `malloc`; * Further improve symbol relocation lookup, including support for "raw" relocations that refer only to addresses, not to a given symbol. --- include/comp_utils.h | 17 ++ include/compartment.h | 26 +-- include/intercept.h | 40 +---- include/manager.h | 2 - include/mem_mng.h | 35 ---- src/CMakeLists.txt | 5 +- src/comp_utils.c | 46 +++++ src/compartment.c | 268 ++++++----------------------- src/intercept.c | 68 -------- src/manager.c | 27 +-- src/mem_mng.c | 115 ------------- tests/CMakeLists.txt | 20 ++- tests/init_test.py | 1 + tests/simple_fopen.c | 21 ++- tests/simple_global_var-external.c | 11 ++ tests/simple_global_var.c | 12 ++ tests/simple_open_write.c | 26 +++ tests/simple_syscall_getpid.c | 3 +- tests/simple_syscall_write.c | 3 +- tests/simple_various.c | 3 +- 20 files changed, 219 insertions(+), 530 deletions(-) create mode 100644 include/comp_utils.h delete mode 100644 include/mem_mng.h create mode 100644 src/comp_utils.c delete mode 100644 src/mem_mng.c create mode 100644 tests/simple_global_var-external.c create mode 100644 tests/simple_global_var.c create mode 100644 tests/simple_open_write.c diff --git a/include/comp_utils.h b/include/comp_utils.h new file mode 100644 index 0000000..c230ae7 --- /dev/null +++ b/include/comp_utils.h @@ -0,0 +1,17 @@ +#ifndef _COMP_UTILS_H +#define _COMP_UTILS_H + +#include +#include +#include + +#include "cheriintrin.h" + +void *malloc(size_t); +void +free(void *); +void *calloc(size_t, size_t); +void * +realloc(void *, size_t); + +#endif // _COMP_UTILS_H diff --git a/include/compartment.h b/include/compartment.h index cd18d0e..f84e1a8 100644 --- a/include/compartment.h +++ b/include/compartment.h @@ -47,30 +47,12 @@ comp_exec_out(); extern void __clear_cache(void *, void *); -// Number of instructions to inject at intercepted function call point -// TODO ensure there is sufficient space for these, so we don't spill over -#define INTERCEPT_INSTR_COUNT 5 - // Number of instructions required by the transition function #define COMP_TRANS_FN_INSTR_CNT 4 extern void *__capability sealed_redirect_cap; extern void *__capability comp_return_caps[2]; -/* For a function to be intercepted, information required to insert the - * redirect code and perform redirection - * - * TODO recheck this is properly used, or re-design into a more light-weight - * approach with pre-given transition capabilities - */ -struct InterceptPatch -{ - int *patch_addr; - int32_t instr[INTERCEPT_INSTR_COUNT]; - uintptr_t comp_manager_cap_addr; - void *__capability manager_cap; -}; - // Maximum size of an argument, in bytes #define COMP_ARG_SIZE 8 @@ -210,10 +192,6 @@ struct Compartment // Hardware info - maybe move size_t page_size; - - // Misc - unsigned short curr_intercept_count; - struct InterceptPatch *intercept_patches; }; int @@ -221,9 +199,7 @@ entry_point_cmp(const void *, const void *); struct Compartment * comp_init(); struct Compartment * -comp_from_elf(char *, char **, size_t, char **, void **, size_t, void *); -void -comp_add_intercept(struct Compartment *, uintptr_t, uintptr_t); +comp_from_elf(char *, char **, size_t, void *); void comp_map(struct Compartment *); void diff --git a/include/intercept.h b/include/intercept.h index 70ce1db..83531f6 100644 --- a/include/intercept.h +++ b/include/intercept.h @@ -11,8 +11,6 @@ #include "cheriintrin.h" -#include "mem_mng.h" - // Forward declarations struct Compartment; extern struct Compartment *loaded_comp; @@ -21,6 +19,8 @@ exec_comp(struct Compartment *, char *, char **); struct Compartment *manager_get_compartment_by_id(size_t); extern void *__capability manager_ddc; +extern void +comp_exec_out(); // Number of capabilities required to perform a transition #define COMP_RETURN_CAPS_COUNT 2 @@ -55,43 +55,7 @@ intercept_wrapper(); void setup_intercepts(); -time_t -intercepted_time(time_t *); -FILE * -intercepted_fopen(const char *, const char *); -size_t -intercepted_fread(void *__restrict, size_t, size_t, FILE *__restrict); -size_t -intercepted_fwrite(void *__restrict, size_t, size_t, FILE *__restrict); -int -intercepted_fclose(FILE *); -int -intercepted_getc(FILE *); -int -intercepted_fputc(int, FILE *); -int -intercepted___srget(FILE *); - -void * -my_realloc(void *, size_t); -void *my_malloc(size_t); -void -my_free(void *); -int -my_fprintf(FILE *, const char *, ...); - size_t my_call_comp(size_t, char *, void *); -static const struct FuncIntercept to_intercept_funcs[] = { - /* Mem funcs */ - { "malloc", (void *) my_malloc, NULL }, - { "realloc", (void *) my_realloc, NULL }, - { "free", (void *) my_free, NULL }, -}; -// -// Functions to be intercepted and associated data -#define INTERCEPT_FUNC_COUNT \ - sizeof(to_intercept_funcs) / sizeof(to_intercept_funcs[0]) -extern struct FuncIntercept comp_intercept_funcs[INTERCEPT_FUNC_COUNT]; #endif // _INTERCEPT_H diff --git a/include/manager.h b/include/manager.h index 1cc4cbc..d00b182 100644 --- a/include/manager.h +++ b/include/manager.h @@ -83,6 +83,4 @@ clean_compartment_config(struct CompEntryPointDef *, size_t); * Memory allocation ******************************************************************************/ -#include "mem_mng.h" - #endif // _MANAGER_H diff --git a/include/mem_mng.h b/include/mem_mng.h deleted file mode 100644 index fb5d8b0..0000000 --- a/include/mem_mng.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef MEM_MNG_H -#define MEM_MNG_H - -#include -#include -#include -#include - -#include - -#include "compartment.h" - -// TODO consider single linked list -struct MemAlloc -{ - uintptr_t ptr; - size_t size; - - struct MemAlloc *prev_alloc; - struct MemAlloc *next_alloc; -}; - -extern size_t comp_mem_alloc; -extern size_t comp_mem_max; - -void * -manager_register_mem_alloc(struct Compartment *, size_t); -void -manager_insert_new_alloc(struct Compartment *, struct MemAlloc *); -size_t -manager_free_mem_alloc(struct Compartment *, void *); -struct MemAlloc * -get_alloc_struct_from_ptr(struct Compartment *, uintptr_t); - -#endif // MEM_MNG_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d9a9cf2..bbd58e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,10 +1,13 @@ # Compartment management library add_library(chcomp STATIC manager.c - mem_mng.c compartment.c intercept.c transition.S ) target_include_directories(chcomp PRIVATE ${INCLUDE_DIR} ${TOML_INCLUDE_DIR}) target_link_libraries(chcomp PRIVATE tomllib) + +add_library(computils SHARED + comp_utils.c) +target_include_directories(computils PRIVATE ${INCLUDE_DIR}) diff --git a/src/comp_utils.c b/src/comp_utils.c new file mode 100644 index 0000000..259f247 --- /dev/null +++ b/src/comp_utils.c @@ -0,0 +1,46 @@ +#include "comp_utils.h" + +static void *malloc_ptr; +static size_t heap_mem_left; + +void * +malloc(size_t to_alloc) +{ + if (!malloc_ptr) + { + void *__capability ddc = cheri_ddc_get(); + malloc_ptr = (char *) cheri_address_get(ddc); + heap_mem_left = cheri_length_get(ddc) - cheri_offset_get(ddc); + } + if (to_alloc > heap_mem_left) + { + errx(1, "Insufficient heap space left."); + } + void *to_ret = malloc_ptr; + memset(to_ret, 0, to_alloc); + malloc_ptr = (char *) malloc_ptr + to_alloc; + heap_mem_left -= to_alloc; + return to_ret; +} + +void +free(void *to_free) +{ + // TODO temp usage for bump allocator implementation to satisfy compiler + to_free = to_free; +} + +void * +calloc(size_t elem_count, size_t elem_size) +{ + return malloc(elem_count * elem_size); +} + +void * +realloc(void *to_realloc, size_t new_size) +{ + // TODO temp usage for bump allocator implementation to satisfy compiler + to_realloc = to_realloc; + + return malloc(new_size); +} diff --git a/src/compartment.c b/src/compartment.c index 3e13dbd..2257788 100644 --- a/src/compartment.c +++ b/src/compartment.c @@ -6,8 +6,6 @@ const char *libs_path_env_var = "COMP_LIBRARY_PATH"; * Forward declarations ******************************************************************************/ -static void -get_lib_name(struct LibDependency *, const char *); static struct LibDependency * parse_lib_file(char *, struct Compartment *); static void @@ -21,8 +19,6 @@ parse_lib_dynamic_deps(Elf64_Shdr *, Elf64_Ehdr *, int, struct LibDependency *); static void find_comp_entry_points(char **, size_t, struct Compartment *); static void -find_comp_intercepts(char **, void **, size_t, struct Compartment *); -static void resolve_rela_syms(struct Compartment *); static struct LibSymSearchResult find_lib_dep_sym_in_comp(const char *, struct Compartment *, unsigned short); @@ -87,9 +83,6 @@ comp_init() new_comp->page_size = sysconf(_SC_PAGESIZE); - new_comp->curr_intercept_count = 0; - new_comp->intercept_patches = NULL; - return new_comp; } @@ -108,7 +101,6 @@ entry_point_cmp(const void *val1, const void *val2) */ struct Compartment * comp_from_elf(char *filename, char **entry_points, size_t entry_point_count, - char **intercepts, void **intercept_addrs, size_t intercept_count, void *new_comp_base) { struct Compartment *new_comp = comp_init(); @@ -156,114 +148,11 @@ comp_from_elf(char *filename, char **entry_points, size_t entry_point_count, new_comp->mem_top = new_comp->scratch_mem_stack_top; find_comp_entry_points(entry_points, entry_point_count, new_comp); - find_comp_intercepts( - intercepts, intercept_addrs, intercept_count, new_comp); resolve_rela_syms(new_comp); return new_comp; } -/* For a given Compartment `new_comp`, an address `intercept_target` pointing - * to a function found within the compartment which we would like to intercept, - * and a `intercept_data` struct representing information to perform the - * intercept, synthesize and inject intructions at the call point of the - * `intercept_target`, in order to perform a transition out of the compartment - * to call the appropriate function with higher privileges. - */ -void -comp_add_intercept(struct Compartment *new_comp, uintptr_t intercept_target, - uintptr_t redirect_addr) -{ - // TODO check whether negative values break anything in all these generated - // functions - int32_t new_instrs[INTERCEPT_INSTR_COUNT]; - size_t new_instr_idx = 0; - const ptraddr_t comp_manager_cap_addr = (ptraddr_t) new_comp->manager_caps - + new_comp->active_manager_caps_count - * sizeof(void *__capability); // TODO - - const int32_t arm_function_target_register = 0b01010; // use `x10` for now - const int32_t arm_transition_target_register = 0b01011; // use `x11` for now - - // `x10` is used to hold the address of the manager function we want to - // execute after a jump out of the compartment - // TODO ideally we want 1 `movz` and 3 `movk`, to be able to access any - // address, but this is sufficient for now - // movz x0, $target_fn_addr:lo16 - // movk x0, $target_fn_addr:hi16 - assert(intercept_target < ((ptraddr_t) 1 << 32)); - const uint32_t arm_movz_instr_mask = 0b11010010100 << 21; - const uint32_t arm_movk_instr_mask = 0b11110010101 << 21; - const ptraddr_t target_address_lo16 = (redirect_addr & ((1 << 16) - 1)) - << 5; - const ptraddr_t target_address_hi16 = (redirect_addr >> 16) << 5; - const int32_t arm_movz_intr = arm_movz_instr_mask | target_address_lo16 - | arm_function_target_register; - const int32_t arm_movk_intr = arm_movk_instr_mask | target_address_hi16 - | arm_function_target_register; - new_instrs[new_instr_idx++] = arm_movz_intr; - new_instrs[new_instr_idx++] = arm_movk_intr; - - /* `ldpbr` instr generation */ - // TODO do we have space to insert these instructions? - // TODO what if we need to jump more than 4GB away? - // Use `adrp` to get address close to address of manager capability required - // adrp x11, $OFFSET - const uint32_t arm_adrp_instr_mask = 0b10010000 << 24; - const ptraddr_t target_address - = (comp_manager_cap_addr >> 12) - (intercept_target >> 12); - assert(target_address < ((ptraddr_t) 1 << 32)); - const int32_t arm_adrp_immlo = (target_address & 0b11) << 29; - const int32_t arm_adrp_immhi = (target_address >> 2) << 5; - const int32_t arm_adrp_instr = arm_adrp_instr_mask | arm_adrp_immlo - | arm_adrp_immhi | arm_transition_target_register; - new_instrs[new_instr_idx++] = arm_adrp_instr; - - // `ldr` capability within compartment pointing to manager capabilities - // ldr (unsigned offset, capability, normal base) - // `ldr c11, [x11, $OFFSET]` - const uint32_t arm_ldr_instr_mask = 0b1100001001 - << 22; // includes 0b00 bits for `op` field - ptraddr_t arm_ldr_pcc_offset - = comp_manager_cap_addr; // offset within 4KB page - ptraddr_t offset_correction = align_down(comp_manager_cap_addr, 1 << 12); - arm_ldr_pcc_offset -= offset_correction; - - assert(arm_ldr_pcc_offset < 65520); // from ISA documentation - assert(arm_ldr_pcc_offset % 16 == 0); - arm_ldr_pcc_offset = arm_ldr_pcc_offset << 10; - const int32_t arm_ldr_base_register = arm_transition_target_register - << 5; // use `x11` for now - const int32_t arm_ldr_dest_register - = arm_transition_target_register; // use `c11` for now - const int32_t arm_ldr_instr = arm_ldr_instr_mask | arm_ldr_pcc_offset - | arm_ldr_base_register | arm_ldr_dest_register; - new_instrs[new_instr_idx++] = arm_ldr_instr; - - // `b` instr generation - ptraddr_t arm_b_instr_offset - = (((uintptr_t) new_comp->mng_trans_fn) - - (intercept_target + new_instr_idx * sizeof(uint32_t))) - / 4; - assert(arm_b_instr_offset < (1 << 27)); - arm_b_instr_offset &= (1 << 26) - 1; - const uint32_t arm_b_instr_mask = 0b101 << 26; - uintptr_t arm_b_instr = arm_b_instr_mask | arm_b_instr_offset; - new_instrs[new_instr_idx++] = arm_b_instr; - - assert(new_instr_idx == INTERCEPT_INSTR_COUNT); - struct InterceptPatch new_patch; - new_patch.patch_addr = (void *) intercept_target; - memcpy(new_patch.instr, new_instrs, sizeof(new_instrs)); - __clear_cache(new_patch.instr, new_patch.instr + sizeof(new_instrs)); - new_patch.comp_manager_cap_addr = comp_manager_cap_addr; - new_patch.manager_cap = sealed_redirect_cap; - new_comp->curr_intercept_count += 1; - new_comp->intercept_patches = realloc(new_comp->intercept_patches, - new_comp->curr_intercept_count * sizeof(struct InterceptPatch)); - new_comp->intercept_patches[new_comp->curr_intercept_count - 1] = new_patch; -} - /* Map a struct Compartment into memory, making it ready for execution */ void @@ -324,20 +213,6 @@ comp_map(struct Compartment *to_map) err(1, "Error mapping compartment %zu stack!\n", to_map->id); } - // Inject intercept instructions within identified intercepted functions - for (unsigned short i = 0; i < to_map->curr_intercept_count; ++i) - { - struct InterceptPatch to_patch = to_map->intercept_patches[i]; - // TODO change to memcpy? - for (size_t j = 0; j < INTERCEPT_INSTR_COUNT; ++j) - { - int32_t *curr_addr = to_patch.patch_addr + j; - *curr_addr = to_patch.instr[j]; - } - *((void *__capability *) to_patch.comp_manager_cap_addr) - = to_patch.manager_cap; - } - // Inject manager transfer function memcpy(to_map->mng_trans_fn, (void *) &compartment_transition_out, to_map->mng_trans_fn_sz); @@ -457,7 +332,10 @@ comp_clean(struct Compartment *to_clean) // Clean library relocation mappings for (j = 0; j < curr_lib_dep->rela_maps_count; ++j) { - free(curr_lib_dep->rela_maps[j].rela_name); + if (curr_lib_dep->rela_maps[j].rela_name) + { + free(curr_lib_dep->rela_maps[j].rela_name); + } } free(curr_lib_dep->rela_maps); @@ -467,7 +345,6 @@ comp_clean(struct Compartment *to_clean) } free(to_clean->libs); free(to_clean->entry_points); - free(to_clean->intercept_patches); free(to_clean); } @@ -491,7 +368,7 @@ parse_lib_file(char *lib_name, struct Compartment *new_comp) lib_fd = open(lib_path, O_RDONLY); if (lib_fd == -1) { - errx(1, "Error opening compartment file %s!\n", lib_path); + errx(1, "Error opening compartment file %s!\n", lib_name); } } @@ -507,16 +384,16 @@ parse_lib_file(char *lib_name, struct Compartment *new_comp) } struct LibDependency *new_lib = malloc(sizeof(struct LibDependency)); - new_lib->lib_name = malloc(strlen(lib_name)); + new_lib->lib_name = malloc(strlen(lib_name) + 1); strcpy(new_lib->lib_name, lib_name); if (lib_path) { - new_lib->lib_path = malloc(strlen(lib_path)); + new_lib->lib_path = malloc(strlen(lib_path) + 1); strcpy(new_lib->lib_path, lib_path); } else { - new_lib->lib_path = malloc(strlen(lib_name)); + new_lib->lib_path = malloc(strlen(lib_name) + 1); strcpy(new_lib->lib_path, lib_name); } @@ -686,10 +563,12 @@ parse_lib_symtb(Elf64_Shdr *symtb_shdr, Elf64_Ehdr *lib_ehdr, int lib_fd, for (size_t j = 0; j < lib_dep->lib_syms_count; ++j) { curr_sym = sym_tb[j]; - if (curr_sym.st_value == 0) + // TODO currently ignore symbols of unspecified type + if (ELF_ST_TYPE(curr_sym.st_info) == STT_NOTYPE) { continue; } + ld_syms[actual_syms].sym_offset = (void *) curr_sym.st_value; char *sym_name = &str_tb[curr_sym.st_name]; ld_syms[actual_syms].sym_name = malloc(strlen(sym_name) + 1); @@ -739,50 +618,55 @@ parse_lib_rela(Elf64_Shdr *rela_shdr, Elf64_Ehdr *lib_ehdr, int lib_fd, { curr_rela = rela_sec[j]; size_t curr_rela_sym_idx = ELF64_R_SYM(curr_rela.r_info); - Elf64_Sym curr_rela_sym = dyn_sym_tbl[curr_rela_sym_idx]; - if (curr_rela_sym_idx == 0) - { - // TODO In some test programs, there are some relocations with no - // name and some weird value; we currently filter them out, but - // they might mean something in the future - continue; - } - // 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")) + struct LibRelaMapping lrm = { NULL, 0x0, 0x0, -1, -1 }; + if (curr_rela_sym_idx != 0) { - warnx("Currently not relocating symbol `environ` from library %s - " - "using within a container might cause a crash.", - lib_dep->lib_name); - continue; + Elf64_Sym curr_rela_sym = dyn_sym_tbl[curr_rela_sym_idx]; + + // 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")) + { + warnx("Currently not relocating symbol `__progname` from " + "library %s " + "- using within a container might cause a crash.", + lib_dep->lib_name); + continue; + } + + lrm.rela_name + = malloc(strlen(&dyn_str_tbl[curr_rela_sym.st_name]) + 1); + strcpy(lrm.rela_name, &dyn_str_tbl[curr_rela_sym.st_name]); + lrm.rela_sym_type = ELF64_ST_TYPE(curr_rela_sym.st_info); + lrm.rela_sym_bind = ELF64_ST_BIND(curr_rela_sym.st_info); + if (curr_rela_sym.st_value != 0) + { + new_relas[actual_relas].target_func_address + = curr_rela_sym.st_value + (char *) lib_dep->lib_mem_base; + } + // TODO + assert(curr_rela.r_addend == 0 + && "I want to check if we have symbol-related relocations with " + "addends"); } - else if (!strcmp(&dyn_str_tbl[curr_rela_sym.st_name], "__progname")) + else { - warnx( - "Currently not relocating symbol `__progname` from library %s " - "- using within a container might cause a crash.", - lib_dep->lib_name); - continue; + lrm.target_func_address + = curr_rela.r_addend + (char *) lib_dep->lib_mem_base; } - char *curr_rela_name - = malloc(strlen(&dyn_str_tbl[curr_rela_sym.st_name]) + 1); - strcpy(curr_rela_name, &dyn_str_tbl[curr_rela_sym.st_name]); - struct LibRelaMapping lrm; - - // TODO haven't handled addends on relocations yet - assert(curr_rela.r_addend == 0); + lrm.rela_address = curr_rela.r_offset + (char *) lib_dep->lib_mem_base; + memcpy(new_relas + actual_relas, &lrm, sizeof(struct LibRelaMapping)); - new_relas[actual_relas] = (struct LibRelaMapping) { curr_rela_name, - curr_rela.r_offset + (char *) lib_dep->lib_mem_base, NULL, - ELF64_ST_TYPE(curr_rela_sym.st_info), - ELF64_ST_BIND(curr_rela_sym.st_info) }; - if (curr_rela_sym.st_value != 0) - { - new_relas[actual_relas].target_func_address - = curr_rela_sym.st_value + (char *) lib_dep->lib_mem_base; - } actual_relas += 1; } lib_dep->rela_maps = realloc(lib_dep->rela_maps, @@ -819,7 +703,7 @@ parse_lib_dynamic_deps(Elf64_Shdr *dynamic_shdr, Elf64_Ehdr *lib_ehdr, lib_dep->lib_dep_names = realloc(lib_dep->lib_dep_names, (lib_dep->lib_dep_count + 1) * sizeof(char *)); lib_dep->lib_dep_names[lib_dep->lib_dep_count] - = malloc(strlen(&dynstr_tbl[dyn_entries[i].d_un.d_val])); + = malloc(strlen(&dynstr_tbl[dyn_entries[i].d_un.d_val]) + 1); strcpy(lib_dep->lib_dep_names[lib_dep->lib_dep_count], &dynstr_tbl[dyn_entries[i].d_un.d_val]); lib_dep->lib_dep_count += 1; @@ -851,39 +735,6 @@ find_comp_entry_points( } } -static void -find_comp_intercepts(char **intercepts, void **intercept_addrs, - size_t intercept_count, struct Compartment *new_comp) -{ - // Find symbols for intercepts - char **intercept_names = malloc(intercept_count * sizeof(char *)); - const char *so_plt_suffix = "@plt"; - for (size_t i = 0; i < intercept_count; ++i) - { - size_t to_intercept_name_len - = strlen(intercepts[i]) + strlen(so_plt_suffix) + 1; - intercept_names[i] = malloc(to_intercept_name_len); - strcpy(intercept_names[i], intercepts[i]); - strcat(intercept_names[i], so_plt_suffix); - } - for (size_t i = 0; i < intercept_count; ++i) - { - struct LibSymSearchResult found_sym - = find_lib_dep_sym_in_comp(intercept_names[i], new_comp, STT_FUNC); - if (found_sym.lib_idx == USHRT_MAX) - { - continue; - } - - // TODO double check - comp_add_intercept(new_comp, - (uintptr_t) extract_sym_offset(new_comp, found_sym), - (uintptr_t) intercept_addrs[i]); - free(intercept_names[i]); - } - free(intercept_names); -} - static void resolve_rela_syms(struct Compartment *new_comp) { @@ -943,14 +794,6 @@ do_pread(int fd, void *buf, size_t count, off_t offset) return res; } -static void -get_lib_name(struct LibDependency *lib_dep, const char *lib_path) -{ - const char *basename = strrchr(lib_path, '/') + 1; - lib_dep->lib_name = malloc(strlen(basename)); - strcpy(lib_dep->lib_name, basename); -} - static void * extract_sym_offset(struct Compartment *comp, struct LibSymSearchResult res) { @@ -969,7 +812,8 @@ find_lib_dep_sym_in_comp(const char *to_find, if (comp_to_search->libs[i]->lib_syms[j].sym_bind != STB_LOCAL && !strcmp( to_find, comp_to_search->libs[i]->lib_syms[j].sym_name) - && comp_to_search->libs[i]->lib_syms[j].sym_type == sym_type) + && comp_to_search->libs[i]->lib_syms[j].sym_type == sym_type + && comp_to_search->libs[i]->lib_syms[j].sym_offset != 0) { struct LibSymSearchResult res = { i, j }; return res; diff --git a/src/intercept.c b/src/intercept.c index 1613a36..ce28ecd 100644 --- a/src/intercept.c +++ b/src/intercept.c @@ -1,6 +1,5 @@ #include "intercept.h" -struct FuncIntercept comp_intercept_funcs[INTERCEPT_FUNC_COUNT]; void *__capability comp_return_caps[COMP_RETURN_CAPS_COUNT]; void *__capability sealed_redirect_cap; @@ -20,15 +19,6 @@ void *__capability sealed_redirect_cap; void setup_intercepts() { - for (size_t i = 0; - i < sizeof(to_intercept_funcs) / sizeof(to_intercept_funcs[0]); ++i) - { - comp_intercept_funcs[i].func_name = to_intercept_funcs[i].func_name; - comp_intercept_funcs[i].redirect_func - = to_intercept_funcs[i].redirect_func; - comp_intercept_funcs[i].intercept_pcc - = cheri_address_set(cheri_pcc_get(), (uintptr_t) intercept_wrapper); - } sealed_redirect_cap = manager_ddc; sealed_redirect_cap = cheri_address_set(sealed_redirect_cap, (intptr_t) comp_return_caps); @@ -40,64 +30,6 @@ setup_intercepts() = cheri_address_set(cheri_pcc_get(), (uintptr_t) comp_exec_out); } -/******************************************************************************* - * Intercept functions - * - * These functions are meant to be executed within a manager context, by - * intercepting certain functions within compartments which must have higher - * privlige - ******************************************************************************/ - -void * -my_realloc(void *ptr, size_t to_alloc) -{ - // TODO revisit this logic; do we keep a pointer in the manager of the - // currently loaded compartment (would probably require this to be set in - // the transition function), or do we get this information from the - // intercept source (could check the compartment mapping to see which - // compartment the source address comes from) - /*struct Compartment* comp = - * manager_find_compartment_by_ddc(cheri_ddc_get());*/ - struct Compartment *comp = loaded_comp; - - if (ptr == NULL) - { - return my_malloc(to_alloc); // TODO - } - - void *new_ptr = manager_register_mem_alloc(comp, to_alloc); - struct MemAlloc *old_alloc - = get_alloc_struct_from_ptr(comp, (uintptr_t) ptr); - memcpy( - new_ptr, ptr, to_alloc < old_alloc->size ? to_alloc : old_alloc->size); - manager_free_mem_alloc(comp, ptr); - return new_ptr; -} - -void * -my_malloc(size_t to_alloc) -{ - /*struct Compartment* comp = - * manager_find_compartment_by_ddc(cheri_ddc_get());*/ - struct Compartment *comp = loaded_comp; - assert(comp->scratch_mem_alloc + to_alloc < comp->scratch_mem_size); - void *new_mem = manager_register_mem_alloc(comp, to_alloc); - return new_mem; -} - -void -my_free(void *ptr) -{ - if (ptr == NULL) - { - return; - } - /*struct Compartment* comp = - * manager_find_compartment_by_ddc(cheri_ddc_get());*/ - manager_free_mem_alloc(loaded_comp, ptr); // TODO - return; -} - size_t my_call_comp( size_t comp_id, char *fn_name, void *args) // TODO , size_t args_count) diff --git a/src/manager.c b/src/manager.c index 01d4f60..b58d013 100644 --- a/src/manager.c +++ b/src/manager.c @@ -69,24 +69,15 @@ register_new_comp(char *filename, bool allow_default_entry) strcpy(ep_names[i], new_cep[i].name); } - char **intercept_names = calloc(INTERCEPT_FUNC_COUNT, sizeof(char *)); - void **intercept_addrs = calloc(INTERCEPT_FUNC_COUNT, sizeof(uintptr_t)); - for (size_t i = 0; i < INTERCEPT_FUNC_COUNT; ++i) - { - intercept_names[i] = malloc(strlen(comp_intercept_funcs[i].func_name)); - strcpy(intercept_names[i], comp_intercept_funcs[i].func_name); - intercept_addrs[i] = comp_intercept_funcs[i].redirect_func; - } - - struct Compartment *new_comp - = comp_from_elf(filename, ep_names, new_comp_ep_count, intercept_names, - intercept_addrs, INTERCEPT_FUNC_COUNT, get_next_comp_addr()); + struct Compartment *new_comp = comp_from_elf( + filename, ep_names, new_comp_ep_count, get_next_comp_addr()); new_comp->id = comps_count; void *__capability new_comp_ddc = cheri_address_set(cheri_ddc_get(), (uintptr_t) new_comp->base); - // TODO double check second parameter of `cheri_bounds_set` - new_comp_ddc = cheri_bounds_set( - new_comp_ddc, (uintptr_t) new_comp->scratch_mem_stack_top); + new_comp_ddc = cheri_bounds_set(new_comp_ddc, + (char *) new_comp->scratch_mem_stack_top - (char *) new_comp->base); + new_comp_ddc = cheri_offset_set(new_comp_ddc, + (char *) new_comp->scratch_mem_base - (char *) new_comp->base); new_comp->ddc = new_comp_ddc; struct CompWithEntries *new_cwe = malloc(sizeof(struct CompWithEntries)); @@ -105,12 +96,6 @@ register_new_comp(char *filename, bool allow_default_entry) free(ep_names[i]); } free(ep_names); - for (size_t i = 0; i < INTERCEPT_FUNC_COUNT; ++i) - { - free(intercept_names[i]); - } - free(intercept_names); - free(intercept_addrs); return new_comp; } diff --git a/src/mem_mng.c b/src/mem_mng.c deleted file mode 100644 index 061210d..0000000 --- a/src/mem_mng.c +++ /dev/null @@ -1,115 +0,0 @@ -#include "mem_mng.h" - -// MEM TODO - -/* An initial design of a simple bump allocator. This is here more to have - * something intercept `malloc` calls from the compartment, and might be - * scrapped in favour of something useful. The only requirement is that we are - * able to restrict what area of the memory we want to manage to the - * compartment scratch memory space - */ - -void * -manager_register_mem_alloc(struct Compartment *comp, size_t mem_size) -{ - // TODO better algorithm to find blocks of memory available for mapping - void *new_mem = (char *) comp->scratch_mem_base + comp->scratch_mem_alloc; - struct MemAlloc *new_alloc = malloc(sizeof(struct MemAlloc)); - new_alloc->ptr = (uintptr_t) new_mem; - new_alloc->size = mem_size; - manager_insert_new_alloc(comp, new_alloc); - comp->scratch_mem_alloc += __builtin_align_up(mem_size, sizeof(void *)); - return new_mem; -} - -void -manager_insert_new_alloc(struct Compartment *comp, struct MemAlloc *to_insert) -{ - if (comp->alloc_head == NULL) - { - to_insert->prev_alloc = NULL; - to_insert->next_alloc = NULL; - comp->alloc_head = to_insert; - return; - } - - if (comp->alloc_head->ptr > to_insert->ptr) - { - to_insert->next_alloc = comp->alloc_head; - to_insert->prev_alloc = NULL; - comp->alloc_head->prev_alloc = to_insert; - comp->alloc_head = to_insert; - return; - } - - struct MemAlloc *curr_alloc = comp->alloc_head; - while (curr_alloc->next_alloc != NULL && curr_alloc->ptr < to_insert->ptr) - { - curr_alloc = curr_alloc->next_alloc; - } - if (curr_alloc->next_alloc == NULL) - { - to_insert->prev_alloc = curr_alloc; - curr_alloc->next_alloc = to_insert; - to_insert->next_alloc = NULL; - return; - } - - to_insert->next_alloc = curr_alloc->next_alloc; - to_insert->next_alloc->prev_alloc = to_insert; - curr_alloc->next_alloc = to_insert; - to_insert->prev_alloc = curr_alloc; - return; -} - -size_t -manager_free_mem_alloc(struct Compartment *comp, void *ptr) -{ - struct MemAlloc *curr_alloc = comp->alloc_head; - while (curr_alloc != NULL && curr_alloc->ptr != (uintptr_t) ptr) - { - curr_alloc = curr_alloc->next_alloc; - } - - assert(curr_alloc != NULL && "Memory allocation not found to be freed."); - if (curr_alloc->prev_alloc != NULL) - { - curr_alloc->prev_alloc->next_alloc = curr_alloc->next_alloc; - } - if (curr_alloc->next_alloc != NULL) - { - curr_alloc->next_alloc->prev_alloc = curr_alloc->prev_alloc; - } - size_t to_return = curr_alloc->size; - free(curr_alloc); - - return to_return; -} - -/** - * Find allocation record in a compartment for a given address - * - * Given a compartment and an address, iterates over the memory allocations - * recorded for that compartment in order to find the allocation record - * refering to the given address. - * This currently expects the allocation record to exactly point to a given - * address to be searched, due to how the memory allocator is designed. - * - * \param comp Compartment in which we expect the allocation to exist - * \param ptr Address to search for - * \return A record indicating the requested memory allocation - */ -struct MemAlloc * -get_alloc_struct_from_ptr(struct Compartment *comp, uintptr_t ptr) -{ - struct MemAlloc *curr_alloc = comp->alloc_head; - while (curr_alloc->next_alloc != NULL) - { - if (curr_alloc->ptr == ptr) - { - return curr_alloc; - } - curr_alloc = curr_alloc->next_alloc; - } - errx(1, "ERROR: Could not find allocated pointer %Pu!\n", ptr); -} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c7c117c..1fa35d7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,7 +57,7 @@ function(new_comp_test test_name) add_library(${test_name} SHARED ${test_name}.c) set_target_properties(${test_name} PROPERTIES PREFIX "") - target_link_libraries(${test_name} PRIVATE chcomp lualib dl m) + target_link_libraries(${test_name} PRIVATE chcomp computils lualib dl m) target_include_directories(${test_name} PRIVATE ${INCLUDE_DIR} ${LUA_INCLUDE_DIR}) set_property(TARGET ${test_name} PROPERTY compartment TRUE) @@ -127,14 +127,17 @@ set(comp_binaries "simple_call_external" "simple_static_var" "simple_static_var-external" + "simple_global_var" + "simple_global_var-external" "simple_external" "simple_syscall_getpid" "simple_syscall_write" "simple_va_args" + "simple_open_write" "simple_fputs" - "simple_printf" "simple_fopen" - #"time" + "simple_malloc" + "time" #"lua_simple" #"lua_script" "args_simple" @@ -150,13 +153,15 @@ set(tests "simple_call_internal_weak" "simple_call_external" "simple_static_var" + "simple_global_var" "simple_syscall_getpid" "simple_syscall_write" "simple_va_args" - #"simple_fputs" - #"simple_printf" + "simple_open_write" + "simple_fputs" "simple_fopen" - #"time" + "simple_malloc" + "time" #"lua_simple" #"lua_script" "test_map" @@ -196,6 +201,9 @@ new_dependency(simple_call_external $) target_link_libraries(simple_static_var PRIVATE simple_static_var-external) new_dependency(simple_static_var $) +target_link_libraries(simple_global_var PRIVATE simple_global_var-external) +new_dependency(simple_global_var $) + #new_dependency(test_map $) #new_dependency(lua_script ${CMAKE_CURRENT_SOURCE_DIR}/hello_world.lua) diff --git a/tests/init_test.py b/tests/init_test.py index 4cf409d..c14cc00 100755 --- a/tests/init_test.py +++ b/tests/init_test.py @@ -16,6 +16,7 @@ LOCAL_LIBS = [ "./third-party/lua/liblua.so", + "./build/src/libcomputils.so" ] REMOTE_LIBS = [ "/lib/libc.so.7", diff --git a/tests/simple_fopen.c b/tests/simple_fopen.c index 7fd58d0..6409763 100644 --- a/tests/simple_fopen.c +++ b/tests/simple_fopen.c @@ -2,37 +2,50 @@ #include #include #include +#include #include void by_fopen() { FILE *fd = fopen("tmp", "w"); - fprintf(fd, "Hi\n"); + if (!fd) + { + err(1, "Error in fopen: "); + } fclose(fd); } void by_syscall() { + int fd = syscall(SYS_open, "tmp", O_CREAT); // open + if (fd == -1) + { + err(1, "Error in open: "); + } + syscall(SYS_close, fd); // close } void by_open() { - int fd = open("tmp", O_WRONLY | O_CREAT); + int fd = open("tmp", O_CREAT); if (fd == -1) { err(1, "Error in open: "); } - char *buf = "Hi\n"; - write(fd, buf, strlen(buf)); close(fd); } int main() { + write(STDOUT_FILENO, "== By open\n", 11); by_open(); + write(STDOUT_FILENO, "== By syscall\n", 14); + by_syscall(); + write(STDOUT_FILENO, "== By fopen\n", 12); + by_fopen(); return 0; } diff --git a/tests/simple_global_var-external.c b/tests/simple_global_var-external.c new file mode 100644 index 0000000..ccdf715 --- /dev/null +++ b/tests/simple_global_var-external.c @@ -0,0 +1,11 @@ +static int ext_val; + +int +get_ext_val() +{ + if (!ext_val) + { + ext_val = 42; + } + return ext_val; +} diff --git a/tests/simple_global_var.c b/tests/simple_global_var.c new file mode 100644 index 0000000..bb91272 --- /dev/null +++ b/tests/simple_global_var.c @@ -0,0 +1,12 @@ +#include + +int +get_ext_val(); + +int +main(void) +{ + int ext_val = get_ext_val(); + assert(ext_val == 42); + return 0; +} diff --git a/tests/simple_open_write.c b/tests/simple_open_write.c new file mode 100644 index 0000000..b68161b --- /dev/null +++ b/tests/simple_open_write.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +int +main(void) +{ + char *buf = "Hello File!\n"; + char *file = "out_syscall_write"; + int fd = open(file, O_WRONLY | O_CREAT); + if (fd == -1) + { + err(1, "Error in open: "); + } + if (write(fd, buf, strlen(buf)) == -1) + { + err(1, "Error in write: "); + } + if (close(fd) == -1) + { + err(1, "Error in close: "); + } + return 0; +} diff --git a/tests/simple_syscall_getpid.c b/tests/simple_syscall_getpid.c index 4956dfa..3bae87e 100644 --- a/tests/simple_syscall_getpid.c +++ b/tests/simple_syscall_getpid.c @@ -1,10 +1,11 @@ #include +#include #include int main(void) { - long int sc_pid = syscall(20); + long int sc_pid = syscall(SYS_getpid); pid_t pid = getpid(); assert(pid == sc_pid); return 0; diff --git a/tests/simple_syscall_write.c b/tests/simple_syscall_write.c index 119cd45..44d35f2 100644 --- a/tests/simple_syscall_write.c +++ b/tests/simple_syscall_write.c @@ -1,12 +1,13 @@ #include #include +#include #include int main(void) { char *buf = "Hello World!\n"; - long int sc_write = syscall(4, STDOUT_FILENO, buf, strlen(buf)); + long int sc_write = syscall(SYS_write, STDOUT_FILENO, buf, strlen(buf)); if (sc_write == -1) { err(1, "Error calling `syscall`:"); diff --git a/tests/simple_various.c b/tests/simple_various.c index 7d61a27..c3dc960 100644 --- a/tests/simple_various.c +++ b/tests/simple_various.c @@ -1,3 +1,4 @@ +#include #include #include @@ -12,7 +13,7 @@ do_print(const char *const to_print) int main(void) { - char *x = malloc(strlen(hw)); + char *x = malloc(strlen(hw) + 1); strcpy(x, hw); do_print(x); free(x);