From 02547b124dc41a129746d6cdcdf55edde9b09384 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Thu, 28 Dec 2023 00:58:15 +0800 Subject: [PATCH] feat: pass config instead of getenv --- CMakeLists.txt | 6 +++ launcher.c | 106 +++++++++++++++++++++++++++++++------------------ launcher.h | 24 +++++------ library.c | 18 +++++++-- resource.c | 10 ++--- resource.h | 4 +- rules/rules.c | 9 ++--- rules/rules.h | 6 +-- sandbox.c | 22 +++++----- sandbox.h | 7 +++- 10 files changed, 128 insertions(+), 84 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e75a4c..4a851f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,17 +20,23 @@ 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_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) # 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}) +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}) + # Optimization include(CheckIPOSupported) check_ipo_supported(RESULT ipo_result OUTPUT ipo_output) diff --git a/launcher.c b/launcher.c index c55c594..4f06c27 100644 --- a/launcher.c +++ b/launcher.c @@ -15,7 +15,7 @@ #include #include -char *config[is_valid + 1]; +char *config[CFG_IS_VALID + 1]; void print_help(char *self) { LOG_WARN("Usage:"); @@ -36,33 +36,33 @@ void print_help(char *self) { void parse(int argc, char *argv[]) { static struct option options[] = { - [memory_limit] = {"memory_limit", required_argument, NULL, 0}, - [nproc_limit] = {"nproc_limit", required_argument, NULL, 0}, - [time_limit] = {"time_limit", required_argument, NULL, 0}, - [sandbox_path] = {"sandbox_path", required_argument, NULL, 0}, - [sandbox_template] = {"sandbox_template", required_argument, NULL, 0}, - [sandbox_action] = {"sandbox_action", required_argument, NULL, 0}, - [file_input] = {"file_input", required_argument, NULL, 0}, - [file_output] = {"file_output", required_argument, NULL, 0}, - [file_info] = {"file_info", required_argument, NULL, 0}, - [program] = {"program", required_argument, NULL, 0}, - [is_valid] = {"help", no_argument, NULL, 0}, - [is_valid + 1] = {NULL, 0, NULL, 0} + [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}, + [CFG_FILE_OUTPUT] = {"file_output", required_argument, NULL, 0}, + [CFG_FILE_INFO] = {"file_info", required_argument, NULL, 0}, + [CFG_PROGRAM] = {"program", required_argument, NULL, 0}, + [CFG_IS_VALID] = {"help", no_argument, NULL, 0}, + [CFG_IS_VALID + 1] = {NULL, 0, NULL, 0} }; int c, idx = 0; while ((c = getopt_long_only(argc, argv, "", options, &idx)) != -1) { if (c != 0) break; - if (idx < is_valid) + if (idx < CFG_IS_VALID) config[idx] = optarg; - else if (idx == is_valid) { + else if (idx == CFG_IS_VALID) { print_help(argv[0]); exit(0); } } - for (int i = 0; i < is_valid; i++) { + for (int i = 0; i < CFG_IS_VALID; i++) { if (!config[i]) { print_help(argv[0]); LOG_ERR("Missing arguments"); @@ -70,51 +70,74 @@ void parse(int argc, char *argv[]) { } } - config[is_valid] = (char *)1; + config[CFG_IS_VALID] = (char *)1; } void launch_child() { - char *args[] = {config[program], NULL}; + char *args[] = {config[CFG_PROGRAM], NULL}; char *env[8]; /* build env */ { - env[0] = malloc(sizeof("LD_PRELOAD=") + strlen(config[sandbox_path]) + 1); - sprintf(env[0], "LD_PRELOAD=%s", config[sandbox_path]); + 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[memory_limit]) + 1); - sprintf(env[1], LIMIT_MEMORY "=%s", config[memory_limit]); + 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[nproc_limit]) + 1); - sprintf(env[2], LIMIT_NPROC "=%s", config[nproc_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[time_limit]) + 1); - sprintf(env[3], LIMIT_TIME "=%s", config[time_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[sandbox_template]) + 1); - sprintf(env[4], SANDBOX_TEMPLATE "=%s", config[sandbox_template]); + 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[sandbox_action]) + 1); - sprintf(env[5], SANDBOX_ACTION "=%s", config[sandbox_action]); + 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[program]) + 1); - sprintf(env[6], SANDBOX_EXE_PATH "=%s", config[program]); + 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[file_input], O_RDONLY); + int fd = open(config[CFG_FILE_INPUT], O_RDONLY); dup2(fd, STDIN_FILENO); close(fd); } /* build stdout */ { - int fd = open(config[file_output], O_WRONLY | O_CREAT, 0644); + int fd = open(config[CFG_FILE_OUTPUT], O_WRONLY | O_CREAT, 0644); dup2(fd, STDOUT_FILENO); close(fd); } - execve(config[program], args, env); + 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 */ { + 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); + } + + setup_all(); + + execve(config[CFG_PROGRAM], args, nullptr); } void dump_info(FILE *dest, struct rusage *usage, int status, long long time_usage) { @@ -137,7 +160,14 @@ int main(int argc, char *argv[]) { exit(ERR_FORK); } else if (child == 0) { // Program - launch_child(); + if (!setup_all) { + LOG_INFO("Using preload sandbox"); + launch_child(); + } else { + LOG_INFO("Using inplace sandbox"); + launch_child2(); + } + LOG_ERR("Failed to execute child program"); exit(ERR_EXEC); @@ -148,7 +178,7 @@ int main(int argc, char *argv[]) { exit(ERR_FORK); } else if (killer == 0) { // Killer - long limit = (strtol(config[time_limit], NULL, 10) + 1000) / 1000 + 2; + long limit = (strtol(config[CFG_TIME_LIMIT], NULL, 10) + 1000) / 1000 + 2; LOG_INFO("Killer started, time limit: %lds", limit); sleep(limit); // two more seconds LOG_WARN("Killer killed child"); @@ -175,7 +205,7 @@ int main(int argc, char *argv[]) { exit(ERR_WAIT); } - FILE *info = fopen(config[file_info], "w"); + FILE *info = fopen(config[CFG_FILE_INFO], "w"); dump_info(info, &usage, status, time_usage); exit(0); } diff --git a/launcher.h b/launcher.h index d8c7c58..9ed0013 100644 --- a/launcher.h +++ b/launcher.h @@ -2,19 +2,17 @@ #define WOJ_SANDBOX_LAUNCHER_H enum ConfigIndex { - memory_limit = 0, - nproc_limit, - time_limit, - sandbox_path, - sandbox_template, - sandbox_action, - file_input, - file_output, - file_info, - program, - is_valid + CFG_MEMORY_LIMIT = 0, + CFG_NPROC_LIMIT, + CFG_TIME_LIMIT, + CFG_SANDBOX_PATH, + CFG_SANDBOX_TEMPLATE, + CFG_SANDBOX_ACTION, + CFG_FILE_INPUT, + CFG_FILE_OUTPUT, + CFG_FILE_INFO, + CFG_PROGRAM, + CFG_IS_VALID }; -char *config[is_valid + 1] __attribute__((weak)); - #endif // WOJ_SANDBOX_LAUNCHER_H diff --git a/library.c b/library.c index 0b480f0..2f9093b 100644 --- a/library.c +++ b/library.c @@ -1,12 +1,14 @@ -#include "launcher.h" #include "resource.h" #include "rules/lang.h" #include "sandbox.h" #include "utils/log.h" #include +#include #include +char *config[CFG_IS_VALID + 1] __attribute__((weak)); + void setup_all(void) { char comm[64]; int fd = open("/proc/self/comm", O_RDONLY); @@ -17,13 +19,21 @@ void setup_all(void) { LOG_INFO("Setting up sandbox for %s(%d)", comm, getpid()); - if (config[is_valid]) { + if (config[CFG_IS_VALID]) { LOG_INFO("Using config from launcher"); } else { LOG_INFO("Using config from environment"); + + config[CFG_MEMORY_LIMIT] = getenv(LIMIT_MEMORY); + config[CFG_NPROC_LIMIT] = getenv(LIMIT_NPROC); + config[CFG_TIME_LIMIT] = getenv(LIMIT_TIME); + + config[CFG_SANDBOX_TEMPLATE] = getenv(SANDBOX_TEMPLATE); + config[CFG_SANDBOX_ACTION] = getenv(SANDBOX_ACTION); + config[CFG_PROGRAM] = getenv(SANDBOX_EXE_PATH); } register_lang_c_cpp(); - setup_rlimit(); - setup_seccomp(); + setup_rlimit(config); + setup_seccomp(config); } diff --git a/resource.c b/resource.c index 61c51ce..226686a 100644 --- a/resource.c +++ b/resource.c @@ -16,18 +16,18 @@ } \ } while (0) -void setup_rlimit(void) { +void setup_rlimit(char *config[CFG_IS_VALID + 1]) { LOG_INFO("Setting resource limit"); - char *mem_limit_str = getenv(LIMIT_MEMORY); // in mb - char *nproc_limit_str = getenv(LIMIT_NPROC); - char *time_limit_str = getenv(LIMIT_TIME); // in ms + char *mem_limit_str = config[CFG_MEMORY_LIMIT]; // in mb + char *nproc_limit_str = config[CFG_NPROC_LIMIT]; + char *time_limit_str = config[CFG_TIME_LIMIT]; // in ms long mem_limit = 0, nproc_limit = 0, time_limit = 0; if (mem_limit_str) { // convert to bytes and double the memory limit - mem_limit = strtol(mem_limit_str, NULL, 10) * 1024 * 1024 * 2; + mem_limit = strtol(mem_limit_str, NULL, 10) * 1024 * 1024; } if (nproc_limit_str) { diff --git a/resource.h b/resource.h index 4f2761d..25cf6a1 100644 --- a/resource.h +++ b/resource.h @@ -1,11 +1,13 @@ #ifndef WOJ_SANDBOX_RESOURCE_H #define WOJ_SANDBOX_RESOURCE_H +#include "launcher.h" + // Configuration Environment Variables #define LIMIT_MEMORY "LIMIT_MEMORY" #define LIMIT_TIME "LIMIT_TIME" #define LIMIT_NPROC "LIMIT_NPROC" -void setup_rlimit(void); +void setup_rlimit(char *config[CFG_IS_VALID + 1]); #endif // WOJ_SANDBOX_RESOURCE_H diff --git a/rules/rules.c b/rules/rules.c index e6315ad..d808b25 100644 --- a/rules/rules.c +++ b/rules/rules.c @@ -10,17 +10,16 @@ LIST_HEAD(seccomp_rules); void register_rule(struct rule *rule) { list_add(&rule->list, &seccomp_rules); } -void setup_self(scmp_filter_ctx ctx) { +void setup_self(scmp_filter_ctx ctx, const char *exe_path) { // allow to execute self - char *self = getenv(SANDBOX_EXE_PATH); - if (self) add_syscall_nr_arg(SCMP_SYS(execve), ctx, SCMP_ACT_ALLOW, 1, SCMP_A0(SCMP_CMP_EQ, (scmp_datum_t)self)); + add_syscall_nr_arg(SCMP_SYS(execve), ctx, SCMP_ACT_ALLOW, 1, &SCMP_A0(SCMP_CMP_EQ, (scmp_datum_t)exe_path)); } -void setup_rule(char *name, scmp_filter_ctx ctx) { +void setup_rule(const char *name, scmp_filter_ctx ctx, const char *exe_path) { struct list_head *current; struct rule *rule; - setup_self(ctx); + setup_self(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 219b6c4..e7b15a5 100644 --- a/rules/rules.h +++ b/rules/rules.h @@ -6,13 +6,13 @@ #include "seccomp.h" struct rule { - char *name; - void (*setup)(scmp_filter_ctx); + char *name; + void (*setup)(scmp_filter_ctx); struct list_head list; }; void register_rule(struct rule *rule); -void setup_rule(char *name, scmp_filter_ctx ctx); +void setup_rule(const char *name, scmp_filter_ctx ctx, const char *exe_path); void dump_rules(void); #endif // WOJ_SANDBOX_RULES_H diff --git a/sandbox.c b/sandbox.c index 986d89d..58146cf 100644 --- a/sandbox.c +++ b/sandbox.c @@ -16,17 +16,13 @@ void add_syscall_nr(int syscall_nr, scmp_filter_ctx ctx, uint32_t action) { } } -void add_syscall_nr_arg(int syscall_nr, scmp_filter_ctx ctx, uint32_t action, unsigned arg_cnt, ...) { - va_list(args); - va_start(args, arg_cnt); - - if (seccomp_rule_add(ctx, action, syscall_nr, arg_cnt, args)) { +void add_syscall_nr_arg(int syscall_nr, scmp_filter_ctx ctx, uint32_t action, unsigned arg_cnt, + const struct scmp_arg_cmp *args) { + if (seccomp_rule_add_array(ctx, action, syscall_nr, arg_cnt, args)) { LOG_ERR("Failed to add syscall %d", syscall_nr); seccomp_release(ctx); exit(ERR_SECCOMP_RESOLVE); } - - va_end(args); } void add_syscall_name(const char *syscall_name, scmp_filter_ctx ctx, uint32_t action) { @@ -40,14 +36,14 @@ void add_syscall_name(const char *syscall_name, scmp_filter_ctx ctx, uint32_t ac add_syscall_nr(syscall_nr, ctx, action); } -void setup_seccomp(void) { +void setup_seccomp(char *config[CFG_IS_VALID + 1]) { LOG_INFO("Setting seccomp rules..."); - char *template = getenv(SANDBOX_TEMPLATE); - char *action = getenv(SANDBOX_ACTION); + char *template = config[CFG_SANDBOX_TEMPLATE]; + char *action = config[CFG_SANDBOX_ACTION]; + char *exe_path = config[CFG_PROGRAM]; - uint32_t act = SCMP_ACT_KILL; - bool disabled = false; + uint32_t act = SCMP_ACT_KILL; if (action && strncmp(action, "log", sizeof("log")) == 0) act = SCMP_ACT_LOG; if (action && strncmp(action, "kill", sizeof("kill")) == 0) act = SCMP_ACT_KILL; @@ -69,7 +65,7 @@ void setup_seccomp(void) { exit(ERR_SECCOMP_INIT); } - setup_rule(template, ctx); + setup_rule(template, ctx, exe_path); if (seccomp_load(ctx)) { LOG_ERR("Failed to load seccomp context"); diff --git a/sandbox.h b/sandbox.h index 82adece..3c0beab 100644 --- a/sandbox.h +++ b/sandbox.h @@ -1,6 +1,7 @@ #ifndef WOJ_SANDBOX_SANDBOX_H #define WOJ_SANDBOX_SANDBOX_H +#include "launcher.h" #include #include @@ -9,9 +10,11 @@ #define SANDBOX_ACTION "SANDBOX_ACTION" #define SANDBOX_EXE_PATH "SANDBOX_EXE_PATH" -void setup_seccomp(void); +void setup_seccomp(char *config[CFG_IS_VALID + 1]); + void add_syscall_nr(int syscall_nr, scmp_filter_ctx ctx, uint32_t action); -void add_syscall_nr_arg(int syscall_nr, scmp_filter_ctx ctx, uint32_t action, unsigned arg_cnt, ...); +void add_syscall_nr_arg(int syscall_nr, scmp_filter_ctx ctx, uint32_t action, unsigned arg_cnt, + const struct scmp_arg_cmp *args); void add_syscall_name(const char *syscall_name, scmp_filter_ctx ctx, uint32_t action); #endif // WOJ_SANDBOX_SANDBOX_H