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), | 
