diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a851f8..8d6cb5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,10 @@ project(woj_sandbox C) set(CMAKE_C_STANDARD 23) +# Check IPO +include(CheckIPOSupported) +check_ipo_supported(RESULT ipo_result OUTPUT ipo_output) + # Handle __FILE__ in logging set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmacro-prefix-map=${CMAKE_SOURCE_DIR}=.") @@ -19,30 +23,22 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libseccomp/include) # Targets add_library(woj_sandbox SHARED ${PROJECT_SOURCE_DIR}/library.c ${PROJECT_SOURCE_DIR}/inject.c ${SRC_FILES}) -add_executable(woj_launcher ${PROJECT_SOURCE_DIR}/launcher.c) -add_executable(woj_launcher2 ${PROJECT_SOURCE_DIR}/library.c ${PROJECT_SOURCE_DIR}/launcher.c ${SRC_FILES}) +add_executable(woj_launcher ${PROJECT_SOURCE_DIR}/library.c ${PROJECT_SOURCE_DIR}/launcher.c ${SRC_FILES}) add_executable(woj_test ${PROJECT_SOURCE_DIR}/test.c) -# Link seccomp -target_link_libraries(woj_sandbox ${CMAKE_SOURCE_DIR}/libseccomp/src/.libs/libseccomp.a) -target_link_libraries(woj_launcher ${CMAKE_SOURCE_DIR}/libseccomp/src/.libs/libseccomp.a) -target_link_libraries(woj_launcher2 ${CMAKE_SOURCE_DIR}/libseccomp/src/.libs/libseccomp.a) +set(TARGETS woj_sandbox woj_launcher) -# Disable symbol export -set_target_properties(woj_sandbox PROPERTIES C_VISIBILITY_PRESET hidden) -set_property(TARGET woj_sandbox APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--version-script=${VERSION_SCRIPT}") -set_target_properties(woj_sandbox PROPERTIES LINK_DEPENDS ${VERSION_SCRIPT}) +foreach (TARGET ${TARGETS}) + # Link seccomp + target_link_libraries(${TARGET} ${CMAKE_SOURCE_DIR}/libseccomp/src/.libs/libseccomp.a) -set_target_properties(woj_launcher2 PROPERTIES C_VISIBILITY_PRESET hidden) -set_property(TARGET woj_launcher2 APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--version-script=${VERSION_SCRIPT}") -set_target_properties(woj_launcher2 PROPERTIES LINK_DEPENDS ${VERSION_SCRIPT}) + # Disable symbol export + set_target_properties(${TARGET} PROPERTIES C_VISIBILITY_PRESET hidden) + set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--version-script=${VERSION_SCRIPT}") + set_target_properties(${TARGET} PROPERTIES LINK_DEPENDS ${VERSION_SCRIPT}) -# Optimization -include(CheckIPOSupported) -check_ipo_supported(RESULT ipo_result OUTPUT ipo_output) -if (ipo_result) - set_property(TARGET woj_sandbox PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) - set_property(TARGET woj_launcher PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) -else () - message(WARNING "IPO is not supported: ${ipo_output}") -endif () + # Optimization + if (ipo_result) + set_property(TARGET ${TARGET} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + endif () +endforeach (TARGET) diff --git a/inject.c b/inject.c index 043c8de..6721344 100644 --- a/inject.c +++ b/inject.c @@ -1,3 +1,3 @@ #include "library.h" -static __attribute__((constructor)) void inject(void) { setup_all(); } +static __attribute__((constructor(102))) void inject(void) { setup_all(); } diff --git a/launcher.c b/launcher.c index 2f36ed6..1e2734f 100644 --- a/launcher.c +++ b/launcher.c @@ -1,8 +1,6 @@ -#include "launcher.h" #include "err.h" #include "library.h" #include "resource.h" -#include "sandbox.h" #include "utils/log.h" #include @@ -24,7 +22,6 @@ void print_help(char *self) { LOG_WARN(" --memory_limit memory limit in MB"); LOG_WARN(" --nproc_limit number of processes limit"); LOG_WARN(" --time_limit time limit in ms"); - LOG_WARN(" --sandbox_path path to sandbox"); LOG_WARN(" --sandbox_template sandbox template"); LOG_WARN(" --sandbox_action sandbox action"); LOG_WARN(" --file_input path to input file"); @@ -39,7 +36,6 @@ void parse(int argc, char *argv[]) { [CFG_MEMORY_LIMIT] = {"memory_limit", required_argument, NULL, 0}, [CFG_NPROC_LIMIT] = {"nproc_limit", required_argument, NULL, 0}, [CFG_TIME_LIMIT] = {"time_limit", required_argument, NULL, 0}, - [CFG_SANDBOX_PATH] = {"sandbox_path", required_argument, NULL, 0}, [CFG_SANDBOX_TEMPLATE] = {"sandbox_template", required_argument, NULL, 0}, [CFG_SANDBOX_ACTION] = {"sandbox_action", required_argument, NULL, 0}, [CFG_FILE_INPUT] = {"file_input", required_argument, NULL, 0}, @@ -74,53 +70,6 @@ void parse(int argc, char *argv[]) { } void launch_child() { - char *args[] = {config[CFG_PROGRAM], NULL}; - char *env[8]; - - /* build env */ { - env[0] = malloc(sizeof("LD_PRELOAD=") + strlen(config[CFG_SANDBOX_PATH]) + 1); - sprintf(env[0], "LD_PRELOAD=%s", config[CFG_SANDBOX_PATH]); - - env[1] = malloc(sizeof(LIMIT_MEMORY "=") + strlen(config[CFG_MEMORY_LIMIT]) + 1); - sprintf(env[1], LIMIT_MEMORY "=%s", config[CFG_MEMORY_LIMIT]); - - env[2] = malloc(sizeof(LIMIT_NPROC "=") + strlen(config[CFG_NPROC_LIMIT]) + 1); - sprintf(env[2], LIMIT_NPROC "=%s", config[CFG_NPROC_LIMIT]); - - env[3] = malloc(sizeof(LIMIT_TIME "=") + strlen(config[CFG_TIME_LIMIT]) + 1); - sprintf(env[3], LIMIT_TIME "=%s", config[CFG_TIME_LIMIT]); - - env[4] = malloc(sizeof(SANDBOX_TEMPLATE "=") + strlen(config[CFG_SANDBOX_TEMPLATE]) + 1); - sprintf(env[4], SANDBOX_TEMPLATE "=%s", config[CFG_SANDBOX_TEMPLATE]); - - env[5] = malloc(sizeof(SANDBOX_ACTION "=") + strlen(config[CFG_SANDBOX_ACTION]) + 1); - sprintf(env[5], SANDBOX_ACTION "=%s", config[CFG_SANDBOX_ACTION]); - - env[6] = malloc(sizeof(SANDBOX_EXE_PATH "=") + strlen(config[CFG_PROGRAM]) + 1); - sprintf(env[6], SANDBOX_EXE_PATH "=%s", config[CFG_PROGRAM]); - - env[7] = NULL; - } - - /* build stdin */ { - int fd = open(config[CFG_FILE_INPUT], O_RDONLY); - dup2(fd, STDIN_FILENO); - close(fd); - } - - /* build stdout */ { - int fd = open(config[CFG_FILE_OUTPUT], O_WRONLY | O_CREAT, 0644); - dup2(fd, STDOUT_FILENO); - close(fd); - } - - execve(config[CFG_PROGRAM], args, env); -} - -void launch_child2() { - // TODO: glibc compiled program has a very annoying setup process - LOG_WARN("launch_child2 is not implemented yet"); - char *args[] = {config[CFG_PROGRAM], NULL}; /* build stdin */ { @@ -160,14 +109,7 @@ int main(int argc, char *argv[]) { exit(ERR_FORK); } else if (child == 0) { // Program - if (!setup_all) { - LOG_INFO("Using preload sandbox"); - launch_child(); - } else { - LOG_INFO("Using inplace sandbox"); - launch_child2(); - } - + launch_child(); LOG_ERR("Failed to execute child program"); exit(ERR_EXEC); diff --git a/launcher.h b/launcher.h index 9ed0013..b16a258 100644 --- a/launcher.h +++ b/launcher.h @@ -5,7 +5,6 @@ enum ConfigIndex { CFG_MEMORY_LIMIT = 0, CFG_NPROC_LIMIT, CFG_TIME_LIMIT, - CFG_SANDBOX_PATH, CFG_SANDBOX_TEMPLATE, CFG_SANDBOX_ACTION, CFG_FILE_INPUT, diff --git a/library.c b/library.c index 2f9093b..3483341 100644 --- a/library.c +++ b/library.c @@ -1,5 +1,4 @@ #include "resource.h" -#include "rules/lang.h" #include "sandbox.h" #include "utils/log.h" @@ -33,7 +32,6 @@ void setup_all(void) { config[CFG_PROGRAM] = getenv(SANDBOX_EXE_PATH); } - register_lang_c_cpp(); setup_rlimit(config); setup_seccomp(config); } diff --git a/rules/lang.h b/rules/lang.h deleted file mode 100644 index 7210c46..0000000 --- a/rules/lang.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef WOJ_SANDBOX_LANG_H -#define WOJ_SANDBOX_LANG_H - -void register_lang_c_cpp(void); - -#endif // WOJ_SANDBOX_LANG_H diff --git a/rules/lang_c_cpp.c b/rules/lang_c_cpp.c index 9cd1f99..d1a4e08 100644 --- a/rules/lang_c_cpp.c +++ b/rules/lang_c_cpp.c @@ -1,36 +1,20 @@ -#include "../sandbox.h" -#include "lang.h" #include "rules.h" #include void setup_lang_c_cpp(scmp_filter_ctx ctx) { + // some more syscall(s) that glibc uses int white[] = { - SCMP_SYS(read), // 0 - SCMP_SYS(write), // 1 - SCMP_SYS(close), // 3 - SCMP_SYS(fstat), // 5 - SCMP_SYS(lseek), // 8 - SCMP_SYS(mmap), // 9 - SCMP_SYS(munmap), // 11 - SCMP_SYS(brk), // 12 - SCMP_SYS(pread64), // 17 - SCMP_SYS(getpid), // 39 SCMP_SYS(clone), // 56 + SCMP_SYS(arch_prctl), // 158 SCMP_SYS(futex), // 202 - SCMP_SYS(newfstatat), // 262 - SCMP_SYS(clock_gettime), // 228 - SCMP_SYS(clock_getres), // 229 - SCMP_SYS(clock_nanosleep), // 230 + SCMP_SYS(set_tid_address), // 218 SCMP_SYS(exit_group), // 231 SCMP_SYS(set_robust_list), // 273 SCMP_SYS(get_robust_list), // 274 + SCMP_SYS(rseq), // 334 }; - int white_len = sizeof(white) / sizeof(white[0]); - - for (int i = 0; i < white_len; i++) { - add_syscall_nr(white[i], ctx, SCMP_ACT_ALLOW); - } + ADD_RULE_LIST(white, SCMP_ACT_ALLOW); } struct rule lang_c_rule = { @@ -43,7 +27,7 @@ struct rule lang_cpp_rule = { .setup = setup_lang_c_cpp, }; -void register_lang_c_cpp(void) { +void __attribute__((constructor(101))) register_lang_c_cpp(void) { register_rule(&lang_c_rule); register_rule(&lang_cpp_rule); } diff --git a/rules/rules.c b/rules/rules.c index d808b25..d39a525 100644 --- a/rules/rules.c +++ b/rules/rules.c @@ -1,8 +1,8 @@ #include "rules.h" #include "../err.h" -#include "../sandbox.h" #include "../utils/log.h" +#include #include #include @@ -10,16 +10,50 @@ LIST_HEAD(seccomp_rules); void register_rule(struct rule *rule) { list_add(&rule->list, &seccomp_rules); } -void setup_self(scmp_filter_ctx ctx, const char *exe_path) { +void setup_common(scmp_filter_ctx ctx, const char *exe_path) { // allow to execute self add_syscall_nr_arg(SCMP_SYS(execve), ctx, SCMP_ACT_ALLOW, 1, &SCMP_A0(SCMP_CMP_EQ, (scmp_datum_t)exe_path)); + + // allow to read files - do not allow write, readwrite, append, create + add_syscall_nr_arg(SCMP_SYS(open), ctx, SCMP_ACT_ALLOW, 1, + &SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_EXCL, 0)); + add_syscall_nr_arg(SCMP_SYS(openat), ctx, SCMP_ACT_ALLOW, 1, + &SCMP_A2(SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_EXCL, 0)); + + // prlimit64(302) - disallow new_limit + add_syscall_nr_arg(SCMP_SYS(prlimit64), ctx, SCMP_ACT_ALLOW, 1, &SCMP_A2(SCMP_CMP_NE, 0)); + + // some commonly used syscall(s) + int white[] = { + SCMP_SYS(read), // 0 + SCMP_SYS(write), // 1 + SCMP_SYS(close), // 3 + SCMP_SYS(fstat), // 5 + SCMP_SYS(lseek), // 8 + SCMP_SYS(mmap), // 9 + SCMP_SYS(mprotect), // 10 + SCMP_SYS(munmap), // 11 + SCMP_SYS(brk), // 12 + SCMP_SYS(pread64), // 17 + SCMP_SYS(writev), // 20 + SCMP_SYS(access), // 21 + SCMP_SYS(nanosleep), // 35 + SCMP_SYS(getpid), // 39 + SCMP_SYS(clock_gettime), // 228 + SCMP_SYS(clock_getres), // 229 + SCMP_SYS(clock_nanosleep), // 230 + SCMP_SYS(newfstatat), // 262 + SCMP_SYS(getrandom), // 318 + + }; + ADD_RULE_LIST(white, SCMP_ACT_ALLOW); } void setup_rule(const char *name, scmp_filter_ctx ctx, const char *exe_path) { struct list_head *current; struct rule *rule; - setup_self(ctx, exe_path); + setup_common(ctx, exe_path); list_for_each(current, &seccomp_rules) { rule = list_entry(current, struct rule, list); diff --git a/rules/rules.h b/rules/rules.h index e7b15a5..aa06f98 100644 --- a/rules/rules.h +++ b/rules/rules.h @@ -1,10 +1,17 @@ #ifndef WOJ_SANDBOX_RULES_H #define WOJ_SANDBOX_RULES_H +#include "../sandbox.h" #include "../utils/list.h" #include "seccomp.h" +#define ADD_RULE_LIST(white_list, act) \ + do { \ + int white_len = sizeof(white_list) / sizeof(white_list[0]); \ + for (int i = 0; i < white_len; i++) add_syscall_nr(white_list[i], ctx, act); \ + } while (0) + struct rule { char *name; void (*setup)(scmp_filter_ctx); diff --git a/sandbox.c b/sandbox.c index 58146cf..5094dfe 100644 --- a/sandbox.c +++ b/sandbox.c @@ -4,7 +4,6 @@ #include "utils/log.h" #include -#include #include #include