From ed582b747b35199edb97fde7fc51d4947249b833 Mon Sep 17 00:00:00 2001 From: Andrei Lascu Date: Wed, 23 Oct 2024 12:08:53 +0100 Subject: [PATCH] Add some useful script and various changes Add a number of useful scripts: * Scripts to compile the project, for `cheri` and `linux` configurations; * Script to run `clang-format`; * Script to execute a native executable multiple times in a shell script; * Script to run full benchmarking, from compiling in release mode, to gathering data locally. Add a variant of the compartment manager which executes the given compartment multiple times. To be used in conjunction with `multi_execute.sh` and the `EXECUTE_COUNT` environment variable for benchmarking. Some fixes and optimisations: * Implement compartment unmapping, and integrate it into the cleaning process (add one relevant test) * Merge `comp_map` `mmap`s into one * Replace compartment parsing `pread`s with a single `mmap` and various memory operations * Fix overflow when copying `environ` data from manager to compartment * Enable `-Werror` only in `DEBUG` builds --- CMakeLists.txt | 2 +- include/compartment.h | 6 ++ scripts/compile-cheri.sh | 32 ++++++ scripts/compile-linux.sh | 43 ++++++++ scripts/do_benchmarks.py | 131 ++++++++++++++++++++++++ scripts/do_clang_format.sh | 2 + scripts/multi_execute.sh | 14 +++ src/compartment.c | 170 +++++++++++++++++--------------- src/manager.c | 21 ++-- tests/CMakeLists.txt | 8 ++ tests/compartment_harness.c | 2 + tests/manager_caller_multiple.c | 30 ++++++ tests/test_map_multi.c | 20 ++++ 13 files changed, 395 insertions(+), 86 deletions(-) create mode 100755 scripts/compile-cheri.sh create mode 100755 scripts/compile-linux.sh create mode 100755 scripts/do_benchmarks.py create mode 100755 scripts/do_clang_format.sh create mode 100755 scripts/multi_execute.sh create mode 100644 tests/manager_caller_multiple.c create mode 100644 tests/test_map_multi.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 84deef2..4d2c0a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16) project(CHERI_ELF_Compartments LANGUAGES C ASM) # Set global compilation options -add_compile_options(-pedantic -Wextra -Wno-gnu-binary-literal -Wno-language-extension-token -Werror) +add_compile_options(-pedantic -Wextra -Wno-gnu-binary-literal -Wno-language-extension-token $<$:-Werror>) # Set useful directory variables set(TEST_DIR ${CMAKE_SOURCE_DIR}/tests) diff --git a/include/compartment.h b/include/compartment.h index 431f778..a5539f4 100644 --- a/include/compartment.h +++ b/include/compartment.h @@ -168,6 +168,10 @@ struct CompConfig struct CompEntryPointDef *entry_points; size_t entry_point_count; void *base_address; + + char** env_ptr; + size_t env_ptr_sz; + unsigned short env_ptr_count; }; /** @@ -219,6 +223,8 @@ comp_from_elf(char *, struct CompConfig *); // char **, size_t, void *); void comp_map(struct Compartment *); void +comp_unmap(struct Compartment *); +void comp_map_full(struct Compartment *); int64_t comp_exec(struct Compartment *, char *, void *, size_t); diff --git a/scripts/compile-cheri.sh b/scripts/compile-cheri.sh new file mode 100755 index 0000000..9c31250 --- /dev/null +++ b/scripts/compile-cheri.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -e +set -x + +# CheriBSD +export CC=/home/cheriworker/cheri/output/morello-sdk/bin/clang +export AR=/home/cheriworker/cheri/output/morello-sdk/bin/llvm-ar +export CFLAGS="--config cheribsd-morello-hybrid.cfg -DARM -O0" +export ASMFLAGS="--config cheribsd-morello-hybrid.cfg" +export LDFLAGS="--config cheribsd-morello-hybrid.cfg" + +# Morello Linux Glibc +#export CC=/home/cheriworker/morello-glibc/arm-gnu-toolchain-10.1.morello-alp2-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc +#export AR=/home/cheriworker/morello-glibc/arm-gnu-toolchain-10.1.morello-alp2-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-ar +#export CFLAGS="-march=morello" +#export ASMFLAGS="-march=morello" +#export LDFLAGS="-march=morello" + +# Morello Linux + +#export CC=clang +#export CFLAGS="-DX86" + +build_dir="$(pwd)/build" +src_dir="$(pwd)/" + +cmake \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=DEBUG \ + -B $build_dir \ + -S $src_dir +cmake --build $build_dir -v diff --git a/scripts/compile-linux.sh b/scripts/compile-linux.sh new file mode 100755 index 0000000..922fed6 --- /dev/null +++ b/scripts/compile-linux.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +#export CC=/home/cheriworker/cheri/output/morello-sdk/bin/clang +#export AR=/home/cheriworker/cheri/output/morello-sdk/bin/llvm-ar + +export CC=clang +export AR=llvm-ar-10 +#export CFLAGS="-fsanitize=address" + +src_dir=/home/cheriworker/workspace/CHERI-ELF-comp +build_dir=$src_dir/build-linux +third_party_dir=$src_dir/third-party +comp_libs_dir=$build_dir/libs +sys_lib=/lib/x86_64-linux-gnu + +cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -B $build_dir -S $src_dir +cmake --build $build_dir --target comp_harness so_harness +cmake --build $build_dir --target lua_script simple_thrloc_var simple_const_thrloc_var simple + + +mkdir -p $comp_libs_dir + +libs=( + $build_dir/src/libcomputils.so + $third_party_dir/lua/liblua.so + $sys_lib/libdl.so.2 + $sys_lib/libm.so.6 + $sys_lib/libc.so.6 + /lib64/ld-linux-x86-64.so.2 +) +for lib in ${libs[@]} +do + if [ -f $comp_libs_dir/$(basename $lib) ] + then + continue + fi + if [ ! -f $lib ] + then + echo "Did not find $lib!" + exit + fi + cp $lib $comp_libs_dir +done diff --git a/scripts/do_benchmarks.py b/scripts/do_benchmarks.py new file mode 100755 index 0000000..e7bc56a --- /dev/null +++ b/scripts/do_benchmarks.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 + +import datetime +import os +import shlex +import subprocess + +from fabric import Connection + +################################################################################ +# Constants +################################################################################ + +BENCH_HOST = "10.81.18.119" +BENCH_USER = "al2510" + +BENCH_RUN_PATH = "/home/0152la/bench-script" +BENCH_RUN_LIBS_PATH = f"{BENCH_RUN_PATH}/libs" + +SRC_DIR = os.getcwd() +BUILD_DIR = f"{SRC_DIR}/build-release" +BUILD_TESTS_DIR = f"{BUILD_DIR}/tests" +SRC_TESTS_DIR = f"{SRC_DIR}/tests" +SCRIPTS_DIR = f"{SRC_DIR}/scripts" +RESULTS_DIR = f"{BUILD_DIR}/results-{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}" + +THIRD_PARTY_DIR = f"{SRC_DIR}/third-party" +LUA_DIR = f"{THIRD_PARTY_DIR}/lua" + +CMAKE_BUILD_ENV = { + **os.environ, + "CC": "/home/cheriworker/cheri/output/morello-sdk/bin/clang", + "AR": "/home/cheriworker/cheri/output/morello-sdk/bin/llvm-ar", + "CFLAGS": "--config cheribsd-morello-hybrid.cfg -DARM -O3", + "ASMFLAGS": "--config cheribsd-morello-hybrid.cfg", + "LDFLAGS": "--config cheribsd-morello-hybrid.cfg" + } + +BENCH_RUN_ENV = { + "COMP_LIBRARY_PATH": f"{BENCH_RUN_PATH}/libs", + "LD_64_LIBRARY_PATH": f"{BENCH_RUN_PATH}/libs", + "EXECUTE_COUNT": 1000, + } + +TESTS = [ + "lua_script" + ] + +LOCAL_LIBS = [ + f"{THIRD_PARTY_DIR}/lua/liblua.so", + f"{BUILD_DIR}/src/libcomputils.so", + ] +REMOTE_LIBS = [ + "/usr/lib64/libc.so.7", + "/usr/lib64/libdl.so.1", + "/usr/lib64/libm.so.5", + ] + +BENCH_BINS = [ + f"{SCRIPTS_DIR}/multi_execute.sh", + f"{BUILD_TESTS_DIR}/manager_call_multi", + f"{SRC_TESTS_DIR}/hello_world.lua" + ] +BENCH_EXECUTIONS = { + "native_multi": "multi_execute.sh ./lua_script", + "manager_multi": "manager_call_multi ./lua_script.so", + } + +################################################################################ +# Helper functions +################################################################################ + +def remote_put(conn, file, dest): + conn.put(file, remote = dest) + +def remote_exec(conn, cmd, env = None, out = None): + return conn.run(cmd, env = env, echo = True, warn = True) + +def remote_exec_log(conn, cmd, env, out): + return conn.run(cmd, env = env, echo = True, warn = True, out_stream = out, hide = 'stdout') + +def remote_exec_log_err(conn, cmd, env, out): + return conn.run(cmd, env = env, echo = True, warn = True, err_stream = out, hide = 'stdout') + +################################################################################ +# Main +################################################################################ + + +# Compile project +cmake_cmd = f"cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -B {BUILD_DIR} -S {SRC_DIR}" +subprocess.run(shlex.split(cmake_cmd), env = CMAKE_BUILD_ENV) +cmake_cmd = f"cmake --build {BUILD_DIR}" +subprocess.run(shlex.split(cmake_cmd), env = CMAKE_BUILD_ENV) + +# Compile native tests +native_build_flags = f"-I{LUA_DIR} -L{LUA_DIR} -llua" +native_build_cmd = f"{CMAKE_BUILD_ENV['CC']} {CMAKE_BUILD_ENV['CFLAGS']} -o {BUILD_TESTS_DIR}/{{0}} {SRC_TESTS_DIR}/{{0}}.c {native_build_flags}" +for test in TESTS: + cmd = shlex.split(native_build_cmd.format(test)) + subprocess.run(cmd) + +# Prepare results folder +os.makedirs(RESULTS_DIR, exist_ok = True) + +# Copy tests and scripts +conn = Connection(host = BENCH_HOST, user = BENCH_USER, inline_ssh_env = True) +remote_exec(conn, f"mkdir -p {BENCH_RUN_LIBS_PATH}") + +for test in TESTS: + remote_put(conn, f"{BUILD_TESTS_DIR}/{test}", BENCH_RUN_PATH) + remote_put(conn, f"{BUILD_TESTS_DIR}/{test}.so", BENCH_RUN_PATH) +for bbin in BENCH_BINS: + remote_put(conn, bbin, BENCH_RUN_PATH) +for llib in LOCAL_LIBS: + remote_put(conn, llib, BENCH_RUN_LIBS_PATH) +for rlib in REMOTE_LIBS: + remote_exec(conn, f"ln -sf {rlib} {BENCH_RUN_LIBS_PATH}") + +# Execute benchmarks +for key, cmd in BENCH_EXECUTIONS.items(): + cmd = f"cd {BENCH_RUN_PATH} ; truss -c ./{cmd}" + with open(f"{RESULTS_DIR}/truss-{key}", 'w') as res_fd: + remote_exec_log_err(conn, cmd, env = BENCH_RUN_ENV, out = res_fd) + +cmd = f"cd {BENCH_RUN_PATH} ; hyperfine" +cmd = ' '.join([cmd, *[f"'./{x}'" for x in BENCH_EXECUTIONS.values()]]) +with open(f"{RESULTS_DIR}/hyperfine", 'w') as res_fd: + remote_exec_log(conn, cmd, env = BENCH_RUN_ENV, out = res_fd) + +conn.close() diff --git a/scripts/do_clang_format.sh b/scripts/do_clang_format.sh new file mode 100755 index 0000000..a65e625 --- /dev/null +++ b/scripts/do_clang_format.sh @@ -0,0 +1,2 @@ +#!/bin/bash +clang-format -i ./src/*.c ./include/*.h ./tests/*.c diff --git a/scripts/multi_execute.sh b/scripts/multi_execute.sh new file mode 100755 index 0000000..8ff059c --- /dev/null +++ b/scripts/multi_execute.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ $# -ne 1 ] +then + echo "Expected exactly one argument: test to execute!" + exit 1 +fi + +EXECUTE_COUNT=${EXECUTE_COUNT:=100} + +for i in $(seq 1 $EXECUTE_COUNT) +do + ./$1 +done diff --git a/src/compartment.c b/src/compartment.c index 4d12c6e..b40794d 100644 --- a/src/compartment.c +++ b/src/compartment.c @@ -4,10 +4,6 @@ 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 ******************************************************************************/ @@ -20,13 +16,13 @@ lib_init(); static struct LibDependency * parse_lib_file(char *, struct Compartment *); static void -parse_lib_segs(Elf64_Ehdr *, int, struct LibDependency *, struct Compartment *); +parse_lib_segs(Elf64_Ehdr *, void*, struct LibDependency *, struct Compartment *); static void -parse_lib_symtb(Elf64_Shdr *, Elf64_Ehdr *, int, struct LibDependency *); +parse_lib_symtb(Elf64_Shdr *, Elf64_Ehdr *, void*, struct LibDependency *); static void -parse_lib_rela(Elf64_Shdr *, Elf64_Ehdr *, int, struct LibDependency *); +parse_lib_rela(Elf64_Shdr *, Elf64_Ehdr *, void*, struct LibDependency *); static void -parse_lib_dynamic_deps(Elf64_Shdr *, Elf64_Ehdr *, int, struct LibDependency *); +parse_lib_dynamic_deps(Elf64_Shdr *, Elf64_Ehdr *, void*, struct LibDependency *); static void map_comp_entry_points(struct Compartment *); static void @@ -45,6 +41,10 @@ eval_sym_tls_offset(struct Compartment *, const comp_symbol *); static ssize_t do_pread(int, void *, size_t, off_t); +static void +get_lib_data(void*, void*, size_t, off_t); +static void* +seek_lib_data(void*, off_t); static char * find_in_dir(const char *, char *); static void @@ -214,12 +214,20 @@ comp_map(struct Compartment *to_map) { assert(!(to_map->mapped)); struct SegmentMap *curr_seg; - void *map_result; // Map compartment library dependencies segments struct LibDependency *lib_dep; struct SegmentMap lib_dep_seg; int lib_dep_fd; + + void* map_result = mmap(to_map->base, (intptr_t) ((char*) to_map->mem_top - (char*) to_map->base), + PROT_READ | PROT_WRITE | PROT_EXEC, // TODO fix + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + if (map_result == MAP_FAILED) + { + err(1, "Error mapping compartment %zu data", to_map->id); + } + for (size_t i = 0; i < to_map->libs_count; ++i) { lib_dep = to_map->libs[i]; @@ -227,20 +235,10 @@ comp_map(struct Compartment *to_map) for (size_t j = 0; j < lib_dep->lib_segs_count; ++j) { lib_dep_seg = lib_dep->lib_segs[j]; - map_result = mmap((char *) lib_dep->lib_mem_base - + (uintptr_t) lib_dep_seg.mem_bot, - lib_dep_seg.mem_sz, - PROT_READ | PROT_WRITE | PROT_EXEC, // TODO fix - MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); - if (map_result == MAP_FAILED) - { - err(1, "Error mapping library %s dependency segment idx %zu", - lib_dep->lib_name, j); - } do_pread(lib_dep_fd, - (char *) lib_dep->lib_mem_base - + (uintptr_t) lib_dep_seg.mem_bot, - lib_dep_seg.file_sz, lib_dep_seg.offset); + (char*) lib_dep->lib_mem_base + + (uintptr_t) lib_dep_seg.mem_bot, + lib_dep_seg.file_sz, lib_dep_seg.offset); } close(lib_dep_fd); } @@ -269,13 +267,9 @@ comp_map(struct Compartment *to_map) 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) + memcpy(to_map->environ_ptr, to_map->cc->env_ptr, to_map->cc->env_ptr_sz); + for (unsigned short i = 0; i < to_map->cc->env_ptr_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; } @@ -309,6 +303,27 @@ comp_map(struct Compartment *to_map) to_map->mapped = true; } +void +comp_unmap(struct Compartment* to_unmap) +{ + int res; + + res = munmap(to_unmap->base, (intptr_t) ((char*) to_unmap->mem_top - (char*) to_unmap->base)); + if (res == -1) + { + err(1, "Error unmapping compartment %zu data", to_unmap->id); + } + + res + = munmap((void *) to_unmap->scratch_mem_base, to_unmap->scratch_mem_size); + if (res == -1) + { + err(1, "Error unmapping compartment %zu scratch memory", to_unmap->id); + } + + to_unmap->mapped = false; +} + /* Execute a mapped compartment, by jumping to the appropriate entry point. * * The entry point is given as a function name in the `fn_name` argument, and @@ -374,7 +389,7 @@ comp_clean(struct Compartment *to_clean) { if (to_clean->mapped) { - // TODO unmap + comp_unmap(to_clean); } struct LibDependency *curr_lib_dep; @@ -467,9 +482,19 @@ parse_lib_file(char *lib_name, struct Compartment *new_comp) } } + struct stat lib_fd_stat; + if (fstat(lib_fd, &lib_fd_stat) == -1) + { + err(1, "Error accessing data for file %s", lib_path); + } + void* lib_data = mmap(NULL, lib_fd_stat.st_size, PROT_READ, MAP_PRIVATE, + lib_fd, 0); + close(lib_fd); + // Read ELF headers Elf64_Ehdr lib_ehdr; - do_pread(lib_fd, &lib_ehdr, sizeof(Elf64_Ehdr), 0); + get_lib_data(&lib_ehdr, lib_data, sizeof(Elf64_Ehdr), 0); + if (lib_ehdr.e_type != ET_DYN) { errx(1, @@ -491,14 +516,13 @@ parse_lib_file(char *lib_name, struct Compartment *new_comp) strcpy(new_lib->lib_path, lib_name); } - parse_lib_segs(&lib_ehdr, lib_fd, new_lib, new_comp); + parse_lib_segs(&lib_ehdr, lib_data, new_lib, new_comp); // Load `.shstr` section, so we can check section names Elf64_Shdr shstrtab_hdr; - do_pread(lib_fd, &shstrtab_hdr, sizeof(Elf64_Shdr), + get_lib_data(&shstrtab_hdr, lib_data, sizeof(Elf64_Shdr), lib_ehdr.e_shoff + lib_ehdr.e_shstrndx * sizeof(Elf64_Shdr)); - char *shstrtab = malloc(shstrtab_hdr.sh_size); - do_pread(lib_fd, shstrtab, shstrtab_hdr.sh_size, shstrtab_hdr.sh_offset); + char* shstrtab = (char*) seek_lib_data(lib_data, shstrtab_hdr.sh_offset); // XXX The string table is read in `strtab` as a sequence of // variable-length strings. Then, symbol names are obtained by indexing at @@ -526,28 +550,28 @@ parse_lib_file(char *lib_name, struct Compartment *new_comp) Elf64_Shdr curr_shdr; for (size_t i = 0; i < lib_ehdr.e_shnum; ++i) { - do_pread(lib_fd, &curr_shdr, sizeof(Elf64_Shdr), + get_lib_data(&curr_shdr, lib_data, sizeof(Elf64_Shdr), lib_ehdr.e_shoff + i * sizeof(Elf64_Shdr)); if (curr_shdr.sh_type == SHT_SYMTAB || curr_shdr.sh_type == SHT_DYNSYM) { - parse_lib_symtb(&curr_shdr, &lib_ehdr, lib_fd, new_lib); + parse_lib_symtb(&curr_shdr, &lib_ehdr, lib_data, new_lib); } // Lookup `.rela.plt` to eagerly load relocatable function addresses else if (curr_shdr.sh_type == SHT_RELA && !strcmp(&shstrtab[curr_shdr.sh_name], ".rela.plt")) { - parse_lib_rela(&curr_shdr, &lib_ehdr, lib_fd, new_lib); + parse_lib_rela(&curr_shdr, &lib_ehdr, lib_data, new_lib); } else if (curr_shdr.sh_type == SHT_RELA && !strcmp(&shstrtab[curr_shdr.sh_name], ".rela.dyn")) { - parse_lib_rela(&curr_shdr, &lib_ehdr, lib_fd, new_lib); + parse_lib_rela(&curr_shdr, &lib_ehdr, lib_data, new_lib); } // Lookup `.dynamic` to find library dependencies else if (curr_shdr.sh_type == SHT_DYNAMIC) { - parse_lib_dynamic_deps(&curr_shdr, &lib_ehdr, lib_fd, new_lib); + parse_lib_dynamic_deps(&curr_shdr, &lib_ehdr, lib_data, new_lib); } // Section containing TLS static data else if (curr_shdr.sh_type == SHT_PROGBITS @@ -558,7 +582,6 @@ parse_lib_file(char *lib_name, struct Compartment *new_comp) } } - close(lib_fd); new_comp->libs_count += 1; new_comp->libs = realloc( new_comp->libs, new_comp->libs_count * sizeof(struct LibDependency *)); @@ -569,20 +592,18 @@ parse_lib_file(char *lib_name, struct Compartment *new_comp) new_comp->comp_syms, new_lib->lib_syms, new_comp->libs_count - 1); } - free(shstrtab); - return new_lib; } static void -parse_lib_segs(Elf64_Ehdr *lib_ehdr, int lib_fd, struct LibDependency *lib_dep, +parse_lib_segs(Elf64_Ehdr *lib_ehdr, void* lib_data, struct LibDependency *lib_dep, struct Compartment *new_comp) { // Get segment data Elf64_Phdr lib_phdr; for (size_t i = 0; i < lib_ehdr->e_phnum; ++i) { - do_pread(lib_fd, &lib_phdr, sizeof(Elf64_Phdr), + get_lib_data(&lib_phdr, lib_data, sizeof(Elf64_Phdr), lib_ehdr->e_phoff + i * sizeof(lib_phdr)); if (lib_phdr.p_type == PT_TLS) @@ -634,19 +655,17 @@ parse_lib_segs(Elf64_Ehdr *lib_ehdr, int lib_fd, struct LibDependency *lib_dep, } static void -parse_lib_symtb(Elf64_Shdr *symtb_shdr, Elf64_Ehdr *lib_ehdr, int lib_fd, +parse_lib_symtb(Elf64_Shdr *symtb_shdr, Elf64_Ehdr *lib_ehdr, void* lib_data, struct LibDependency *lib_dep) { // Get symbol table Elf64_Shdr link_shdr; assert(symtb_shdr->sh_link); - do_pread(lib_fd, &link_shdr, sizeof(Elf64_Shdr), + get_lib_data(&link_shdr, lib_data, sizeof(Elf64_Shdr), lib_ehdr->e_shoff + symtb_shdr->sh_link * sizeof(Elf64_Shdr)); - Elf64_Sym *sym_tb = malloc(symtb_shdr->sh_size); - do_pread(lib_fd, sym_tb, symtb_shdr->sh_size, symtb_shdr->sh_offset); - char *str_tb = malloc(link_shdr.sh_size); - do_pread(lib_fd, str_tb, link_shdr.sh_size, link_shdr.sh_offset); + Elf64_Sym* sym_tb = (Elf64_Sym*) seek_lib_data(lib_data, symtb_shdr->sh_offset); + char* str_tb = (char*) seek_lib_data(lib_data, link_shdr.sh_offset); size_t lib_syms_count = symtb_shdr->sh_size / sizeof(Elf64_Sym); size_t actual_syms = 0; @@ -677,32 +696,26 @@ parse_lib_symtb(Elf64_Shdr *symtb_shdr, Elf64_Ehdr *lib_ehdr, int lib_fd, to_insert->sym_shndx = curr_sym.st_shndx; lib_syms_insert(to_insert, lib_dep->lib_syms); } - - free(sym_tb); - free(str_tb); } static void -parse_lib_rela(Elf64_Shdr *rela_shdr, Elf64_Ehdr *lib_ehdr, int lib_fd, +parse_lib_rela(Elf64_Shdr *rela_shdr, Elf64_Ehdr *lib_ehdr, void* lib_data, struct LibDependency *lib_dep) { // Traverse `.rela.plt`, so we can see which function addresses we need // to eagerly load - Elf64_Rela *rela_sec = malloc(rela_shdr->sh_size); - do_pread(lib_fd, rela_sec, rela_shdr->sh_size, rela_shdr->sh_offset); + Elf64_Rela* rela_sec = (Elf64_Rela*) seek_lib_data(lib_data, rela_shdr->sh_offset); size_t rela_count = rela_shdr->sh_size / sizeof(Elf64_Rela); Elf64_Shdr dyn_sym_hdr; - do_pread(lib_fd, &dyn_sym_hdr, sizeof(Elf64_Shdr), + get_lib_data(&dyn_sym_hdr, lib_data, sizeof(Elf64_Shdr), lib_ehdr->e_shoff + rela_shdr->sh_link * sizeof(Elf64_Shdr)); - Elf64_Sym *dyn_sym_tbl = malloc(dyn_sym_hdr.sh_size); - do_pread(lib_fd, dyn_sym_tbl, dyn_sym_hdr.sh_size, dyn_sym_hdr.sh_offset); + Elf64_Sym *dyn_sym_tbl = (Elf64_Sym*) seek_lib_data(lib_data, dyn_sym_hdr.sh_offset); Elf64_Shdr dyn_str_hdr; - do_pread(lib_fd, &dyn_str_hdr, sizeof(Elf64_Shdr), + get_lib_data(&dyn_str_hdr, lib_data, sizeof(Elf64_Shdr), lib_ehdr->e_shoff + dyn_sym_hdr.sh_link * sizeof(Elf64_Shdr)); - char *dyn_str_tbl = malloc(dyn_str_hdr.sh_size); - do_pread(lib_fd, dyn_str_tbl, dyn_str_hdr.sh_size, dyn_str_hdr.sh_offset); + char *dyn_str_tbl = (char*) seek_lib_data(lib_data, dyn_str_hdr.sh_offset); // XXX Since TLSDESC entries might resolve to two relocation slots, we // ensure we have enough space by doubling the expected relocation counts @@ -856,24 +869,18 @@ parse_lib_rela(Elf64_Shdr *rela_shdr, Elf64_Ehdr *lib_ehdr, int lib_fd, lib_dep->rela_maps_count += actual_relas; free(new_relas); - free(rela_sec); - free(dyn_sym_tbl); - free(dyn_str_tbl); } static void parse_lib_dynamic_deps(Elf64_Shdr *dynamic_shdr, Elf64_Ehdr *lib_ehdr, - int lib_fd, struct LibDependency *lib_dep) + void* lib_data, struct LibDependency *lib_dep) { // Find additional library dependencies - Elf64_Dyn *dyn_entries = malloc(dynamic_shdr->sh_size); - do_pread( - lib_fd, dyn_entries, dynamic_shdr->sh_size, dynamic_shdr->sh_offset); + Elf64_Dyn *dyn_entries = (Elf64_Dyn*) seek_lib_data(lib_data, dynamic_shdr->sh_offset); Elf64_Shdr dynstr_shdr; - do_pread(lib_fd, &dynstr_shdr, sizeof(Elf64_Shdr), + get_lib_data(&dynstr_shdr, lib_data, sizeof(Elf64_Shdr), lib_ehdr->e_shoff + dynamic_shdr->sh_link * sizeof(Elf64_Shdr)); - char *dynstr_tbl = malloc(dynstr_shdr.sh_size); - do_pread(lib_fd, dynstr_tbl, dynstr_shdr.sh_size, dynstr_shdr.sh_offset); + char *dynstr_tbl = (char*) seek_lib_data(lib_data, dynstr_shdr.sh_offset); for (size_t i = 0; i < dynamic_shdr->sh_size / sizeof(Elf64_Dyn); ++i) { @@ -888,9 +895,6 @@ parse_lib_dynamic_deps(Elf64_Shdr *dynamic_shdr, Elf64_Ehdr *lib_ehdr, lib_dep->lib_dep_count += 1; } } - - free(dynstr_tbl); - free(dyn_entries); } static void @@ -1084,6 +1088,18 @@ do_pread(int fd, void *buf, size_t count, off_t offset) return res; } +static void +get_lib_data(void* buf, void* lib_file_addr, size_t data_sz, off_t offset) +{ + memcpy(buf, (char*) lib_file_addr + offset, data_sz); +} + +static void* +seek_lib_data(void* lib_data, off_t offset) +{ + return (void*) ((char*) lib_data + offset); +} + static void * eval_sym_offset(struct Compartment *comp, const comp_symbol *sym) { @@ -1217,9 +1233,9 @@ get_extra_scratch_region_base(struct Compartment *new_comp) static void setup_environ(struct Compartment *new_comp) { - assert(proc_env_ptr != NULL); // TODO consider optional check + assert(new_comp->cc->env_ptr != NULL); // TODO consider optional check new_comp->environ_sz - = align_up(max_env_sz, new_comp->page_size) + new_comp->page_size; + = align_up(new_comp->cc->env_ptr_sz, new_comp->page_size) + new_comp->page_size; new_comp->environ_ptr = get_extra_scratch_region_base(new_comp); adjust_comp_scratch_mem(new_comp, new_comp->environ_sz); } diff --git a/src/manager.c b/src/manager.c index 1f5f3dc..6f35fa2 100644 --- a/src/manager.c +++ b/src/manager.c @@ -19,6 +19,8 @@ void *__capability manager_ddc = 0; const char *comp_config_suffix = ".comp"; char **proc_env_ptr = NULL; +size_t proc_env_ptr_sz = 0; +unsigned short proc_env_count = 0; const unsigned short avg_sz_per_env_entry = 128; // TODO const unsigned short max_env_count = 128; // TODO const size_t max_env_sz @@ -113,10 +115,12 @@ register_new_comp(char *filename, bool allow_default_entry) struct CompConfig *new_cc = parse_compartment_config_file(filename, allow_default_entry); new_cc->base_address = get_next_comp_addr(); + new_cc->env_ptr = proc_env_ptr; + new_cc->env_ptr_sz = proc_env_ptr_sz; + new_cc->env_ptr_count = proc_env_count; struct Compartment *new_comp = comp_from_elf(filename, new_cc); new_comp->id = comps_count; - new_comp->cc = new_cc; void *__capability new_comp_ddc = cheri_address_set(cheri_ddc_get(), (intptr_t) new_comp->base); new_comp_ddc = cheri_bounds_set( @@ -364,21 +368,22 @@ 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 *); + /*char **proc_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); + proc_env_ptr[proc_env_count] = (char *) (vals_offset + proc_env_ptr_sz); + strcpy((char *) proc_env_ptr + vals_offset + proc_env_ptr_sz, *curr_env); - envs_parsed += 1; - envs_parsed_sz += strlen(*curr_env) + 1; + proc_env_count += 1; + proc_env_ptr_sz += strlen(*curr_env) + 1; } + proc_env_ptr_sz += vals_offset; + proc_env_ptr = realloc(proc_env_ptr, proc_env_ptr_sz); + } static void * diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1b5bc7a..82a5306 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,12 @@ add_executable(manager_call target_include_directories(manager_call PUBLIC ${BIN_INCLUDE_DIRS}) target_link_libraries(manager_call PUBLIC chcomp) +add_executable(manager_call_multi + ${TEST_DIR}/manager_caller_multiple.c + ) +target_include_directories(manager_call_multi PUBLIC ${BIN_INCLUDE_DIRS}) +target_link_libraries(manager_call_multi PUBLIC chcomp) + add_executable(manager_args ${TEST_DIR}/manager_arg_passer.c ) @@ -130,6 +136,7 @@ endfunction() # Library tests set(func_binaries "test_map" + "test_map_multi" #"test_args_near_unmapped" #"test_two_comps" #"test_two_comps_inter_call" @@ -205,6 +212,7 @@ set(tests "lua_suite_some" "test_map" + "test_map_multi" #"test_args_near_unmapped" #"test_two_comps" #"test_two_comps_inter_call" diff --git a/tests/compartment_harness.c b/tests/compartment_harness.c index 71046a9..285d195 100644 --- a/tests/compartment_harness.c +++ b/tests/compartment_harness.c @@ -60,7 +60,9 @@ main(int argc, char **argv) mock_cc->base_address = (void *) 0x1000000UL; struct Compartment *hw_comp = comp_from_elf(file, mock_cc); + hw_comp->id = 0; + comp_map(hw_comp); comp_clean(hw_comp); return 0; } diff --git a/tests/manager_caller_multiple.c b/tests/manager_caller_multiple.c new file mode 100644 index 0000000..131762e --- /dev/null +++ b/tests/manager_caller_multiple.c @@ -0,0 +1,30 @@ +#include "manager.h" + +int +main(int argc, char **argv) +{ + const char* count_env_name = "EXECUTE_COUNT"; + const char* count_env_val = getenv(count_env_name); + const unsigned int comps_count_default = 100; + unsigned int comps_count = count_env_val ? atoi(count_env_val) : comps_count_default; + + // Initial setup + manager_ddc = cheri_ddc_get(); + setup_intercepts(); + + assert(argc >= 2 + && "Expect at least one argument: binary file for compartment"); + char *file = argv[1]; + + struct Compartment *hw_comp = register_new_comp(file, true); + int comp_result = 0; + for (size_t i = 0; i < comps_count; ++i) + { + comp_map(hw_comp); + comp_result = (exec_comp(hw_comp, "main", NULL) != 0) || comp_result; + comp_unmap(hw_comp); + } + comp_clean(hw_comp); + assert(!comp_result); + return comp_result; +} diff --git a/tests/test_map_multi.c b/tests/test_map_multi.c new file mode 100644 index 0000000..ebf9f51 --- /dev/null +++ b/tests/test_map_multi.c @@ -0,0 +1,20 @@ +#include "compartment.c" +#include "manager.h" + +int +main() +{ + manager_ddc = cheri_ddc_get(); + setup_intercepts(); + + char *file = "./simple.so"; + struct Compartment *hw_comp = register_new_comp(file, true); + for (size_t i = 0; i < 100; ++i) + { + comp_map(hw_comp); + comp_unmap(hw_comp); + } + comp_clean(hw_comp); + return 0; +} +