diff options
-rw-r--r-- | .dockerignore | 2 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | docker/venv.Dockerfile | 2 | ||||
-rw-r--r-- | scripts/.profile | 18 | ||||
-rw-r--r-- | snekbox.cfg | 90 | ||||
-rw-r--r-- | snekbox/nsjail.py | 22 |
6 files changed, 99 insertions, 37 deletions
diff --git a/.dockerignore b/.dockerignore index afc786a..4f43e08 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,8 +2,8 @@ * # Make exceptions for what's needed -!docker/.profile !snekbox +!snekbox.cfg !tests !Pipfile !Pipfile.lock @@ -24,7 +24,7 @@ result <- | |<----------| | <----------+ The code is executed in a Python process that is launched through [NsJail](https://github.com/google/nsjail), which is responsible for sandboxing the Python process. NsJail is configured as follows: -* Root directory is mounted as read-only +* All mounts are read-only * Time limit of 2 seconds * Maximum of 1 PID * Maximum memory of 52428800 bytes diff --git a/docker/venv.Dockerfile b/docker/venv.Dockerfile index be15f08..b415430 100644 --- a/docker/venv.Dockerfile +++ b/docker/venv.Dockerfile @@ -7,7 +7,7 @@ ENV PIP_NO_CACHE_DIR=false \ PIPENV_NOSPIN=1 \ PIPENV_VENV_IN_PROJECT=1 -COPY Pipfile Pipfile.lock /snekbox/ +COPY Pipfile Pipfile.lock snekbox.cfg /snekbox/ WORKDIR /snekbox RUN if [ -n "${DEV}" ]; then pipenv sync --dev; else pipenv sync; fi diff --git a/scripts/.profile b/scripts/.profile index daaf1dd..47ee141 100644 --- a/scripts/.profile +++ b/scripts/.profile @@ -15,23 +15,7 @@ nsjpy() { echo "${MEM_MAX}" > /sys/fs/cgroup/memory/NSJAIL/memory.memsw.limit_in_bytes nsjail \ - -Mo \ - --rlimit_as 700 \ - --chroot / \ - -E LANG=en_US.UTF-8 \ - -E OMP_NUM_THREADS=1 \ - -E OPENBLAS_NUM_THREADS=1 \ - -E MKL_NUM_THREADS=1 \ - -E VECLIB_MAXIMUM_THREADS=1 \ - -E NUMEXPR_NUM_THREADS=1 \ - -R/usr -R/lib -R/lib64 \ - --user 65534 \ - --group 65534 \ - --time_limit 2 \ - --disable_proc \ - --iface_no_lo \ - --cgroup_pids_max=1 \ - --cgroup_mem_max="${MEM_MAX}" \ + --config "${NSJAIL_CFG:-/snekbox/snekbox.cfg}" \ $nsj_args -- \ /snekbox/.venv/bin/python3 -Iq -c "$@" } diff --git a/snekbox.cfg b/snekbox.cfg new file mode 100644 index 0000000..2f4a0e4 --- /dev/null +++ b/snekbox.cfg @@ -0,0 +1,90 @@ +name: "snekbox" +description: "Execute Python" + +mode: ONCE +hostname: "snekbox" +cwd: "/snekbox" + +time_limit: 2 + +keep_env: false +envar: "LANG=en_US.UTF-8" +envar: "OMP_NUM_THREADS=1" +envar: "OPENBLAS_NUM_THREADS=1" +envar: "MKL_NUM_THREADS=1" +envar: "VECLIB_MAXIMUM_THREADS=1" +envar: "NUMEXPR_NUM_THREADS=1" + +keep_caps: false + +rlimit_as: 700 + +clone_newnet: true +clone_newuser: true +clone_newns: true +clone_newpid: true +clone_newipc: true +clone_newuts: true +clone_newcgroup: true + +uidmap { + inside_id: "65534" + outside_id: "65534" +} + +gidmap { + inside_id: "65534" + outside_id: "65534" +} + +mount_proc: false + +mount { + src: "/etc/ld.so.cache" + dst: "/etc/ld.so.cache" + is_bind: true + rw: false +} + +mount { + src: "/lib" + dst: "/lib" + is_bind: true + rw: false +} + +mount { + src: "/lib64" + dst: "/lib64" + is_bind: true + rw: false +} + +mount { + src: "/snekbox" + dst: "/snekbox" + is_bind: true + rw: false +} + +mount { + src: "/usr/local/lib" + dst: "/usr/local/lib" + is_bind: true + rw: false +} + +cgroup_mem_max: 52428800 +cgroup_mem_mount: "/sys/fs/cgroup/memory" +cgroup_mem_parent: "NSJAIL" + +cgroup_pids_max: 1 +cgroup_pids_mount: "/sys/fs/cgroup/pids" +cgroup_pids_parent: "NSJAIL" + +iface_no_lo: true + +exec_bin { + path: "/snekbox/.venv/bin/python3" + arg: "-Iq" +} diff --git a/snekbox/nsjail.py b/snekbox/nsjail.py index f160aa8..83d3b8d 100644 --- a/snekbox/nsjail.py +++ b/snekbox/nsjail.py @@ -24,6 +24,7 @@ CGROUP_PIDS_PARENT = Path("/sys/fs/cgroup/pids/NSJAIL") CGROUP_MEMORY_PARENT = Path("/sys/fs/cgroup/memory/NSJAIL") NSJAIL_PATH = os.getenv("NSJAIL_PATH", "/usr/sbin/nsjail") +NSJAIL_CFG = os.getenv("NSJAIL_CFG", "./snekbox.cfg") MEM_MAX = 52428800 @@ -31,9 +32,9 @@ class NsJail: """ Core Snekbox functionality, providing safe execution of Python code. - NsJail configuration: + Default NsJail configuration (snekbox.cfg): - - Root directory is mounted as read-only + - All mounts are read-only - Time limit of 2 seconds - Maximum of 1 PID - Maximum memory of 52428800 bytes @@ -117,21 +118,8 @@ class NsJail: """Execute Python 3 code in an isolated environment and return the completed process.""" with NamedTemporaryFile() as nsj_log: args = ( - self.nsjail_binary, "-Mo", - "--rlimit_as", "700", - "--chroot", "/", - "-E", "LANG=en_US.UTF-8", - "-E", "OMP_NUM_THREADS=1", - "-E", "OPENBLAS_NUM_THREADS=1", - "-E", "MKL_NUM_THREADS=1", - "-E", "VECLIB_MAXIMUM_THREADS=1", - "-E", "NUMEXPR_NUM_THREADS=1", - "-R/usr", "-R/lib", "-R/lib64", - "--user", "65534", # nobody - "--group", "65534", # nobody/nogroup - "--time_limit", "2", - "--disable_proc", - "--iface_no_lo", + self.nsjail_binary, + "--config", NSJAIL_CFG, "--log", nsj_log.name, f"--cgroup_mem_max={MEM_MAX}", "--cgroup_mem_mount", str(CGROUP_MEMORY_PARENT.parent), |