blob: 741370906c82ba84baefb82f3958e2dcae1b4b85 [file] [log] [blame] [view]
---
layout: documentation
title: Sandboxing
---
# Sandboxing
This article covers sandboxing in Bazel, installing `sandboxfs`, and debugging
your sandboxing environment.
_Sandboxing_ is a permission restricting strategy that isolates processes from
each other or from resources in a system. For Bazel, this means restricting file
system access.
Bazel's file system sandbox runs processes in a working directory that only
contains known inputs, such that compilers and other tools don't see source
files they should not access, unless they know the absolute paths to them.
Sandboxing doesn't hide the host environment in any way. Processes can freely
access all files on the file system. However, on platforms that support user
namespaces, processes can't modify any files outside their working directory.
This ensures that the build graph doesn't have hidden dependencies that could
affect the reproducibility of the build.
More specifically, Bazel constructs an `execroot/` directory for each action,
which acts as the action's work directory at execution time. `execroot/`
contains all input files to the action and serves as the container for any
generated outputs. Bazel then uses an operating-system-provided
technique, containers on Linux and `sandbox-exec` on macOS, to constrain the
action within `execroot/`.
## Reasons for sandboxing
- Without action sandboxing, Bazel will not know if a tool uses undeclared input
files (files that are not explicitly listed in the dependencies of an action).
When one of the undeclared input files changes, Bazel still believes that the
build is up-to-date and wont rebuild the action-resulting in an incorrect
incremental build.
- Incorrect reuse of cache entries creates problems during remote caching. A bad
cache entry in a shared cache affects every developer on the project, and
wiping the entire remote cache is not a feasible solution.
- Sandboxing is closely related to remote execution. If a build works well with
sandboxing, it will likely work well with remote execution. Uploading all
necessary files (including local tools) can significantly reduce maintenance
costs for compile clusters compared to having to install the tools on every
machine in the cluster every time you want to try out a new compiler or make
a change to an existing tool.
## sandboxfs
`sandboxfs` is a FUSE file system that exposes an arbitrary view of the
underlying file system without time penalties. Bazel uses `sandboxfs` to
generate `execroot/` instantaneously for each action, avoiding the cost
of issuing thousands of system calls. Note that further I/O within `execroot/`
may be slower due to FUSE overhead.
### Install sandboxfs
Use the following steps to install `sandboxfs` and perform a Bazel build with
it:
**Download**
[Download and install](https://github.com/bazelbuild/sandboxfs/blob/master/INSTALL.md)
`sandboxfs` so that the `sandboxfs` binary ends up in your `PATH`.
**Run `sandboxfs`**
1. (macOS-only) [Install OSXFUSE](https://osxfuse.github.io/).
2. (macOS-only) Run
```shell
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
```
You will need to do this after installation and after every reboot to ensure
core macOS system services work through sandboxfs.
3. Run a Bazel build with `--experimental_use_sandboxfs`.
```shell
$bazel build <target> --experimental_use_sandboxfs
```
**Troubleshooting**
If you see `local` instead of `darwin-sandbox` or `linux-sandbox` as an
annotation for the actions that are executed, this may mean that sandboxing is
disabled. Pass `--genrule_strategy=sandboxed --spawn_strategy=sandboxed` to
enable it.
## Debugging
Follow the strategies below to debug issues with sandboxing.
### Deactivated namespaces
On some platforms, such as [Google Kubernetes
Engine](https://cloud.google.com/kubernetes-engine/) cluster nodes or Debian,
user namespaces are deactivated by default due to security
concerns. If the `/proc/sys/kernel/unprivileged_userns_clone` file exists and
contains a 0, you can activate user namespaces by running:
```shell
sudo sysctl kernel.unprivileged_userns_clone=1
```
### Rule execution failures
The sandbox may fail to execute rules because of the system setup.
If you see a message like `namespace-sandbox.c:633: execvp(argv[0], argv): No
such file or directory`, try to deactivate the sandbox with
`--strategy=Genrule=local` for genrules, and `--spawn_strategy=local`
for other rules.
### Detailed debugging for build failures
If your build failed, use `--verbose_failures` and `--sandbox_debug` to make
Bazel show the exact command it ran when your build failed, including the part
that sets up the sandbox.
Example error message:
```
ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:
Sandboxed execution failed, which may be legitimate (e.g. a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned
namespace-sandbox failed: error executing command
(cd /some/path && \
exec env - \
LANG=en_US \
PATH=/some/path/bin:/bin:/usr/bin \
PYTHONPATH=/usr/local/some/path \
/some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
/some/path/to/your/some-compiler --some-params some-target)
```
You can now inspect the generated sandbox directory and see which files Bazel
created and run the command again to see how it behaves.
Note that Bazel does not delete the sandbox directory when you use
`--sandbox_debug`. Unless you are actively debugging, you should disable
`--sandbox-debug` because it fills up your disk over time.