From 9f759e738ebda4bc95c177c3d2206bb5481483bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Apr 2024 13:56:44 +0200 Subject: [PATCH 1/1] initial readme --- README.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ bubblebox.py | 6 +++- profiles.py | 10 ++---- 3 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e63c4e2 --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ +# BubbleBox: Simple Application Sandboxing + +## Introduction + +This is the documentation of [BubbleBox](https://www.ralfj.de/projects/bubblebox), a +tool to easily sandbox Linux applications. + +The primary use-case for BubbleBox is running applications that you do not trust enough +to give them full access to hour home directory, and in particular the secret keys stored there. +In this regard it is similar to [firejail] and [bubblejail], but less powerful and in exchange hopefully easier to configure. +BubbleBox is based on [bubblewrap] and [xdg-dbus-proxy] which do all of the heavy lifting. + +[firejail]: https://firejail.wordpress.com/ +[bubblejail]: https://github.com/igo95862/bubblejail +[bubblewrap]: https://github.com/containers/bubblewrap +[xdg-dbus-proxy]: https://github.com/flatpak/xdg-dbus-proxy + +## Usage + +The typical way to use BubbleBox is to create a new "jail" script in the BubbleBox source folder. +For instance, if you want a "gamejail" that you can use to run games, create a file `gamejail` +in a BubbleBox checkout with contents like this: + +```python +#!/bin/python3 +from bubblebox import * + +bubblebox( + profiles.DEFAULT, + profiles.DESKTOP, + dbus_proxy_flags("--own=com.steampowered.*"), + + home_access({ + ".steam": Access.Write, + }), +) +``` + +Then add a symlink to this file somewhere to your PATH, and now you can use `gamejail ` +to run arbitrary games inside the BubbleBox. + +### Configuration directives + +A BubbleBox sandbox is configured by passing a list of directives to the +`bubblebox` functions that declare things the sandbox has access to. Everything +else is blocked by default. + +These directives are basically lists of bubblewrap and xdg-dbus-proxy flags, +but BubbleBox provides some convenience functions +to allow higher-level configuration and to share common patterns. + +The `profiles.py` file contains some useful directives that are needed by most applications: +- `profiles.DEFAULT` adds the basic flags to isolate the sandbox from the environment + by unsharing all namespaces except for the network. + This profile gives access to `/usr`, `/sys`, and `/etc` and also creates a + stub file system inside the sandbox that is basically always required. It + assumes a merged-usr setup, e.g. it will add `/bin` as a symlink to + `/usr/bin`. It also gives read-only access to some files in the home directory + that are often needed to make a basic shell work: `.bashrc`, `.bash_aliases`, + `.profile` and the `bin` directory. +- `profiles.DESKTOP` is intended to make GUI applications work. It provides + access to DRI, X11, ALSA, Wayland, and PulseAudio. Furthermore, some GUI + configuration files (`.XCompose`, fontconfig, and default mime-type + associations) are made available to the sandbox. This also sets up the D-Bus + proxy and gives the application access to notifications, screen saver control, + status icons, and the flatpak portals (however, actually using these portals + is untested and would likely require further integration). Finally, it makes + clicking on links inside the sandbox work properly if your default browser is + Firefox. + +I recommend looking at the sources in `default.py` to learn how to configure your +own sandboxes. Here are the key directives to use: +- `host_access` gives the sandbox read-only or read-write access to some part + of the host file system. This is declared via nested Python dicts and supports + glob expressions. +- `home_access` works the same as `host_access` except all paths are relative + to the home directory. +- `bwrap_flags` allows passing flags directly to `bwrap`. This is rarely needed. +- `dbus_proxy_flags` allows passing flags directly to `xdg-dbus-proxy`. + This is the typical way to provide access to given D-Bus names. +- `shared_runtime_dir("name")` ensures that all instances of the sandbox with this + name have a shared XDG_RUNTIME_DIR. This is needed e.g. for VSCodium instances + to find each other. This must be declared *before* `profiles.DESKTOP`. + +## Source, License + +You can find the sources in the +[git repository](https://git.ralfj.de/bubblebox.git) (also available +[on GitHub](https://github.com/RalfJung/bubblebox)). They are provided under the +[GPLv2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) or (at your +option) any later version of the GPL. See the file `LICENSE-GPL2` for more +details. + +## Contact + +If you found a bug, or want to leave a comment, please +[send me a mail](mailto:post-AT-ralfj-DOT-de). I'm also happy about pull +requests :) diff --git a/bubblebox.py b/bubblebox.py index 628107e..cb7f514 100644 --- a/bubblebox.py +++ b/bubblebox.py @@ -61,7 +61,11 @@ def collect_flags(*flags): # Run the application in the bubblebox with the given flags. def bubblebox(*flags): - flags = collect_flags(*flags) + if len(sys.argv) <= 1: + print(f"USAGE: {sys.argv[0]} ") + sys.exit(1) + # Make sure `--die-with-parent` is always set. + flags = collect_flags(bwrap_flags("--die-with-parent"), *flags) bwrap = "/usr/bin/bwrap" extraflags = [] if flags.dbus_proxy_flags: diff --git a/profiles.py b/profiles.py index ff685f9..decab86 100644 --- a/profiles.py +++ b/profiles.py @@ -2,10 +2,8 @@ from bubblebox import * # Various default sandbox settings DEFAULT = collect_flags( - # general flags - bwrap_flags("--die-with-parent"), # namespace unsharing - bwrap_flags("--unshare-all", "--share-net", "--hostname", "bwrapped"), + bwrap_flags("--unshare-all", "--share-net", "--hostname", "bubblebox"), # basic directories bwrap_flags("--proc", "/proc", "--dev", "/dev", "--dir", "/tmp", "--dir", "/var", "--dir", "/run", "--symlink", "../run", "/var/run"), # an empty XDG_RUNTIME_DIR @@ -37,13 +35,11 @@ DESKTOP = collect_flags( }), # Access to some key user configuration home_access({ - (".config/fontconfig", ".XCompose"): Access.Read, + (".config/fontconfig", ".XCompose", ".local/share/applications"): Access.Read, }), # Access to basic d-bus services (that are hopefully safe to expose...) dbus_proxy_flags("--talk=org.kde.StatusNotifierWatcher.*", "--talk=org.freedesktop.Notifications.*", "--talk=org.freedesktop.ScreenSaver.*", "--talk=org.freedesktop.portal.*"), # Make it possible to open websites in Firefox - home_access({ - (".mozilla/firefox/profiles.ini", ".local/share/applications"): Access.Read, - }), + home_access({ ".mozilla/firefox/profiles.ini": Access.Read }), dbus_proxy_flags("--talk=org.mozilla.firefox.*"), ) -- 2.30.2