Sandboxing portal

Opening a thread here to follow up on discussions at GUADEC with @matthiasc @alexl @jamesh @kenvandine @chergert @hadess Olivier Tilloy, myself and whoever else I was able to corner. For context, at present Flatpak totally blocks the syscalls necessary to set up your own filesystem/user namespace (see https://github.com/flatpak/flatpak/blob/master/common/flatpak-run.c#L2476-L2480) and necessarily blocks setuid binaries.

Chromium’s sandboxing relies on either being able to directly open a user namespace (ie the system has unprivileged user namespaces enabled) or relying on its setuid helper to do so. In the case both of these fail, Chromium errors out, which has precluded running Chromium inside a Flatpak for the time being, without patching out the sandbox code, which seems deeply irresponsible, or passing --disable-sandbox which earns you a very scary warning.

It seems recently that Electron has either updated to a newer Chromium or changed their build defaults, which means that various third-party Electron apps are starting to fail to run inside Flatpak too. This is sad.

Although I have not read the code, speaking with @jamesh and @kenvandine it seems that snapd has a special consideration for browsers, based off a whitelist or a rarely-given privilege, that trusts them to create user namespaces. It wasn’t clear how Electron apps avoid the same fate, given they don’t possess this privilege, but (conjecture) Electron builder itself has a mode where it outputs snaps, so perhaps this also disables the sandboxing.

Similarly, we also have the oddly-inverted situation that certain operations (eg thumbnailing, see https://gitlab.gnome.org/GNOME/gnome-desktop/blob/master/libgnome-desktop/gnome-desktop-thumbnail-script.c#L766-770) which should/could be very heavily sandboxed are run with no additional confinement when they are executed in a Flatpak (and presumably snap?) context.

@refi64 has a proof-of-concept patch to Chromium which shells out to flatpak-spawn at the time it would otherwise call the setuid sandbox helper, but it strikes me that this Flatpak-specific approach is the wrong way to do it and isn’t likely to be upstream-able, so it also wouldn’t make it very far through the Electron ecosystem either.

I think if we work on a shared sandboxing portal API which both Flatpak and snapd can implement, we can remove any special-casing for browsers and make a consistent/united case towards toolkit and app developers about how stricter sandboxing should be accessed for confined apps, improving security and our chances of getting one “golden” (ie works everywhere) patch upstream.

My plan would be something like:

  • Discuss the Flatpak sandboxing API and how it could be made generic to work with snapd as well (see https://github.com/flatpak/flatpak/blob/master/data/org.freedesktop.portal.Flatpak.xml)
  • Implement the agreed API all round
  • Re-implement our Chromium patch in terms of calling the portal API over D-Bus and submit upstream
  • Submit to Electron in parallel if that lets us stop breakage sooner
  • Push towards using that API in Firefox as well
  • Drop browser hacks all round
  • Add a “sandbox spawn” API to Glib that could use this or fallback to eg bwrap/seccomp when run on a Linux system (other platforms may be available)
  • Celebrate improved desktop security
5 Likes

Also add WebKitGTK to that list :stuck_out_tongue:

So I wanted to use flatpak-spawn for our purposes there and there were a few limitations that I hope a replacement will cover:

  • Ability to specify directories to mount in the sandbox. Currently it just gives you a shared dir which isn’t ideal.
  • More granular disable toggles. Currently it just has --sandbox and --no-network. I would like --no-x11, --no-dbus (except I do want xdg-desktop-portal access so maybe --filtered-dbus or something, I realize that is probably WebKitGTK specific since Chromium doesn’t care about the portals), etc.

Add a “sandbox spawn” API to Glib

My only concern with this is that its impossible to automatically run a sandbox using host data that covers all usage so you’ll have to make applications set their own mounts at which point is a very thin wrapper that doesn’t hide much details. Maybe that is OK but I don’t know if it has a ton of value.

:tada:

I suspect that we won’t be able to (like flatpak-spawn does) start with the assumption that “everything shared will be the same as flatpak does, apart from…” because we need something which can be implemented the same in snapd, and it has a different approach to structuring its filesystem etc.

I am a little puzzled though (and my apologies for not making it to your talk; it’s on my “wait for the video” list) - which part of WebKitGTK wants access to portals and filesystems? Does it not have a UI / renderer split similar to Chromium where the renderer is very unprivileged and so quite a reasonable sandbox boundary?

In a Glib API that might, eg, want to fall back to not sandboxing but still executing, where the OS/environment limits the available technique, an “assume very little, add things incrementally” approach of finding a set of sandbox controls which are in common/useful set between Flatpak and snap might work OK.

Some random side notes that might be interesting:

  • We’d need to be very careful to make sure the sandboxes are consistent with each other. For instance, a fallback sandbox’s PID namespace would probably be a child of the caller’s, but with flatpak-spawn they’re fully isolated and in parallel.
  • Apparently, you can still use seccomp/bpf sandboxes in Flatpak? I was kinda surprised that it worked but surely enough it did. Nowadays, that alone is a pretty powerful sandboxing technique; heck, the only thing missing on top of it in Chrome that requires us to call out to flatpak-spawn is lack of unshare.
  • More granular controls like @pgriffis said would be nice IMO (right now the GPU process needs to run unsandboxed because otherwise it will fail to access the Xorg display), but it might be a hard sell to upstream Flatpak.

It is split to a degree but the WebKitWebProcess still has GTK usage.

As for file system access applications can embed arbitrary plugins in the process (WebKitWebExtensions) and we allow giving them limited filesystem access. WebKit has a few internal directories we grant access to also that are less arbitrary but still don’t fit into the limitations of flatpak-spawn.

I think in terms of our patch for Chromium/Electron we just need to make sure that the code interacting with the sandboxed PIDs is able to work with a different PID namespace. Ie make this an assumption of the API, that a new PID namespace might be unavoidable.

Yes, they can be composed safely because essentially you can’t later permit something that was earlier (by a more priveleged process that launched you) denied. You can only add them and deny more stuff.

Well, @alexl is here (or can be) and I am hoping to get @jamesh and Snap folks to weigh in soon. But, I think “this needs display access” or - perhaps more nuanced, considering we have Wayland-or-X11-fallback behaviour in Flatpak - “inherit my display access” is not an unreasonable ask for the API.

Hi. Sorry for dropping the ball on this. I have discussed the basic requirements of this API with some of the core snapd developers (Zygmunt Krynicki in particular). At present it is not trivial for us to support the API, since the mount namespaces, AppArmor profiles and seccomp filters for snaps are generated at package install/upgrade time.

I’m at a sprint with the snapd folk this week, and we have a few meetings scheduled to discuss it. I will keep you guys updated on what happens.