/ia-sandbox

Infoarena sandbox for running user submitted code, in rust using namespaces and cgroups

Primary LanguageRustMIT LicenseMIT

ia-sandbox

Infoarena sandbox for running user submitted code, in rust using namespaces and cgroups.

pipeline status License: MIT

Currently a work in progress and experimental, use it at your own risk.

CHANGELOG

Please see the CHANGELOG for a release history.

Quick Links

What is ia-sandbox?

ia-sandbox is a command line utility allowing you to run untrusted code, such as the one submitted by users on websites like Codeforces, Topcoder or the website it was designed for Infoarena with certain limits for time (both user time and wall time), memory and number of processes while also collecting runtime information and exit status.

It uses modern linux tools and as such requires a relatively new kernel:

  • cgroups v1 - a linux kernel feature for limiting, accounting and isolating resource usage of a collection of proceeses
    • cpuacct - for precise user time usage and limits, requires a 64-bit computer for proper precision. Requires linux kernel ≥ 2.6.24
    • memory - for memory usage and limits. Requires linux kernel ≥ 2.6.24
    • pids - for limiting the number of processes, necessary for protection against fork bombs. Requires linux kernel ≥ 4.3
  • linux namespaces: - another linux kernel feature for isolating resources on the system
    • mount - for isolating mountpoints, the isolated application will only see itself and whatever the caller desides to mount next to it. Requires linux kernel ≥ 2.4.19
    • ipc - for ipc isolation. Requires linux kernel ≥ 2.6.19
    • uts - for uts isolation. Requires linux kernel ≥ 2.6.19
    • pid - for isolating processes, the sandboxed application will see itself as the only running process on the entire system. Requires linux kernel ≥ 2.6.24
    • network - for isolating network interfaces, the application can not make any changes to network, or see external changes. Requires linux kernel ≥ 2.6.24
    • user namespaces - for isolating the user id and group id. The isolated application will see itself as root inside the sandbox, and as having all capabilities but for the purpose of accessing resources it will actually be the user id of sandbox owner, greatly limiting whatever power or exploit the application can do. Requires linux kernel ≥ 3.5, but for proper security it is better for it to ≥ 3.9
    • cgroup - for isolating cgroups, to not allow the sandboxed application to change its own limits or usage. Requires linux kernel ≥ 4.6

Since all of these features need to be active, the minimum required version is 4.6.

Installation

The binary name is ia-sandbox.

The easiest way to install this is using cargo the package manager for Rust.

  • The minimum supported version of Rust for ia-sandbox is 1.27.0, altough ia-sandbox might work with older versions.
cargo install ia-sandbox

For actual isolation it is best to change the root of the sandbox (using -r or --new-root). This will unmount everything, except for /proc which is necessary, and is already only showing the isolated process.

If you would like to explore the inside of the sandbox an easy way would be

ia-sandbox --mount /lib:/lib:exec --mount /lib64:/lib64:exec --mount /usr:/usr:exec
           --mount /bin:/bin:exec --new-root PATH_TO_SOME_FOLDER --interactive --forward-env
           /bin/bash

How does it work?

  • It first spawns a supervisor process into a new pid and user namespaces (while also setting the right uid, gid and proc mount).
  • It sets the supervisor to be killed when it's parent dies.
  • It then spawns the process that will actually become sandboxed application.
    • It does this to protect itself from the case where the parent process dies, because it was forcefully killed and there is no one to kill the sandboxed application should it exceed its limits. By pid namespaces design, if the init process in the namespace dies, all processes get killed.
    • This new process is spawned in completely different namespaces except for cgroup.
  • It redirects standard input and output (while it still has acces to the file paths), if configured.
  • It sets the stack limit.
    • This has nothing to do with security, but rather with providing as much stack memory as required for the process to run.
  • It enters the cgroups necessary (cpuacct, memory, pids) optionally not clearing the usage from previous runs.
  • It enters a new cgroup namespace.
  • If a new root is requested (via --new-root or -r), it pivot roots to that path
  • It mounts the /proc path.
  • It sets the uid/gid map.
  • It moves to a different process group.
  • Lastly it execs the given application.

Contribuiting.

For any issues, especially security-related please open an issue at Issues.

I can not make any promises about pull requests, but I am open to them :-).

If you want to run the tests you will need to build the test-fixtures first, this can be easily done with

cargo build --features integration-test --bins

and then run the tests

cargo test

There are fixtures that require nightly only features (such as inline assembly). If running on nightly you can compile the fixtures with

cargo build --features integration-test,nightly --bins

and then run the test with

cargo test --features nightly