desktop Linux sandboxing: a DIY proposal

this post presents some problems and an idea to solve them. I have successfully deployed this idea on my laptop for over a year. all my scripts are open source, but this isn't a tutorial and I don't advise copying what I've done unless you know what you're doing. some innovation required, batteries not included, no warranty express or implied, etc.

status quo

sandboxing is when an app or component is prevented from accessing or modifying the rest of the system, generally for security.

most desktop Linux distros provide little or no application sandboxing by default. this is slowly changing as the Flatpak and Snap ecosystems develop. these technologies allow packaging an app within a container to limit its capabilities, among other alleged benefits. at some point we may have entirely Flatpak or Snap-based distros that are usable for everyday tasks, but this is still a ways off.

Qubes OS and Spectrum (in development) are security-focused operating systems that take a more radical approach. they put each app in their own virtual machine. this is the most secure architecture, but it comes with significant complexity and overhead.

Android diverges significantly from desktop Linux, and iOS is an entirely different OS, but their security models are both conceptually similar to Flatpaks/Snaps.

these strategies work, but cause problems. many tasks from using unusual hardware to setting up dev tools become more difficult. there's often significant disk space and performance overhead. I believe these issues aren't minor kinks to work out, but are indistinctive of a...

fundamental problem

with the "lock it down" mindset. it attempts to impose restrictions on what everything interacting with a system can do, including its user. it's nontrivial to punch holes through the security layers because you're not supposed to do that. "solutions" to problems tend to be adding support for more special cases, rather than enabling the user to fix their own problems.

for nontechnical users this may generally be the best philosophy. for power users and developers it's not. we tend to gravitate towards distributions without these security models (a trend I expect to accelerate as distros like Ubuntu push their sandboxing solution of choice more aggressively).

but power users can also benefit from sandboxing, we just need the ability to work with it instead of against it.

proposal

what if an easier way to sandbox apps on Linux has been under our noses this whole time? instead of running each app in its own container or VM, lets divide attack vectors/targets and make a user for each.

I'll use the term UID (User ID) instead of "user" in the rest of this post, to make clear when I'm referring to Linux's concept of a "user" rather than a physical human user of the computer. each UID generally has its own files and its own home directory in /home to put them in.

example

in my case, the main UIDs are:

benefits

apps and usage domains are sandboxed, but managing these sandboxes requires nothing but understanding how users and permissions work. you, not your distro, decides what apps and OS components share a sandbox and how these are configured. it can be set up on a normal distro without any special app packaging. there's very little disk space required, and basically zero performance overhead.

it's also fully compatible with logging in as root, unlike most major alternatives.

costs

this system creates a number of inconveniences. setting it up in the first place is a chore, and you'll need to frequently move and chown files between UIDs. you can write scripts to make a lot of common tasks easier, but there will always be a little friction.

Technicalities

running graphical apps under different UIDs requires some setup. I launch sway as root and have a script to allow apps from other UIDs to connect to it. this script has to be re-run immediately before launching an XWayland app if none are already running.

just launching programs from different UIDs is tricky. environment variables need to be set, d-bus sessions need to be launched, etc. I use these scripts to do it, but they may only work if launched by root.

I have a work-in-progress project to bridge d-bus messages between different session busses. this may securely solve filesystem access and help with notifications eventually, but isn't ready yet.

alternatives

if you're familiar with containers or AppArmor you might be able to spin up an equivalent or superior system using them. I use UIDs because they work, and I already know how they work from my general Linux experience.

risks

UID isolation may be less secure than containers/AppArmor, and is much less secure than VMs like QubesOS uses. sophisticated attacks often include kernel or driver exploits that render it pointless. if a user doesn't know what they're doing, they may also open up vulnerabilities (for example some apps may expose sensitive data or attack surfaces over network ports that are available to all users). it's unadvisable to use this or any untested security model for many threat models, but if the alternative is no sandboxing it's likely safer.