In my last posts I've written about the usage of Linux namespaces.
I've took the lessons learned there and went one step further to
create a sandbox called hustior.
What does it do?
hustior tries to hide all of your home directory except the folders
you specify as the program arguments and it will hide all other
processes.
If you call hustior with no arguments it will start a bash and you
will be in your home directory. But your home directory will be
empty. Don't worry your file won't be deleted. They are just not
visible from this bash (and all their child processes).
When you call hustior with the argument
"/home/<user>/path1/path2" it will be the same as above except
that you have one directory in your home: "path2". "path2" will
contain all the subdirectories and files that it also contains
outside of the hustior started bash.
When stopping the hustior started bash all files saved in the home
will disappear. Except they were stored in a mounted directory. Like
e.g. "path2" from the example above.
When to use:
Use it when you want to get an extra line of defense before
executing software or surfing on a site when everything should be
OK. E.g. you start software like NodeJS, VisualCode, Eclipse, ...
All this software is created by well known companies/organisations
and used by millions of people. It should be safe to use. But one
malicious/infected plugin and an attacker has access to all your
mails/picutures/videos/documents. See this XKCD.
The idea of hustior is to allow programs like Eclipse only access to
its binary and its workspace. There is no need to access my mails or
my holiday pictures.
When not to use:
hustior is not battle hardened. Do not use it when you expect to get
attacked. E.g. you execute a script/binary downloaded from a shady
website.
In this case use a virtual machine on a spare PC that you nuke
regularly.
Also don't call hustior as root. You should have absolutely no doubt
about the software you execute as root.
How does it work:
Upon calling hustior restarts itself but in a new user, pid and
mount namespace. The caller id is mapped to 0 and the current used
information is added as a program parameter.
Then it creates a tmp filesystem where it mount bind several
directories and files in it so that you get a complete root
filesystem there.
All binaries are from your main system. That mean when you update
your main system the binaries used by hustior are also up to date.
This is unlike docker where you have to update each container
separately.
Than it will create your home directory and mount bind all
directories that were given as a program argument into it. No
arguments, no directories in home.
All the mount binds are private. That means they aren't visible
outside the process and its children. It means also that once
hustior stops that they will be automatically unmounted.
The last step is to start a bash in a new user namespace. There the
0 id is mapped back to the id of the original caller.
Limits:
The temp filesystem used is only 200MB. Storing more in your home
isn't possible. When you want to store larger files give a directory
as an argument and store the files there.
The started programs have full network access and can even access
ports opened by other processes.
The processes started by the hustior bash aren't isolated from
attacks outside. E.g. an attacker made it to your machine and runs
in your user context (not restricted by hustior) and you start a
browser from the hustior bash. The attacker can see the browser.
Setuid won't work. As a normal user you can only map your own user
id. Per default "an
unmapped user ID is converted to the overflow user ID". So in
the restarted hustior all files that belonged to root will belong to
nobody (when nobody has the overflow user ID). I haven't found a way
to fix this when starting the bash. So in the bash the setuid
programs like ping or Chrome sandbox won't start as the don't belong
to root.
Please also note that hustior is currently tested only on Ubuntu
17.10.
Lessons learned:
I've learned some lessons that aren't worth its own article.
E.g. I didn't know that you can mount bind files. Just create an
empty file and you can mount bind the desired file to it.
When mount binding directories that have mounted file systems (e.g.
you want to mount bind "/var" but there is a mount
"/var/lib/docker/aufs") you need to use recursive as a parameter. At
least when you've got root via user namespace mapping. That is a
kind of security feature as else you may would see what is under
e.g. "/var/lib/docker/aufs" before the real root mounted something
there.
Alternatives:
subuser: Uses docker to
isolate desktop programs. They are aware that docker allows easy
access to root but I don't know if they fix the docker installation
or only their usage of docker.
Bubblewrap:
From their readme: "The goal of bubblewrap is to run an application
in a sandbox, where it has restricted access to parts of the
operating system or user data such as the home directory.". As far
as I can tell is isn't an out of the box sandbox but the user has to
provide the right parameters to get the sandbox he needs. Requires
setuid root.
isolate: From their
readme: "Isolate is a sandbox built to safely run untrusted
executables, offering them a limited-access environment and
preventing them from affecting the host system." Requires setuid
root.
Qubes OS: Uses virtual
machines to isolate workspaces. This is definitely more secure than
hustior but also needs more resources.