Skip to content

Commit bd2e8c8

Browse files
committed
Update Dockerfile to enhance sandboxing setup and runtime requirements
- Consolidates and clarifies environment variables for `nsjail`-based sandboxing. - Updates comments to reflect improved sandbox configuration, dependencies, and runtime needs, ensuring better security and isolation.
1 parent e7650e5 commit bd2e8c8

1 file changed

Lines changed: 34 additions & 35 deletions

File tree

Dockerfile

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,50 +25,49 @@ RUN python -m compileall -q .
2525
# Copy the evaluation function to the app directory
2626
COPY evaluation_function ./evaluation_function
2727

28-
# Command to start the evaluation function with
29-
ENV FUNCTION_COMMAND="python"
28+
# How lf_toolkit's runner launches the worker.
29+
ENV FUNCTION_COMMAND="python" \
30+
FUNCTION_ARGS="-m,evaluation_function.main"
3031

31-
# Args to start the evaluation function with
32-
ENV FUNCTION_ARGS="-m,evaluation_function.main"
33-
34-
# The transport to use for the RPC server.
35-
# stdio (not ipc): the sandboxed worker runs inside an nsjail mount namespace,
36-
# so the /tmp/eval.sock IPC rendezvous shimmy would otherwise use is fragile.
37-
# stdio sidesteps it; lf_toolkit sends its logs to stderr, so stdout stays
38-
# clean for the RPC framing.
32+
# RPC transport: stdio, not ipc. The sandboxed worker runs in an nsjail mount
33+
# namespace where the /tmp/eval.sock IPC rendezvous is fragile; stdio sidesteps
34+
# it. lf_toolkit logs to stderr, so stdout stays clean for the RPC framing.
3935
ENV FUNCTION_RPC_TRANSPORT="stdio"
4036

4137
# --- Sandboxed execution of untrusted student code (shimmy + nsjail) ---
42-
# Always on for this function. shimmy wraps the worker process -- and every
43-
# `python` subprocess it spawns for a submission -- in an nsjail sandbox:
44-
# unprivileged uid (nobody:nogroup), a minimal bind-mounted filesystem, and a
45-
# seccomp syscall filter.
38+
# Always on. shimmy wraps the worker -- and every `python` subprocess it spawns
39+
# per submission -- in nsjail: run as nobody, a read-only bind-mounted rootfs,
40+
# namespace isolation. Defence in depth on top of the AST gate in
41+
# evaluation_function/security.py, which rejects unsafe imports/builtins before
42+
# any code runs.
4643
#
47-
# DEPENDS ON THE BASE IMAGE shipping nsjail. shimmy provides the `--sandbox`
48-
# feature but not the nsjail binary; `evaluation-function-base/python` currently
49-
# copies only the shimmy binary, not `/usr/sbin/nsjail` or its shared libs
50-
# (libprotobuf, libnl-route-3, libcap2). Until that is fixed upstream, a build
51-
# of this image has shimmy fail to start (missing /usr/sbin/nsjail).
52-
# Tracking: lambda-feedback/evaluation-function-base -- add nsjail to the image.
44+
# Requires a base image that ships /usr/sbin/nsjail AND a shimmy build with the
45+
# sandbox fixes (--keep_env, PATH resolution of FUNCTION_COMMAND, --cwd fallback,
46+
# kafel seccomp, namespace toggles). With stock shimmy the worker fails to start.
5347
#
54-
# RUN-TIME: the container must run with --privileged (or --cap-add SYS_ADMIN)
55-
# so nsjail can create its namespaces (shimmy README, "Sandboxed Execution").
48+
# Run-time: the container must run --privileged (or --cap-add SYS_ADMIN) -- nsjail
49+
# needs CAP_SYS_ADMIN for unshare(CLONE_NEWNS). Running as uid 0, nsjail's "auto"
50+
# userns handling then drops CLONE_NEWUSER (a nested userns' unprivileged gid_map
51+
# write fails); --user still drops the worker to nobody. Network stays up so
52+
# matplotlib plots can be uploaded to S3 via boto3.
5653
#
57-
# Network stays enabled -- matplotlib plots are uploaded to S3 via boto3.
58-
# Untrusted network/filesystem use is already rejected before execution by the
59-
# AST gate in evaluation_function/security.py (check_code_safety).
54+
# SANDBOX_RO_BINDS / _RW_BINDS: shimmy splits these env vars on COMMA. Bind "/"
55+
# read-only (whole rootfs -- arch-independent, where an explicit list would need
56+
# /lib64 only on x86_64, and a missing bind source is fatal to nsjail), then
57+
# re-mount /tmp read-write. Not SANDBOX_TMPFS: nsjail's tmpfs defaults to 4 MiB,
58+
# too small for matplotlib's font cache + plot output.
6059
#
61-
# /tmp is a read-write bind of the container's own /tmp (not SANDBOX_TMPFS):
62-
# nsjail's tmpfs defaults to 4 MiB, too small for matplotlib's font cache and
63-
# plot output. No CPU/memory rlimits -- the RPC worker is long-lived and shared
64-
# across requests, so a cumulative RLIMIT_CPU/AS would eventually kill it;
65-
# per-run wall-clock limits live in evaluation.py (_TIMEOUT).
60+
# SANDBOX_DISABLE_CLONE_NEWPID: a nested PID namespace breaks worker thread
61+
# creation on some hosts ("pthread_create ... Invalid argument"); the mount and
62+
# user namespaces still isolate the filesystem and privileges.
6663
#
67-
# The bind list is linux/x86_64 + Debian-specific (matches the CI/prod build
68-
# platform). If the worker fails to start, drop SANDBOX_SECCOMP first.
64+
# No seccomp (nsjail has no built-in default policy; the fixed shimmy takes a
65+
# kafel policy via SANDBOX_SECCOMP_STRING / _POLICY_FILE if wanted) and no
66+
# rlimits (the RPC worker is long-lived and shared; per-run limits are the
67+
# _TIMEOUT in evaluation.py).
6968
ENV SANDBOX_ENABLED="true" \
70-
SANDBOX_SECCOMP="true" \
71-
SANDBOX_RO_BINDS="/usr:/lib:/lib64:/bin:/sbin:/etc:/app" \
72-
SANDBOX_RW_BINDS="/tmp"
69+
SANDBOX_RO_BINDS="/" \
70+
SANDBOX_RW_BINDS="/tmp" \
71+
SANDBOX_DISABLE_CLONE_NEWPID="true"
7372

7473
ENV LOG_LEVEL="debug"

0 commit comments

Comments
 (0)