feat: tiny sandbox

This commit is contained in:
Paul Pan 2022-10-02 14:09:25 +08:00
commit 228c7b653f
24 changed files with 351 additions and 0 deletions

14
.clang-format Normal file
View File

@ -0,0 +1,14 @@
---
BasedOnStyle: LLVM
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: AcrossEmptyLinesAndComments
AlignConsecutiveDeclarations: Consecutive
AlignEscapedNewlines: Left
AllowShortCaseLabelsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
ColumnLimit: 80
IndentWidth: 4
UseTab: Never
SeparateDefinitionBlocks: Leave

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/cmake-build-*
/build
/libseccomp
*.out

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
woj_sandbox

View File

@ -0,0 +1,7 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

10
.idea/misc.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CidrRootsConfiguration">
<excludeRoots>
<file path="$PROJECT_DIR$/build" />
<file path="$PROJECT_DIR$/libseccomp" />
</excludeRoots>
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/woj-sandbox.iml" filepath="$PROJECT_DIR$/.idea/woj-sandbox.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

2
.idea/woj-sandbox.iml Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

22
CMakeLists.txt Normal file
View File

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.23)
project(woj_sandbox C)
set(CMAKE_C_STANDARD 23)
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.c ${PROJECT_SOURCE_DIR}/rules/*.c ${PROJECT_SOURCE_DIR}/utils/*.c)
list(FILTER SRC_FILES EXCLUDE REGEX ".*test\\.c$")
set(VERSION_SCRIPT ${PROJECT_SOURCE_DIR}/version_script.txt)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libseccomp/include)
add_library(woj_sandbox SHARED ${SRC_FILES})
add_executable(woj_sandbox_test ${PROJECT_SOURCE_DIR}/test.c ${SRC_FILES})
target_link_libraries(woj_sandbox ${CMAKE_SOURCE_DIR}/libseccomp/src/.libs/libseccomp.a)
target_link_libraries(woj_sandbox_test ${CMAKE_SOURCE_DIR}/libseccomp/src/.libs/libseccomp.a)
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})

11
build_libseccomp.sh Executable file
View File

@ -0,0 +1,11 @@
VERSION=v2.5.4
if [ -d ./libseccomp ]; then exit 0; fi
set -x
git clone https://github.com/seccomp/libseccomp.git &>/dev/null
cd libseccomp || exit 1
git checkout $VERSION &>/dev/null
./autogen.sh &>/dev/null
./configure --enable-shared=no &>/dev/null
make -j &>/dev/null

12
err.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef WOJ_SANDBOX_ERR_H
#define WOJ_SANDBOX_ERR_H
// Error Code
#define ERR_SECCOMP_ENV 10
#define ERR_SECCOMP_INIT 11
#define ERR_SECCOMP_RESOLVE 12
#define ERR_SECCOMP_LOAD 13
#define ERR_UNSETENV 14
#define ERR_NO_RULE_FOUND 15
#endif // WOJ_SANDBOX_ERR_H

9
library.c Normal file
View File

@ -0,0 +1,9 @@
#include "rules/lang.h"
#include "sandbox.h"
#include "utils/log.h"
static __attribute__((constructor)) void inject(void) {
LOG_INFO("Setting up...");
register_lang_c();
setup_seccomp();
}

6
rules/lang.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef WOJ_SANDBOX_LANG_H
#define WOJ_SANDBOX_LANG_H
void register_lang_c(void);
#endif // WOJ_SANDBOX_LANG_H

22
rules/lang_c.c Normal file
View File

@ -0,0 +1,22 @@
#include "../sandbox.h"
#include "lang.h"
#include "rules.h"
#include <seccomp.h>
void setup_lang_c(scmp_filter_ctx ctx) {
int white[] = {SCMP_SYS(read), SCMP_SYS(write), SCMP_SYS(getpid),
SCMP_SYS(futex), SCMP_SYS(exit_group), SCMP_SYS(newfstatat)};
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);
}
}
struct rule lang_c_rule = {
.name = "lang_c",
.setup = setup_lang_c,
};
void register_lang_c(void) { register_rule(&lang_c_rule); }

35
rules/rules.c Normal file
View File

@ -0,0 +1,35 @@
#include "rules.h"
#include "../err.h"
#include "../utils/log.h"
#include <stdlib.h>
#include <string.h>
LIST_HEAD(seccomp_rules);
void register_rule(struct rule *rule) { list_add(&rule->list, &seccomp_rules); }
void setup_rule(char *name, scmp_filter_ctx ctx) {
struct list_head *current;
struct rule *rule;
list_for_each(current, &seccomp_rules) {
rule = list_entry(current, struct rule, list);
if (strcmp(rule->name, name) == 0) {
rule->setup(ctx);
return;
}
}
LOG_ERR("No rule found for %s", name);
dump_rules();
exit(ERR_NO_RULE_FOUND);
}
void dump_rules(void) {
struct list_head *current;
struct rule *rule;
LOG_INFO("Available Rules:");
list_for_each(current, &seccomp_rules) {
rule = list_entry(current, struct rule, list);
LOG_INFO("> %s", rule->name);
}
}

18
rules/rules.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef WOJ_SANDBOX_RULES_H
#define WOJ_SANDBOX_RULES_H
#include "../utils/list.h"
#include "seccomp.h"
struct rule {
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 dump_rules(void);
#endif // WOJ_SANDBOX_RULES_H

78
sandbox.c Normal file
View File

@ -0,0 +1,78 @@
#include "sandbox.h"
#include "err.h"
#include "rules/rules.h"
#include "utils/log.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
void add_syscall_nr(int syscall_nr, scmp_filter_ctx ctx, uint32_t action) {
if (seccomp_rule_add_exact(ctx, action, syscall_nr, 0)) {
LOG_ERR("Failed to add syscall %d", syscall_nr);
seccomp_release(ctx);
exit(ERR_SECCOMP_RESOLVE);
}
}
void add_syscall_name(const char *syscall_name, scmp_filter_ctx ctx,
uint32_t action) {
int syscall_nr = seccomp_syscall_resolve_name(syscall_name);
if (syscall_nr == __NR_SCMP_ERROR) {
LOG_ERR("Failed to resolve syscall %s", syscall_name);
seccomp_release(ctx);
exit(ERR_SECCOMP_RESOLVE);
}
add_syscall_nr(syscall_nr, ctx, action);
}
void setup_seccomp(void) {
LOG_INFO("Setting seccomp rules...");
char *template = getenv(SANDBOX_TEMPLATE);
char *action = getenv(SANDBOX_ACTION);
bool kill = true;
if (action && strncmp(action, "log", sizeof("log")) == 0) {
kill = false;
}
if (kill && !template) {
LOG_ERR("Environment variable %s required", SANDBOX_TEMPLATE);
dump_rules();
exit(ERR_SECCOMP_ENV);
}
scmp_filter_ctx ctx =
seccomp_init(kill ? SCMP_ACT_KILL_PROCESS : SCMP_ACT_LOG);
if (!ctx) {
LOG_ERR("Failed to init seccomp context");
exit(ERR_SECCOMP_INIT);
}
setup_rule(template, ctx);
#define UNSETENV(name) \
do { \
if (unsetenv(name)) { \
LOG_ERR("Failed to unset environment variable %s", name); \
seccomp_release(ctx); \
exit(ERR_UNSETENV); \
} \
} while (0)
UNSETENV(SANDBOX_TEMPLATE);
UNSETENV(SANDBOX_ACTION);
#undef UNSETENV
if (seccomp_load(ctx)) {
LOG_ERR("Failed to load seccomp context");
seccomp_release(ctx);
exit(ERR_SECCOMP_LOAD);
}
seccomp_release(ctx);
LOG_INFO("Preload Done");
}

16
sandbox.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef WOJ_SANDBOX_SANDBOX_H
#define WOJ_SANDBOX_SANDBOX_H
#include <seccomp.h>
#include <stdint.h>
// Configuration Environment Variables
#define SANDBOX_TEMPLATE "SANDBOX_TEMPLATE"
#define SANDBOX_ACTION "SANDBOX_ACTION"
void setup_seccomp(void);
void add_syscall_name(const char *syscall_name, scmp_filter_ctx ctx,
uint32_t action);
void add_syscall_nr(int syscall_nr, scmp_filter_ctx ctx, uint32_t action);
#endif // WOJ_SANDBOX_SANDBOX_H

9
test.c Normal file
View File

@ -0,0 +1,9 @@
#include "utils/log.h"
int main() {
char buf[128];
scanf("%s", buf);
printf("Hello %s\n", buf);
return 0;
}

21
utils/list.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef WOJ_SANDBOX_LIST_H
#define WOJ_SANDBOX_LIST_H
struct list_head {
struct list_head *next;
};
#define LIST_HEAD(name) struct list_head name = {&(name)};
static inline void list_add(struct list_head *new, struct list_head *head) {
new->next = head->next;
head->next = new;
}
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
#endif // WOJ_SANDBOX_LIST_H

24
utils/log.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef WOJ_SANDBOX_LOG_H
#define WOJ_SANDBOX_LOG_H
#include <stdio.h>
#include <unistd.h>
// Log
#define COLOR_RED "\x1B[1;31m"
#define COLOR_YELLOW "\x1B[1;33m"
#define COLOR_GREEN "\x1B[1;32m"
#define COLOR_STDOUT_RESET "\x1B[0m"
#define _LOG(color, level, fmt, ...) \
do { \
fprintf(stderr, \
color "[" level "](%d)(%s:%d): " fmt COLOR_STDOUT_RESET "\n", \
getpid(), __FILE__, __LINE__, ##__VA_ARGS__); \
} while (0)
#define LOG_INFO(fmt, ...) _LOG(COLOR_GREEN, "info", fmt, ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) _LOG(COLOR_YELLOW, "warn", fmt, ##__VA_ARGS__)
#define LOG_ERR(fmt, ...) _LOG(COLOR_RED, "err", fmt, ##__VA_ARGS__)
#endif // WOJ_SANDBOX_LOG_H

3
version_script.txt Normal file
View File

@ -0,0 +1,3 @@
{
local: seccomp_*;
};