Back in 1995 or so, pretty much everyone with a PC did all their work as root. We ran graphics editors, word processors, everything as root. Well, not literally an account named “root”, but the most common DOS, Windows, and Mac operating systems of the day had no effective reduced privilege account.
It was that year that I tried my first Unix. “Wow!” A virus can’t take over my system. My programs are safe!
That turned out to be a little short-sighted.
The fundamental problem we have is that we’d like to give users of a computer more access than we would like to give the computer itself.
Many of us have extremely sensitive data on our systems. Emails to family, medical or bank records, Bitcoin wallets, browsing history, the list goes on. Although we have isolation between our user account and root, we have no isolation between applications that run as our user account. We still, in effect, have to be careful about what attachments we open in email.
Only now it’s worse. You might “npm install hello-world”, and audit hello-world itself, but get some totally malicious code as well. How many times do we see instructions to gem install this, pip install that, go get the other, and even curl | sh? Nowadays our risky click isn’t an email attachment. It’s hosted on Github with a README.md.
Not only that, but my /usr/bin has over 4000 binaries. Have every one been carefully audited? Certainly not, and this is from a distro with some of the highest quality control around. What about the PPAs that people add? The debs or rpms that are installed from the Internet? Are you sure that the postinst scripts — which run as root — aren’t doing anything malicious when you install Oracle Virtualbox?
Wouldn’t it be nice if we could, say, deny access to everything in ~/.ssh or ~/bankstatements except for trusted programs when we want it? On mobile, this happens, to an extent. But we have both a legacy of a different API on desktop, and a much more demanding set of requirements.
It feels like our ecosystem is on the cusp of being able to do this, but none of the options I’ve looked at quite get us there. Let’s take a look at some.
AppArmor
AppArmor falls into the “first line of defense — better than nothing” category. It works by imposing mandatory access controls on a per-executable basis. This starts out as a pretty good idea: we can go after some high-risk targets (Firefox, Chromium, etc) and lock them down. Great! Although it’s not exactly intuitive, with a little configuration, you can prevent them from accessing sensitive areas on disk.
But there’s a problem. Actually, several. To start with, AppArmor does nothing by default. On my system, aa-unconfined --paranoid lists 171 processes that have no policies on them. Among them are Firefox, Apache, ssh, a ton of Pythons, and some stuff I don’t even recognize (/usr/lib/geoclue-2.0/demos/agent? What’s this craziness?)
Worse, since AppArmor matches on executable, all shell scripts would match the /bin/bash profile, all Python programs the Python profile, etc. It’s not so useful for them. While AppArmor does technically have a way to set a default profile, it’s not as useful as you might think.
Then you’re still left with problems like: a PDF viewer should not ordinarily have access to my sensitive files — except when I want to see an old bank statement. This can’t really be expressed in AppArmor.
SELinux
From its documentation, it sounds like SELinux might fit the bill well. It allows transitions into different roles after logging in, which is nice. The problem is complexity. The “notebook” for SELinux is 395 pages. The SELinux homepage has a wiki, which says it’s outdated and replaced by a github link with substantially less information. The Debian wiki page on it is enough to be scary in itself: you need to have various filesystem support, even backups are complicated. Ted T’so had a famous comment about never getting some of his life back, and the Debian wiki also warns that it’s not really tested on desktop systems.
We have certainly learned that complexity is an enemy of good security, leading users to just bypass it. I’m not sure we can rely on it.
Mount Tricks
One thing a person could do would be to keep the sensitive data on a separate, ideally encrypted, filesystem. (Maybe even a fuse one such as gocryptfs.) Then, at least, it could be unavailable for most of the time the system is on.
Of course, the downside here is that it’s still going to be available to everything when it is mounted, and there’s the hassle of mounting, remembering to unmount, password typing, etc. Not exactly transparent.
I wondered if mount namespaces might be an answer here. A filesystem could be mounted but left pretty much unavailable to processes unless a proper mount namespace is joined. Indeed that might be a solution. It is somewhat complicated, though, since nsenter requires root to work. Enter sudo, and dropping privileges back to a particular user — a not particularly ideal situation, and complex as well.
Still, it might well have some promise for some of these things.
Firejail
Firejail is a great idea, but suffers from a lot of the problems that AppArmor does: things must explicitly be selected to run within it.
AppImage and related tools
So now there’s your host distro and your bundled distro, each with libraries that may or may not be secure, both with general access to your home directory. I think this is a recipe for worse security, not better. Add to that the difficulty of making those things work; I know that the Digikam people have been working for months to get sound to work reliably in their AppImage.
Others?
What other ideas are out there? I’ve occasionally created a separate user on the system for running suspicious-ish code, or even a VM or container. That’s a fair bit of work, and provides incomplete protection, but has some benefits. Still, it’s again not going to work for everything.
I hope to play around with many of these tools, especially SELinux, before too long and report back how I’ve found them to be.
Finally, I would like to be really clear that I don’t believe this issue is limited to Debian, or even to Linux. It impacts every desktop platform in wide use today. Actually, I think we’re in a better position to address it than some, but it won’t be easy for anyone.
You should look at Qubes, Subgraph, Bubblewrap, Flatpak, Flatpak portals etc.
Seconding Flatpak portals.
You can, for instance, let an application spawn an “open” dialog, and give it access to the file the user selected, but not to the rest of the user’s files.
To expand on what Qubes does, it takes the VM/container approach by having you set up different isolated “qubes” to handle different aspects of your digital life, and they can have different security levels. So you have some for interacting with the Internet, another for banking and finances, another that’s locked down tight with all your secrets, etc. I haven’t had the opportunity to use it myself, so I don’t know how well it delivers.
The problem with Flatpak Portals is the same as that of AppArmor: it is only selectively applied to certain applications, not to everything on the system. Actually, it’s worse, because now you have to worry about the security of all the components inside the Flatpak as well. I mean, if you’re going to do Flatpak anyway, it’s good to have that, but it’s not a general solution.
I’m going to look into Bubblewrap some more. It might just be possible to use it to create a mount namespace with more mounts than the parent, and mount sensitive things only in there. For that matter, Firejail may be able to do this also. I’ll check it out.
Qubes looks really interesting. They have certainly made separate VMs easier to manage than I’ve seen before. The challenge, of course, is that in the “sensitive” VM there may yet be many thousands of binaries that aren’t isolated from the sensitive data. I’d be concerned about performance/resource utilization for using it as an everyday OS on, say, a laptop — but I like their ideas, especially with the WM colors.
I’ve used Qubes for over a year. I actually liked it much but dropped it mainly for three reasons: lack of convenience, maturity and it wasn’t Debian/KVM based. The upgrades were a bit of a pain. I think the concept though is really nice!
make several users and use each one for a different purpose. Eg, dedicated user for on-line banking, another for gov’t access (eg, checking/paying taxes), etc. Has the added advantage of separating your general browsing history from these other suppliers. I don’t know how useful this is when you have a static IP address, but, oh well. It’s better than not doing it.
It /is/ inconvenient.
I’ve just been studying up on AppArmor now that it’s enabled by default in Debian 10. I’m pleased to be able to report that for interpreted scripts (shell, Perl, etc), if the script has the execute permission set and a shebang, and is invoked directly (not as an argument to the interpreter), then it can be confined by its own profile, not that of the interpreter.
So for the following command, AppArmor will do as John describes:
/usr/bin/perl /home/tom/myscript.pl
but for this next command it will do what is probably more useful and desired:
/home/tom/myscript.pl
I’ve tested this and it’s really true.
I appreciate your thoughtful blog John, thanks.
Tom