ISOLATE(1)
π NAME π
isolate β Isolate a process using Linux Containers. Bestie, this is the isolate(1) manual page, and itβs literally about locking a program in a sandbox so it canβt talk to the outside world and canβt eat all your resources. Think programming-contest energy: untrusted contestant code goes in, chaos stays contained. π
β¨ SYNOPSIS β¨
isolate options --init
isolate options --run -- program arguments
isolate options --cleanup
π¦ DESCRIPTION π¦
Run program inside a sandbox, so it cannot communicate with the outside world and its resource consumption is limited. This is useful, for example, in a programming contest where you need to run untrusted programs submitted by contestants in a controlled environment. No cap, thatβs the whole vibe. π§
The sandbox is used like this:
- Run
isolate --init, which initializes the sandbox, creates its working directory, and prints its name to standard output. If the sandbox already existed, it is reset. - Populate the directory with the executable file of the program and its input files.
- Call
isolate --runto run the program. A single line describing the status of the program is written to the standard error stream. - Fetch the output of the program from the directory.
- Run
isolate --cleanupto remove temporary files. Does nothing if the sandbox was already cleaned up.
Heads up, bestie: by default, the program is not allowed to start multiple processes or threads. If you need that, turn on the control group mode (see below). π
πΈ BASIC OPTIONS πΈ
-b,--box-id=idβ When you run multiple sandboxes in parallel, you have to assign unique IDs to them with this option. See the discussion on UIDs in theINSTALLATIONsection. The ID defaults to0.-M,--meta=fileβ Output meta-data on the execution of the program to a given file. See below for syntax of the meta-files.-i,--stdin=fileβ Redirect standard input fromfile. The file has to be accessible inside the sandbox (which means that the sandboxed program can manipulate it arbitrarily). If not specified, standard input is inherited from the parent process.-o,--stdout=fileβ Redirect standard output tofile. The file has to be accessible inside the sandbox (which means that the sandboxed program can manipulate it arbitrarily). If not specified, standard output is inherited from the parent process and the sandbox manager does not write anything to it.-r,--stderr=fileβ Redirect standard error output tofile. The file has to be accessible inside the sandbox (which means that the sandboxed program can manipulate it arbitrarily). If not specified, standard error output is inherited from the parent process. See also--stderr-to-stdout.--stderr-to-stdoutβ Redirect standard error output to standard output. This is performed after the standard output is redirected by--stdout. Mutually exclusive with--stderr.-c,--chdir=dirβ Change directory todirbefore executing the program. This path must be relative to the root of the sandbox.-v,--verboseβ Tell the sandbox manager to be verbose and report on what is going on. Using-vmultiple times produces even more jabber.-s,--silentβ Tell the sandbox manager to keep silence. No status messages are printed to stderr except for fatal errors of the sandbox itself. The combination of--verboseand--silenthas an undefined effect.--waitβ Multiple instances of Isolate cannot manage the same sandbox simultaneously. If you attempt to do that, the new instance refuses to run. With this option, the new instance waits for the other instance to finish.
π₯ LIMITS π₯
The following options can limit system resources consumed by the program. Resource-hungry behavior? Not today, bestie. π
-m,--mem=sizeβ Limit address space of the program tosizekilobytes. If more processes are allowed, this applies to each of them separately. If this limit is reached, further memory allocations fail (e.g.,mallocreturnsNULL).-t,--time=timeβ Limit run time of the program totimeseconds. Fractional numbers are allowed. Time in which the OS assigns the processor to other tasks is not counted. If this limit is exceeded, the program is killed (after--extra-time, if set).-w,--wall-time=timeβ Limit wall-clock time totimeseconds. Fractional values are allowed. This clock measures the time from the start of the program to its exit, so it does not stop when the program has lost the CPU or when it is waiting for an external event. We recommend to use--timeas the main limit, but set--wall-timeto a much higher value as a precaution against sleeping programs. If this limit is exceeded, the program is killed.-x,--extra-time=timeβ When the--timelimit is exceeded, do not kill the program immediately, but wait until--extra-timeseconds elapse since the start of the program. This allows one to report the real execution time, even if it exceeds the limit slightly. Fractional numbers are allowed.-k,--stack=sizeβ Limit process stack tosizekilobytes. By default, the whole address space is available for the stack, but it is subject to the--memlimit. If this limit is exceeded, the program receives theSIGSEGVsignal.-n,--open-files=maxβ Limit number of open files tomax. The default value is64. Setting this option to0will result in unlimited open files. If this limit is reached, system calls creating file descriptors fail with errorEMFILE.-f,--fsize=sizeβ Limit size of each file created (or modified) by the program tosizekilobytes. In most cases, it is better to restrict overall disk usage by a disk quota (see below). This option can help in cases when quotas are not enabled on the underlying filesystem. If this limit is reached, system calls expanding files fail with errorEFBIGand the program receives theSIGXFSZsignal.-q,--quota=blocks,inodesβ Set disk quota to a given number of blocks and inodes. This requires the filesystem to be mounted with support for quotas. Unlike other options, this one must be given toisolate --init. Please note that filesystems differ in what quotas they support and how these are controlled. The interface used by Isolate has been tested with the ext family of filesystems andtmpfs. If the quota is reached, system calls expanding files fail with errorEDQUOT.--core=sizeβ Limit size of core files created when a process crashes tosizekilobytes. Defaults to zero, meaning that no core files are produced inside the sandbox.-p,--processes[=max]β Permit the program to create up tomaxprocesses and/or threads. Please keep in mind that time and memory limit do not work with multiple processes unless you enable the control group mode. Ifmaxis not given, an arbitrary number of processes can be run. By default, only one process is permitted. If this limit is exceeded, system calls creating processes fail with errorEAGAIN.
π ENVIRONMENT RULES π
UNIX processes normally inherit all environment variables from their parent. The sandbox however passes only those variables which are explicitly requested by environment rules:
-E,--env=varβ Inherit the variablevarfrom the parent.-E,--env=var=valueβ Set the variablevartovalue. When the value is empty, the variable is removed from the environment.-e,--full-envβ Inherit all variables from the parent.
The rules are applied in the order in which they were given, except for --full-env, which is applied first.
The list of rules is automatically initialized with -ELIBC_FATAL_STDERR_=1.
π DIRECTORY RULES π
The sandboxed process gets its own filesystem namespace, which contains only subtrees requested by directory rules:
-d,--dir=in=out[:options]β Bind the directoryoutas seen by the caller to the pathininside the sandbox. Multiple options can be separated by colons. If there already was a directory rule forin, it is replaced.-d,--dir=dir[:options]β Bind the directory/dirtodirinside the sandbox. Multiple options can be separated by colons. If there already was a directory rule forin, it is replaced.-d,--dir=in=β Remove a directory rule for the pathininside the sandbox.
By default, all directories are bound read-only and restricted (no devices, no setuid binaries). This behavior can be modified using the options:
rwβ Allow read-write access.devβ Allow access to character and block devices.noexecβ Disallow execution of binaries.maybeβ Silently ignore the rule if the directory to be bound does not exist.fsβ Instead of binding a directory, mount a device-less filesystem calledout. Currently, only the following filesystems are supported:proc,sysfs,tmpfs,devpts.tmpβ Bind a freshly created temporary directory writeable for the sandbox user. Accepts noout, impliesrw.norecβ Do not bind recursively. Without this option, mount points in the outside directory tree are automatically propagated to the sandbox.
Unless --no-default-dirs is specified, the default set of directory rules binds /bin, /dev (with devices allowed), /lib, /lib64 (if it exists), and /usr. It also binds the working directory to /box (read-write), mounts the proc filesystem at /proc, and creates a temporary directory /tmp.
-D,--no-default-dirsβ Do not bind the default set of directories. Care has to be taken to specify the correct set of rules (using--dir) for the executed program to run correctly. In particular,/boxhas to be bound.
The rules are executed in the order in which they are given. Default rules come before all user rules. When a rule is replaced, it retains the original position in the order. This matters when one ruleβs in is a sub-directory of another ruleβs in. For example if you first bind to a and then to a/b, it will work as expected, but a sub-directory b must have existed in the directory bound to a (isolate never creates subdirectories in bound directories for security reasons). If the order is a/b before a, then the directory bound to a/b becomes invisible by the later binding on a. π¦
ποΈ CONTROL GROUPS ποΈ
Okay so real talk β Isolate can absolutely use the kernel's control groups (cgroups) to keep whole multi-process programs on a leash π«Ά. It's giving "herd all the cats at once." Just know this feature needs special system setup, and the deets live in the INSTALLATION section below, so don't skip it π .
--cgβ Turns on control group usage. Bestie, this one should be specified together with--init,--runand--cleanupβ like, all of them, okay? π--cg-mem=sizeβ Caps the total memory usage of the whole control group atsizekilobytes. Should be specified with--run. What happens when you hit this limit is honestly a vibe check on circumstances π: if it hits during memory allocation, the allocation can fail or the kernel can over-commit memory. If it hits while handling a page fault, the whole process gets killed by the OOM killer with theSIGSEGVsignal π.--print-cg-rootβ Prints the root of the control group hierarchy in/sys/and exits. This is used by theisolate-check-environmentscript β¨.
π SPECIAL OPTIONS π
These are the "for special occasions" options β the cute little accessories you only pull out sometimes π.
--share-netβ By default, isolate creates a new network namespace for its child process, and that namespace contains no network devices except for a per-namespace loopback π¦. Which means the program literally cannot talk to the outside world. If you want it to communicate, this switch keeps the child process in the parent's network namespace. Use responsibly π.--inherit-fdsβ By default, isolate closes all file descriptors passed from its parent except for descriptors0,1, and2β no unintentional descriptor leaks, periodt π. But sometimes passing extra descriptors into the sandbox is desirable, so this switch makes them survive.--tty-hackβ Tries to handle interactive programs communicating over a tty. The sandboxed program runs in a separate process group, which temporarily becomes the foreground process group of the terminal. When the program exits, the process group gets switched back to the caller β¨.
β οΈ Bestie. Listen. With--tty-hack, the program can do many nasty things including (but not limited to) changing terminal settings, changing the line discipline, and stuffing characters to the terminal's input queue using theTIOCSTIioctl ππ. Use with extreme caution. Like, extreme extreme. No cap.
--special-filesβ By default, Isolate removes all special files (anything that isn't a regular file or directory) created inside the sandbox. If you actually need them, this option disables that behavior β but you need to carefully check what you open, fr fr π.--as-uid=uid,--as-gid=gidβ Act on behalf of the specified user and group (only if Isolate was invoked by root π). This is used in scenarios where a root-controlled process manages creation of sandboxes for regular users, usually in conjunction with therestricted_initoption in the configuration file.--check-configβ Parses the configuration, checks that it's valid, and exits. A little vibe check for your config β¨.
π META-FILES π
The meta-file holds miscellaneous meta-information about the execution of the program within the sandbox π. It's a textual file made of lines in the format key:value. Here's every key that's defined:
cg-memβ When control groups are enabled, this is the total memory use by the whole control group (in kilobytes). Heads up: if you useisolate --runmultiple times in the same sandbox, the control group retains cached data from the previous runs, which also contributes tocg-memπ.cg-oom-killedβ Present when the program was killed by the out-of-memory killer (e.g., because it exceeded the memory limit of its control group). Reported only on Linux 4.13 and later π.csw-forcedβ Number of context switches forced by the kernel.csw-voluntaryβ Number of context switches caused by the process giving up the CPU voluntarily π .exitcodeβ The program has exited normally with this exit code.exitsigβ The program has exited after receiving this fatal signal.killedβ Present when the program was terminated by the sandbox (e.g., because it exceeded the time limit) β°.max-rssβ Maximum resident set size of the process (in kilobytes).messageβ Status message, not intended for machine processing. E.g.,"Time limit exceeded."statusβ Two-letter status code:REβ run-time error, i.e., exited with a non-zero exit codeSGβ program died on a signalTOβ timed out β°XXβ internal error of the sandbox π
timeβ Run time of the program in fractional seconds.time-wallβ Wall clock time of the program in fractional seconds.
π‘ Please note that not all keys have to be present. For example, nostatusnormessageis reported upon normal termination β she's chill like that πΈ.
π― RETURN VALUE π―
- When the program inside the sandbox finishes correctly, the sandbox returns
0β¨. - If it finishes incorrectly, it returns
1π. - All other return codes signal an internal error π.
π οΈ INSTALLATION π οΈ
Okay so Isolate depends on several advanced features of the Linux kernel β different kinds of namespaces and control groups, the whole menu π. These features are available in kernels of most Linux distributions now, but if you're building your own kernel, you have to be careful π.
Isolate is designed to run setuid to root. The sub-process inside the sandbox then switches to a non-privileged user ID (different for each --box-id). The range of UIDs available and several filesystem paths are set in a configuration file, by default located in /usr/local/etc/isolate π.
For control group mode:
- Linux supports two incompatible implementations of control groups: cgroup v1 and v2. This version of Isolate requires v2, which is the default on recent systems π .
- If you're using systemd, you need to start the
isolate.service(see service files in thesystemddirectory in Isolate's source tree). It establishesisolate.scopewhose cgroup subtree is delegated to Isolate by systemd. The service runs a simple daemonisolate-cg-keeper(8)to keep the scope alive π«Ά. - If you're not using systemd, make sure that Isolate's configuration file refers to the correct location where you have the cgroup filesystem mounted. Also make sure that whatever service manager you're using, it does not interfere with Isolate's use of control groups π.
- Running Isolate in containers is not recommended, since container managers usually do not delegate control groups properly. Besides, you do not want to share the machine with other workloads, which would influence measurement of execution time π. If you still want to use containers, you are on your own and you probably have to make them privileged π.
- Reporting memory usage requires Linux kernel 5.19 or newer.
- Since memory limits do not affect swapped-out data, we recommend turning off swap completely πΈ.
Isolate expects that the root directory / is a mount point. When running isolate inside a chroot, this may not be the case, and isolate may fail with "Cannot privatize mounts" π. A workaround is to convert the root directory of the chroot into a mount point using a bind mount, prior to entering the chroot and running isolate. For example:
mount --bind /path/to/chroot /path/to/chroot
It is recommended to have sys.fs.protected_hardlinks sysctl set to 1 (which is probably default on modern Linux systems). Otherwise, the user running the sandbox could trick isolate into changing the owner of unrelated files π± β not the vibe.
π¨ If you havesystemd-coredumpinstalled, please keep in mind that it records core files even for processes inside the sandbox. Since it configures the kernel to deliver core dumps using a pipe, it is not affected by the--corelimit π.
π¬ REPRODUCIBILITY π¬
The reproducibility of results can be improved by tuning some kernel parameters, listed below β¨. Some of these parameters can be checked using the program isolate-check-environment π.
- Disable address space randomization:
sysctl kernel.randomize_va_space=0. Address space randomization can affect timing, memory usage, and program behavior. This setting can be made persistent through/etc/sysctl.d/π . - Disable dynamic CPU frequency scaling. This is done by setting the cpufreq scaling governor in
/sys/device/system/cpu/cpufreq/*/scaling_governortoperformance. (On Intel CPUs, frequency scaling can be controlled by theintel_pstatedriver, but it still provides its ownperformancecontroller to the cpufreq subsystem.) π₯ - Consider disabling frequency boosting on CPUs that might support it (this includes most i3/i5/i7 Intel CPUs and the AMD Zen architecture). This is done either by writing
1to/sys/devices/system/cpu/intel_pstate/no_turbo(on Intel CPUs) or by writing0to/sys/devices/system/cpu/cpufreq/boost(other machines) π¦. - Run evaluations on a single CPU (core). The Linux scheduler has a tendency to randomly migrate tasks between CPUs, incurring cache migration costs π. You can use isolate's configuration file to pin the process to a specified CPU.
- If you have a CPU with a mix of different cores (e.g., P-cores and E-cores in certain Intel CPUs), pin the sandbox to a homogeneous subset of cores π.
- Disable automatic kernel support for transparent huge pages. Both
/sys/kernel/mm/transparent_hugepage/enabledand/sys/kernel/mm/transparent_hugepage/defragshould be set to"madvise"or"never", and/sys/kernel/mm/transparent_hugepage/khugepaged/defragto0πΈ. - Disable swapping. If you really need swap space and you're using cgroups, make sure that you have the
memswcontroller enabled, so that swap space is properly accounted for π.
See further suggestions in the IOI Technical Checklist β.
π SYSTEM CALL RESTRICTIONS π
Okay bestie, so here's the thing π β Isolate is not out here micromanaging every single thing your sandboxed process does. Nope! It's way chiller than that. Instead of limiting what operations can happen, it drops the process into a whole set of namespaces that restrict what objects can be accessed. So likeβ¦ yeah, your program can totally create network sockets, but there's literally nowhere for them to connect to π. Iconic behaviour, honestly.
BUT β and this is the important but π«Ά β there are a few special-case objects that the Linux kernel just doesn't namespace properly. And those lil guys can be exploited to smuggle information between two sandboxes running in parallel, or even between two instances of the same sandbox running one after another. Sneaky sneaky π.
To block those information leaks, Isolate forbids the use of a few system calls. This is all controlled by the syscall_flags setting in the configuration file, which holds a sum of the following flags:
1β Keyrings ποΈ: disables thekeyctlsystem call, which maintains keyrings that store cryptographic material. Keyrings can be used to establish system-wide or per-user persistent memory, through which data can be passed between successively run sandboxes.2β Virtual machine sockets π§: disables creation of sockets of theAF_VSOCKaddress family. These sockets are intended for communication between virtual machines and their hypervisors, but their scope is the whole system. So a vsock can be used to pass data between two sandboxes running simultaneously.4β i-node operations π₯: when an inode is accessible in multiple sandboxes (e.g., as a part of a read-only bind-mount of/usr, or even/proc/self/ns/uts), file locks on it are shared even across mount namespace boundaries. This can be used to leak information between simultaneously running sandboxes. This restriction forbidsfcntlwithF_SETLK,F_SETLKW,F_OFD_SETLK,F_OFD_SETLKW,F_SETLEASE, andF_NOTIFY, and alsoflock. Unlike the previously mentioned system calls, file locks could be possibly required by libraries used by legitimate programs. π¬
By default, all restrictions are in place. Every single one. No cap. π
π LICENSE π
Isolate was written by Martin Mares and Bernard Blackham β absolute icons, we stan π. It can be distributed and used under the terms of the GNU General Public License version 2 or any later version.
π¦ SEE ALSO π¦
isolate-check-environment(8)isolate-cg-keeper(8)
And that's the whole vibe check, bestie β you made it to the end! π This was ISOLATE(1), dated 01/01/1980 (yes, that date, don't ask π), and it's been a genuine pleasure. Go forth and sandbox responsibly β¨π
π¦ where this page comes from
- nixpkgs unstable: isolate 2.5
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms