[[!meta title="Application isolation"]]

[[!toc levels=3]]

Goals
=====

For now, we are only aiming at filesystem resources isolation: that
is, making sure that e.g. Pidgin cannot read the GnuPG keyring.

Other types of resources, such as signals, X, ptrace, sockets, D-Bus
etc. are [[not part of the isolation goals
yet|application_isolation#more-resources]].

Tools and basic configuration
=============================

For now, we have decided to use AppArmor to isolate applications,
mostly because:

* it is simple: AppArmor policy is relatively easy to understand,
  improve, and audit;
* it is the best supported [[!wikipedia mandatory access control]]
  framework in Debian; it wasn't too hard to reach this point, and
  there is quite some room for improvement via collaboration with
  other distributions, most notably Ubuntu.

The [[!debpts apparmor]] package is installed, and AppArmor is
[[!tails_gitweb config/amnesia desc="enabled on the kernel
command-line"]].

Confinement profiles
====================

The AppArmor confinement profiles included in Tails come from:

* individual Debian packages that ship confinement profiles, e.g.
  Tor;
* the [[!debpts apparmor-profiles]] package;
* the [[!debpts apparmor-profiles-extra]] package;
* the [[!debpts torbrowser-launcher]] package:
  - [[!tails_gitweb config/chroot_local-includes/usr/share/tails/torbrowser-AppArmor-profile.patch]]
  - [[!tails_gitweb config/chroot_local-hooks/19-install-tor-browser-AppArmor-profile]]

To get the full and current list, run `aa-status` as `root`
inside Tails.

Hacks to support the Live system usecase
========================================

Most Live systems use a union filesystem to provide the operating
system with a read-write filesystem, based on a read-only branch
(typically, SquashFS) and a read-write one (most often, tmpfs).

Unfortunately, AppArmor currently does not support union filesystems
very well, because the LSM hooks do not allow it to distinguish
between an access to the upper layer, and an access to the loop-backed
underlying layer.

So, we have to adjust profiles a bit to make them support the paths
that are actually seen by AppArmor in the context of Tails.

First, we are using a couple of
[aliases](http://wiki.apparmor.net/index.php/AppArmor_Core_Policy_Reference#Alias_and_rewrite_rules)
so that rules applying to "normal" paths (e.g.
`/home/amnesia/.gnupg/`) also apply to Debian Live -specific paths,
such as `/lib/live/mount/overlay/home/amnesia/.gnupg/`. And, to avoid
subsequent problems with overlapping rules, and to mitigate the
increased policy compilation time (see details below), we also patch
some some very broad rules to make them _not_ apply to `/lib/live/*`.
All these changes live in
[[!tails_gitweb config/chroot_local-patches/apparmor-aliases.diff]].

Second, few more targeted adjustments are also applied:

* [[!tails_gitweb config/chroot_local-includes/etc/apparmor.d/tunables/home.d/tails]]
* [[!tails_gitweb config/chroot_local-patches/apparmor-adjust-pidgin-profile.diff]]
* [[!tails_gitweb config/chroot_local-patches/apparmor-adjust-tor-abstraction.diff]]
* [[!tails_gitweb config/chroot_local-patches/apparmor-adjust-tor-profile.diff]]
* [[!tails_gitweb config/chroot_local-patches/apparmor-adjust-totem-profile.diff]]

Below, we discuss various leads that might avoid the need for coming
up with such adjustments, and maintaining it.

<a id="ux"></a>

User experience matters
=======================

Currently, no good way exists to let the user choose an arbitrary file
each time they want to open or save one, without leaving the AppArmor
profiles wide-open and then much less useful.

Solutions to this problem are work-in-progress in various upstream
places, e.g.:

* [for
  AppArmor](https://lists.ubuntu.com/archives/apparmor/2015-March/007415.html)
* for GNOME sandboxed applications:
  - [Initial ideas on portals for file
    access](https://mail.gnome.org/archives/gnome-os-list/2015-March/msg00010.html)
    thread on gnome-os-list
  - <https://wiki.gnome.org/Design/OS/Sharing>

The idea is generally to introduce a privileged mediation layer
between applications, the GTK file chooser and the filesystem. So,
some day we can solve this problem in better ways, but we're not
there yet.

Tor Browser
-----------

As of Tails 1.3, the Tor Browser is somewhat confined with AppArmor.

Given we cannot seriously allow the Tor Browser to read and write
everywhere in the home and persistent directory, we had to allow it to
read/write files from/to one specific directory, and make it so the
user experience is not hurt too much.

Now, let's say we have a downloads/uploads directory that's shared
between the Tor Browser, the file browser, and all non-confined
applications. That directory is called `~/Tor Browser/`, and a GTK
bookmark pointing to it is created at login time:

* [[!tails_gitweb config/chroot_local-includes/usr/lib/systemd/user/tails-create-tor-browser-directories.service]]
* [[!tails_gitweb config/chroot_local-includes/usr/local/lib/create-tor-browser-directories]]
* [[!tails_gitweb config/chroot_local-includes/usr/lib/systemd/user/tails-add-GNOME-bookmarks.service]]
* [[!tails_gitweb config/chroot_local-includes/usr/local/lib/add-GNOME-bookmarks]]

Then, we have a usability issue: the space available in that directory
is limited by the free system memory (RAM). So large file downloads
may fail. Note that Firefox doesn't mind letting users start
downloading a file to a directory that hasn't enough room available to
store it entirely, so this problem is not specific to downloading to
an amnesiac directory.

Still, we thought it would be good to allow users to download large
files from Tor Browser to their persistent volume, so we have
introduced a second downloads/uploads directory: `~/Persistent/Tor
Browser/`, that is created whenever the "Personal data" (aka.
`~/Persistent/`) persistence feature is activated. In that case, if
persistence was activated read-write, another GTK bookmark pointing to
that directory is created at login time.

This seemed to be better than introducing yet another persistence
feature (e.g. for `~/Tor Browser/`): having downloads be either always
amnesiac or always persistent (unless you restart or do stuff outside
of the browser) would seem like a regression, since it breaks one of
the core Tails properties. And forcing it to be a persistent folder by
default actually has security issues since secure deletion does not
work as expected on Flash memory. So, we decided that users need to
have the option to download either to an amnesiac (`~/Tor Browser/`)
or persistent (`~/Persistent/Tor Browser/`) place, like it was the
case previously.

So, in a nutshell we give Tor Browser access to:

* `~/Tor Browser/`, which is amnesiac, as everything else in Tails by
  default; this is set to be the default download directory
  ([[!tails_gitweb config/chroot_local-includes/etc/tor-browser/profile/preferences/0000tails.js]]);
* `~/Persistent/Tor Browser/`, that is persistent, and only created
  when `~/Persistent/` is itself persistent and read-write.

Note that we don't call these folders "Downloads", because e.g.
if someone creates an ODT file and wants to upload it, having to move
it to a folder called "Downloads" sounds really weird.

Future work
===========

More confinement profiles
-------------------------

As part of the [[!debwiki AppArmor desc="Debian AppArmor Team"]], we
are working to get more well-tested and maintained profiles integrated
into the distribution, and to improve cross-distribution collaboration
in this area.

<a id="more-resources"></a>

Isolating more types of resources
---------------------------------

With AppArmor 2.9, once the corresponding kernel patches are
merged into Linux mainline, we will get support for mediating many
more types of resources: D-Bus calls, sockets, signals and so on.

[[Linux containers|application_isolation#linux-containers]] may also
be a good way to isolate more types of resources.

Using alias rules to avoid modifying profiles
---------------------------------------------

The most obvious trick to workaround AppArmor's lack of support for
union filesystems is to use [alias
rules](http://wiki.apparmor.net/index.php/AppArmor_Core_Policy_Reference#Alias_and_rewrite_rules),
such as:

      echo 'alias / -> /lib/live/mount/rootfs/filesystem.squashfs/,' \
      >> /etc/apparmor.d/tunables/alias

However, a number of problems prevent this seemingly simple solution
from just working in the context of Tails. The following discusses
these complications, and a few possible solutions.

### Bugs in alias rules implementation

The implementation of alias rules is affected by severe bugs, such as
<https://bugs.launchpad.net/apparmor/+bug/888077>.

There's preliminary work to fix this at
<https://code.launchpad.net/~jjohansen/+junk/parser-alias-fix>.
Note that this code can still revert to the previous behaviour by
passing the `-O old-alias` option to `apparmor_parser`.

### Overlapping rules

Alias rules can generate rules that overlap (and conflict) with
existing ones, which can cause the policy to fail to compile.

E.g. the `sanitized_helper` profile (sourced by the Evince
profile and many others) contains this rule:

    /lib{,32,64}/**/ld{,32,64}-*.so     mrix,

which, once combined with this alias:

    alias / -> /lib/live/mount/rootfs/filesystem.squashfs/,

will end up overlapping a lot of the rules generated for the alias.
E.g.

    /bin/* Pixr,

results in a rule of:

    /lib/live/mount/rootfs/filesystem.squashfs/bin/* Pixr,

being generated, however since the alias command does not remove other
rule sets, it only adds new rules. We end up with both:

    /lib{,32,64}/**/ld{,32,64}-*.so     mrix,
    /lib/live/mount/rootfs/filesystem.squashfs/bin/* Pixr,

which causes a conflict between `ix` and `Pix`.

To workaround this problem, we would need to change the
`/lib{,32,64}/**/ld{,32,64}-*.so mrix,` rule into:

    /lib{32,64}/**/ld{,32,64}-*.so     mrix,
    /lib/{[^l],l[^i],li[^v],liv[^e],live[^/]}**/ld{,32,64}-*.so mrix,

which allows the profile to compile, as the `x` conflict has
been removed.

Needless to say, this kind of regexp is painful to write, audit and
maintain. Things could be nicer if AppArmor supported set operations;
instead, we could do something like (syntax not finalized):

    /lib/{^live**}/ld{,32,64}-*.so     mrix,

Other problematic overlaps include e.g. this rule from the
`sanitized_helper` profile:

    audit deny owner /**/* m,

... that will take away the executable mmap permission from _all_
applications under `/lib/live/` path, if the root user (who owns the
file) tries to launch an application.

This can possibly be fixed using [[rewrite
rules|application_isolation#rewrite-rules]] instead of aliases, or by
an update to the AppArmor permission merging logic that would give us
a way to define that the alias rules should have priority in
the union.

Fixing such problems one after the other may be doable, but
regardless: the way alias rules affect the policy as a whole,
especially once combined with globing, would make our policy harder to
understand, reason about, and audit.

### Persistence

It may be that more aliases are needed to support the bind-mounts set
up by `live-boot` when using the [[contribute/design/persistence]]
feature. It may even be that these aliases need to be dynamically
added, in function of the persistence configuration... that is, at
login time. If that was the case, then the entire policy would need to
be recompiled at login time, which could make the user experience very
painful, especially considering that alias rules vastly increase
policy compilation time.

### Increased policy compilation time

Alias rules dramatically increase the policy compile time (e.g.
100 seconds for the Evince profile, that can be brought down to
8 seconds with the aforementioned rule change in the
`sanitized_helper` profile).

To mitigate that problem, we could:

- either look at the rules and see if we can optimize it... which kind
  of defeats the purpose of using alias rules in the first place to
  avoid the need for modifying profiles;
- or ship a cached pre-compiled policy. As long as the parser and
  kernel are in sync, the policy can be pulled straight from the
  cache, without any compilation. If the parser detects that the
  policy is out of date, then the cache will be ignored and
  compilation will happen. This is what is done for the Ubuntu phone.
  Note that the "exact same kernel" requirement has been relaxed,
  either `--match-string` or `--features-file` or both ought to let
  a new-enough parser generate "correct" policy for a given target
  kernel using any other kernel. This could allow precompiling on the
  build hosts. See `apparmor_parser(8)`, `apparmor_parser --help`,
  examples in `parser/tst/features_files/*`, and `parser.conf`.
  Potential problems:
  * missing documentation: see <https://bugs.launchpad.net/bugs/1491147>
  * if alias rules need to be added at login time, then the cache must
    be invalidated, and the policy entirely recompiled;
  * it remains to be researched how well this would work, once
    combined with the [[additional software
    packages|doc/first_steps/persistence/configure]] persistence
    feature.

<a id="rewrite-rules"></a>

Using rewrite rules to avoid modifying profiles
-----------------------------------------------

Other than alias rules, another option to avoid modifying profiles
would be to use [rewrite
rules](http://wiki.apparmor.net/index.php/AppArmor_Core_Policy_Reference#Alias_and_rewrite_rules).
They're basically the same as alias rules, except that it doesn't
duplicate rules, so no conflicting rules are generated.

It remains to be researched if rewrite rules would work in our use
case: e.g. it might be that some files are seen as read from the
SquashFS initially, and written to the overlay. If that would be the
case, then we would need to duplicate some rules in profiles to add
back some paths that were rewritten.

<a id="overlayfs"></a>

overlayfs
---------

[overlayfs](https://git.kernel.org/cgit/linux/kernel/git/mszeredi/vfs.git/tree/Documentation/filesystems/overlayfs.txt?h=overlayfs.current)
is another kind of union filesystem. It has been merged in
Linux mainline, and is supported by live-boot 5.
overlayfs works differently from aufs, in ways that give hope that it
might be easier for AppArmor to support it natively.

Some ongoing work on AppArmor (labeling, extended conditionals) will
help support overlayfs. Time will tell whether the result meets
our needs.

See [[!tails_ticket 9045]] for more up-to-date information.

<a id="linux-containers"></a>

Linux containers
----------------

Using Linux containers for application isolation is being [[researched
separately|blueprint/Linux_containers]].

Credits
=======

We owe a lot of thanks to John Johansen (<john.johansen@canonical.com>)
for his patience and support. Substantial parts of this document were
adapted from explanations he provided to us.
