This document describes using Cubicle using the bubblewrap
runner.
Bubblewrap is a light-weight
mechanism that runs on Linux only. Under Bubblewrap, the host's root partition
is shared read-only with the environments.
Cubicle relies on Bubblewrap and the Linux kernel for isolation, which aren't perfect. Users should review Bubblewrap's security and, of course, keep up with Linux kernel updates.
Environments with access to X11 probably have full access to your keystrokes. See https://wiki.archlinux.org/title/Bubblewrap#Sandboxing_X11 for more info.
Under Bubblewrap, Cubicle does not currently limit host network access, allowing containers to access services on the local host and local network. The UNIX domain abstract socket namespace is also shared between the host and the containers, since it is also tied to the network namespace. (This is actually how containers running under Bubblewrap currently access the X11 socket without any setup.)
Under Bubblewrap, Cubicle does not currently limit the resources used by its containers. This may leave containers vulnerable to attacks like unauthorized cryptocurrency mining.
Bublewrap's security depends on setting a restrictive seccomp policy, to limit the system calls available to the sandbox environment. Developing such a policy requires a careful audit of what is safe or unsafe to expose in the Linux kernel, which is a moving target.
Cubicle does not currently ship such a seccomp filter for Bubblewrap. Users are encouraged to borrow a seccomp filter from one of these projects:
-
Podman/Buildah/CRI-O's seccomp filter is here: https://github.com/containers/common/blob/main/pkg/seccomp/seccomp.json. This filter does allow running Electron apps with the Chromium sandbox.
-
Docker's seccomp filter is in moby/profiles/seccomp in both JSON format and Golang. This filter doesn’t allow running Electron apps like VS Code with the Chromium Sandbox turned on. See moby/moby#42441 for details.
-
Flatpak's seccomp filter is around here: common/flatpak-run.c in
setup_seccomp
. I haven't tried this one with Cubicle.
This short C
program
can dump a compiled BFP seccomp filter that is installed in a running process.
It uses
PTRACE_SECCOMP_GET_FILTER
to do this. Extracting a filter this way can be easier than trying to compile a
BPF filter from the above source code.
Cubicle is made up of a Rust program that runs on the host and a collection of shell scripts for package setup that run in containers.
You'll need Rust and Cargo. The version in Debian 12 may be too old.
Install the other dependencies:
bwrap
- Bubblewrap, Linux light-weight container tool. Note that while bwrap used to be a setuid binary, this is no longer needed on modern distributions.curl
- HTTP client.git
- version control system.jq
- command-line JSON processor.pv
- pipe viewer, displays progress bars.
On Debian 12, you can install the dependencies using apt
:
sudo apt install bubblewrap curl git jq pv
Assuming you'd like to install into ~/opt/cubicle
and already have ~/bin
in
your $PATH
:
echo 'runner = "bubblewrap"' > ~/.config/cubicle.toml
cd ~/opt/
git clone https://github.com/ongardie/cubicle/
cd cubicle
cargo build --release
ln -s $(pwd)/target/release/cub ~/bin/cub
Inside your cubicle.toml
, set runner
to "bubblewrap"
. You must also
create an object named bubblewrap
with the following keys:
- Type: path (string) or
"dangerously-disabled"
- Required
If set to "dangerously-disabled"
, the Bubblewrap runner will not apply a
seccomp filter. This will likely allow code inside the environment to easily
escape out to the host.
Otherwise, the runner will pass this file to bwrap
through its --seccomp
option. The file must be in compiled BPF program format, as generated by
seccomp_export_bpf
from libseccomp
.
If you haven't done so already, please read the security section on why you need a good seccomp filter. I've extracted a filter from a running Podman container on my amd64 machine and shared it here for convenience: https://ongardie.net/static/podman.bpf. I don't know whether this is secure (for any sandboxing purpose) or will remain so over time. Podman is released under the Apache-2.0 license.
First, exit out of any running Cubicle environments.
Assuming the same paths as in the installation instructions above:
rm -r ~/opt/cubicle/
rm ~/bin/cub
You may also want to remove these directories if you're done with all your Cubicle environments:
rm -r ${XDG_CACHE_HOME:-~/.cache}/cubicle/
rm -r ${XDG_DATA_HOME:-~/.local/share}/cubicle/
Each Cubicle environment consists of three logical filesystem layers:
Layer | Host Path (with default XDG base dirs) | Container Path | Lifetime |
---|---|---|---|
1. OS | / |
/ (read-only) |
long |
2. home | ~/.cache/cubicle/home/ENV |
~/ |
short |
3. work | ~/.local/share/cubicle/work/ENV |
~/w/ |
long |
-
The base operating system. This is currently shared with the host's
/
and read-only inside the container. -
A home directory. Inside the environment, this is at the same path as the host's
$HOME
, but it's not shared with the host. It lives in${XDG_CACHE_HOME:-~/.cache}/cubicle/home/
on the host. The home directory should be treated as replaceable at any time. Cubicle populates the home directory with files from packages when you create the environment (withcub new
) or reset it (withcub reset
). Currently, the home directory is populated with physical copies of package files, so the home directories can be large (a few gigabytes) and can take a few seconds to initialize. -
A work directory. For an environment named
eee
, this is at~/w/
inside the environment and${XDG_DATA_HOME:-~/.local/share}/cubicle/work/eee/
on the host. The work directory is where any important files should go. It persists acrosscub reset
.
There are a couple of special files in the work directory:
-
An executable placed at
~/w/update.sh
will be run automatically at the end ofcub reset
. This can be a useful hook to re-configure a new home directory. -
A file named
~/w/packages.txt
keeps track of which packages the environment was initialized or last reset with. It is used next time the environment is reset (unless the user overrides that on the command line).