Mailcap, HTML and AppArmor

Fed up of being unable to read legitimate multipart/alternative emails in mutt because of badly formatted text/plain sections, I set about fixing my mailcap to have mutt show me the text/html section rendered sensibly.

The usual way to do this is to have the mailcap call out to lynx to convert the HTML into text, and then have mutt display this instead. In my case, I chose links, since by default it renders tables better.

Trouble is, many emails are malicious. They may contain web bugs or attempt to exploit my HTML viewer in some way. How secure is links' (or lynx's) -dump mode in protecting me from this? I wasn't sure, and it seemed like unnecessary attack surface to me. AppArmor to the rescue!

With a custom AppArmor profile, I can arrange for my mailcap to run links constrained. I only need the program to run, read the input file, and write to stdout. No need for it to have network capability or access any other files. So why let it?

To arrange this, I had to edit three files.

The first file is the AppArmor profile itself. I created /etc/apparmor.d/links-local to define a non-attaching profile as follows:

#include <tunables/global>

profile links-local {
  #include <abstractions/base>
  /tmp/links-local-* r,
}

For now, I loaded the profile with the command sudo apparmor_parser -r /etc/apparmor.d/links-local. I think this will automatically load on reboot; I will find out when I reboot next.

The #include <abtractions/base> line pulls in the standard definitions that allow regular programs to run, including things like loading shared libraries. These depend on the tunables I pulled in earlier. Finally, I permit the profile to load a single file in /tmp which I will write to with a wrapper. The prefix should help to ensure that the profile cannot even load some other file in /tmp.

The next file is a wrapper I will use to set up the file in /tmp, and then run links constrained with the profile I defined above. I put this in ~/bin/links-local:

1
2
3
4
5
6
7
8
#!/bin/sh
set -e

tmpfile=`mktemp --tmpdir links-local-XXXXXXXXXX`
clean() { rm -f "$tmpfile"; }
trap clean EXIT
cp "$1" "$tmpfile"
aa-exec -p links-local -- links -dump -force-html "$tmpfile"

Note that I use mktemp for secure /tmp file creation, named using a template that my profile will permit. Then I call aa-exec to constrain links with the profile I loaded earlier.

Finally, I added this entry to ~/.mailcap:

text/html; links-local '%s'; copiousoutput; description=HTML Text

(~/bin/ is already in my PATH)

That's it. Now, from mutt, I can view a text/html section and it'll be rendered securely and appear directly in mutt's pager. I am protected in two ways. First, I hope that links is doing the right thing securely, anyway. Second, even if it is compromised in some way, AppArmor will constrain any compromise from being able to do much on my computer.

Incidentally, I noticed that links does try to do some things that are being blocked by AppArmor. I can see this in dmesg output. It mainly seems to relate to ~/.links2 but doesn't seem to stop the program from operating correctly. This is fine with me. I have no need for it to be touching my home directory when called like this.