diff --git a/Dockerfile b/Dockerfile index 3fed387f..14e23f03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.4 -FROM buildpack-deps:buster as builder-nsjail +FROM buildpack-deps:bookworm as builder-nsjail WORKDIR /nsjail @@ -17,7 +17,7 @@ RUN git clone -b master --single-branch https://github.com/google/nsjail.git . \ RUN make # ------------------------------------------------------------------------------ -FROM buildpack-deps:buster as builder-py-base +FROM buildpack-deps:bookworm as builder-py-base ENV PYENV_ROOT=/pyenv \ PYTHON_CONFIGURE_OPTS='--disable-test-modules --enable-optimizations \ @@ -42,7 +42,7 @@ RUN git clone -b v2.3.26 --depth 1 https://github.com/pyenv/pyenv.git $PYENV_ROO && /build_python.sh 3.12.0rc2 # ------------------------------------------------------------------------------ -FROM python:3.11-slim-buster as base +FROM python:3.11-slim-bookworm as base ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \ PIP_NO_CACHE_DIR=false @@ -52,7 +52,7 @@ RUN apt-get -y update \ gcc \ git \ libnl-route-3-200 \ - libprotobuf17 \ + libprotobuf32 \ && rm -rf /var/lib/apt/lists/* COPY --link --from=builder-nsjail /nsjail/nsjail /usr/sbin/ diff --git a/docker-compose.yml b/docker-compose.yml index 0613abc6..b28d61bc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ services: ports: - "8060:8060" init: true - ipc: none + ipc: private tty: true environment: SNEKBOX_DEBUG: 1 diff --git a/snekbox/nsjail.py b/snekbox/nsjail.py index 1de7b1e7..9bf20bf9 100644 --- a/snekbox/nsjail.py +++ b/snekbox/nsjail.py @@ -3,6 +3,7 @@ import subprocess import sys from collections.abc import Generator +from contextlib import nullcontext from pathlib import Path from tempfile import NamedTemporaryFile from typing import Iterable, TypeVar @@ -56,7 +57,7 @@ def __init__( memfs_home: str = "home", memfs_output: str = "home", files_limit: int | None = 100, - files_timeout: int | None = 5, + files_timeout: float | None = 5, files_pattern: str = "**/[!_]*", ): """ @@ -267,7 +268,7 @@ def python3( # Parse attachments with time limit try: - with time_limit(self.files_timeout): + with time_limit(self.files_timeout) if self.files_timeout else nullcontext(): attachments = fs.files_list( limit=self.files_limit, pattern=self.files_pattern, diff --git a/snekbox/utils/timed.py b/snekbox/utils/timed.py index 11d126c1..59a4e7f4 100644 --- a/snekbox/utils/timed.py +++ b/snekbox/utils/timed.py @@ -11,7 +11,7 @@ @contextmanager -def time_limit(timeout: int | None = None) -> Generator[None, None, None]: +def time_limit(timeout: float) -> Generator[None, None, None]: """ Decorator to call a function with a time limit. @@ -25,10 +25,12 @@ def time_limit(timeout: int | None = None) -> Generator[None, None, None]: def signal_handler(_signum, _frame): raise TimeoutError(f"time_limit call timed out after {timeout} seconds.") + # ITIMER_PROF would be more appropriate, but SIGPROF doesn't seem to interrupt sleeps. signal.signal(signal.SIGALRM, signal_handler) - signal.alarm(timeout) + signal.setitimer(signal.ITIMER_REAL, timeout) try: yield finally: - signal.alarm(0) + # Clear the timer if the function finishes early. + signal.setitimer(signal.ITIMER_REAL, 0) diff --git a/tests/test_nsjail.py b/tests/test_nsjail.py index fe55290f..5d927c26 100644 --- a/tests/test_nsjail.py +++ b/tests/test_nsjail.py @@ -233,7 +233,7 @@ def test_file_parsing_timeout(self): size = 32 * 1024 * 1024 with open("file", "w") as f: - for _ in range((size // 1024) - 5): + for _ in range(size // 1024): f.write(data) for i in range(100): @@ -242,7 +242,7 @@ def test_file_parsing_timeout(self): ).strip() # A value higher than the actual memory needed is used to avoid the limit # on total file size being reached before the timeout when reading. - nsjail = NsJail(memfs_instance_size=512 * Size.MiB, files_timeout=1) + nsjail = NsJail(memfs_instance_size=128 * Size.MiB, files_timeout=0.1) result = nsjail.python3(["-c", code]) self.assertEqual(result.returncode, None) self.assertEqual(