Once Upon a Time
Trying my best to make the title sound like one of those tales you’d tell your kids when putting them to bed. Those who know me well know that I’m doing a PhD, allegedly on activity confinement, and those who know me even better have witnessed me rant every day for three months about how it’s impossible (because ethnomethodology, phenomenology, embodied interaction, situated action, etc.). So I decided to convert to another religion. I’m now a guru of the church of sandboxing. Hopefully neither cognitive dissonance nor my PhD advisor will catch up on me before my defense (ah ah).
There’s a plethora of tools for app sandboxing out there, on every major OS, and even more people arguing over which is the most secure – nothing I can convince myself to care about. Because all these sandboxing tools assume, in one way or another, that the thing they’re trying to contain is designed to be put in their box. This worldview fits server apps incredibly well: they’re designed to process one type of data, continuously, and to produce a specific output at a specific place for a specific input. Security researchers also got very wealthy exploiting the silicia nugget of mobile phones: phone apps have such little utility and phones such restricted interaction techniques that you never do any substantial multitasking or process any complex kind of data, you have fewer options for app customization than on the desktop, and as a result most mobile apps process their own data rather than your documents.
All of that is wonderful, but when you’re interested in general purpose multitasking-capable complex operating systems, it doesn’t work. Users tend to keep a lot of data around on their desktop OS, they have apps that process multiple formats and they reuse a file across multiple apps. They constantly multitask with apps that don’t care the least about proper password storage, etc. You’re even routinely asked to process data from multiple untrusted sources on a routine basis to earn your salary! And yet apps easily get compromised (especially Linux apps), and stay compromised afterwards. They can destroy all of your data, abuse your resources and steal your root password with surprisingly little effort!
It should be obvious to all that access control policies and “fine-grained” sandboxing are no cure to the disease of the desktop. If not, read field studies on information workers’ daily life, contemplate the sheer complexity of their work days and then come back and ask them if they want to sit and write policies because they get any work done. Our challenge is to have the policy be produced on-the-fly, and with no user cost (time, money or cognitive load) s’il-vous-plaît. Sandbox Utils is my collection of black magic tricks that do just that.
App Sandboxing: Friends vs Foes
Remember, I said sandboxing tools were designed to sandbox cooperative apps, that accept dropping their privileges, tell you what they need and don’t need, and naturally process data in well-isolated chuncks. They can be put into VMs, SELinux domains, NaCl, LXCs, etc. to serve them. What we want on the desktop is not to satisfy friend apps who’ll work with us, but enable the writing and use of foe apps who’ll cheat on us. So rather than the “start-almighty-and-keep-yourself-under-control” paradigm, we’ll adopt “start-from-the-bottom-and-prove-your-worth”. Apps start entirely sandboxed, and the user decides on-the-fly what apps gain access too – an access which (unless stated otherwise) lasts only until the user moves on to something else. This concept is called security by designation: the user designates what a process should be allowed to access.
Given that zero-user-effort is critical for the technology to be deployed and adopted, I want the designation to occur naturally in the ways people use their computers. There has been at least one implementation called User-Driven Access Control (albeit in the wonderful world of Samsung Nuggets), that allows providing access to devices like a phone’s camera when a user clicks a button. The concepts behind are no wonder to a security engineer: capabilities and a trusted path. No black magic. And yet no major OSes until very recently implemented anything similar!
What I want to do with Sandbox Utils is serve the foes, and provide them all the features they need to write awesome apps for my users! I want them to be able to access files, with whatever model they enjoy best (atomic accesses, access to recent files, scanning for all your videos, retrieving groups of inter-related files in one interaction, etc.). Because I want my users to know what they’re up to, access will be granted via a user interaction in a trusted and privileged widget. Like what has been done in UDAC, I’ll provide access to all the capabilities we’ve been speaking about here and there through special buttons and dialogs. That’s for the theory.
In practice, GUI apps already exist and make use of permissive APIs. Nobody wants to rewrite their apps just for fun, let alone to use a more restrictive API and lose key features. Feature parity is hardly reachable (as we shall see on one example) so yes, APIs will break and yes, we’ll have to rewrite apps. I’d like to use the occasion to reflect upon things that programmers commonly try to achieve, to reduce their workload in exchange for a more tightly-controlled workflow and the ability for me to do security by designation. This is also an occasion to improve user experience by forcing more key elements of their interactions with apps to become more consistent. Users learn automatisms so we might as well make use of that from times to times rather than resent it when trying to catch their attention and get them to make security decisions (oh, the irony).
I won’t even speak about how one goes about sandboxing an app, launching it and providing it with a privileged helper that exposes the API I’ll discuss. This is engineering details. Let’s have a look at this example used by Ka-Ping Yee and many others, that seems so trivial at first: the almighty and honorable file chooser dialog.
Sandbox File Chooser Dialog
The SandboxFileChooserDialog class is the Sandbox Utils equivalent of GTK+’s GtkFileChooserDialog. It allows developers to display a dialog in which users will either select files or folders to open or a location for them to save a file.
In GTK+ this API is only a convenient method for apps to use a standardized pre-coded dialog, and since apps have access to the file system, they can do a lot of neat things such as previewing the currently selected file, modify the filename typed by the user to include a forgotten extension, etc. Once file system access has been taken, two consequences arise:
- Users must also be protected into apps that attempt to fool them, for instance by modifying the dialog just before they press
- Apps lose the ability to read files or covertly modify the user-chosen filename, and the API must be expanded for all valid use cases that made use of such an ability
The former issue is solved by introducing statefulness to the dialog: developers must finish configuring their dialog before they run it. Once it runs, it cannot be touched (only cancelled, brought to the foreground or destroyed). Then, and only if the run was successful, developers can read whatever files the user selected. The workflow induced by the states actually maps the common way of using a GtkFileChooserDialog. Major differences with the standard API for basic usages are that all functions take a GError parameter and that the
sfcd_run() method no-longer returns a response directly. Instead, one must connect to the
response signal. Both changes are side-effects of needing to carry method calls across D-Bus to a remote server: IPC is more failure-prone.
A developer might attempt to cheat by selecting a file they want to steal whilst in the configuration state, running the dialog and waiting for a bewildered user to click
Cancel. To prevent that, only certain labels can be associated with a positive outcome granting access to files. This is somewhat a regression back to the good old world of stock labels, but I’m afraid it’s necessary to prevent social engineering attacks. One can also argue it reinforces consistency across apps to limit the possible labels.
API extension is a bit harder to tackle. At the moment my API does not support certain things. I provide support for embedding (sandboxed) extra widgets into a (privileged) dialog using the XEmbed spec (knowing that this is temporary and will be replaced with a solution that will be security-assessed later on in Wayland/Weston). Support for file filters will be reintroduced (except for custom file filters which pose the problem of leaking the current folder’s content). The GFile functions will not be reintroduced without a good reason (because they’re mostly featuritis from my layman view, and they’re hard to carry across D-Bus).
For preview widgets, I’m tempted to say app devs should write thumbnailers rather than previewers. Thumbnailers can be used both by the file chooser dialog and by the file manager, and allow rendering files inside sandboxes! This means no risk of information leakage, and no more dangers inherent to bugs in rendering libraries. In any case, app devs would need to provide a separate piece of code or method to do file previewing from the CLI for us to run a sandboxed previewer live. I’d rather rely on something like Tumbler and a bit of extra sandboxing than ask app devs to provide sandboxable libraries that end up being used just for previewing.
Finally, the gtk_file_chooser_get_current_name() method suggests developers may need to append an extension to the user-provided filename based on the state of a file format selection extra widget. In fact, it seems to me that file format selection is the most common usage for an extra widget. I’m also a bit annoyed at how extra widgets are placed in GtkFileChooserDialog (very frankly, the left alignment of the extra widget and right alignment of the file filter make for a big waste of screen real estate).
Since it is known to developers what formats they want to support and how they’d change the file extension depending on this format, I’m tempted to have a specialised widget in SandboxFileChooserDialog that maps a currently selected format to an extension, without the developer ever seeing the filename and with the user getting immediate feedback. Many interactions can be imagined to allow users to either copy the corrected filename in their buffer and further edit it, or to modify the extension on-the-fly with a GtkPopover. Actually, this widget could serve extra purposes such as enforcing filenames that are compatible with a specific file system (e.g., automatically replacing
- for FAT), or timestamping saved files. There are only so many things that developers need on a regular basis to improve their users’ experience, but those things will no longer be possible for sandboxed applications unless catered for.
Internally, Two Dialogs for one API
I won’t describe the whole inner bolts, but it’s worth nothing that the class used by the server to map to GTK+ and the one used by the client to perform D-Bus calls have the same parent class, and that it is this parent class that is exposed to developers and documented. Consequently, users can choose whether to use sandbox-capable or local dialogs simply by typing
--no-sandbox when launching their app. With D-Bus activatable apps, a desktop environment could determine in situation whether it should launch a sandboxed app or not, and adjust the launching environment and parameters accordingly. App developers only need to use a single lib, and not to worry about compile-time parameters. It’s not quite the same as not being aware of the sandbox, however: app developers just have to use the sandbox-compatible API all the time – which is why it needs to rock and provide even higher value than GTK+3 !
I’d like to thank Martin (mupuf) for our usual chatting and his sanity checks on the Git tree, but also all the GTK+ and GNOME people I’ve been bugging on IRC in the past few weeks! Matthias Clasen also provided very useful input and I’m afraid he was right on all the line! You guys probably saved me an extra week-end’s worth of time!
A final note: I don’t care much whether sandbox-capable APIs are implemented inside a toolkit, or as an additional layer; whether they should be written as plain C code or neat GObjects with properties, etc.; whether one should use G-DBus or another lib, etc. I care about the exposed APIs feeling to app developers like system APIs rather than a toolkit they can tweak in whatever way they want, because the distinction should be made clear and developers should know that hacks will not result in features but in denied accesses. I’m merely writing code to play with ideas, because that’s what my job is about (lucky students…)!
I hope Sandbox Utils can get us started discussing exactly how apps will obtain and use user documents, and so I’m interested in the opinions of app developers: which features do you need – which are useless to you? What type of data do you want from your users and how do you process it? What makes your day when using a toolkit – and what ruins it and makes you lose time? How can we improve the APIs you use to build apps, to the point where we provide you more value than what you currently have?