Fix External GPG in Thunderbird Snap

Carson Fleming

Oct 11, 2024 | Technology

I want to preface this take with a shout out to Luci Stanescu from the snapcraft forum, whose post got me like 75% of the way to this completed solution.

With the release of 24.04, Ubuntu will now ship Mozilla's email client, Thunderbird, as a transitional deb-to-snap package. I don't even hate snaps, but I really wish Canonical would stop doing this. Users should be aware and consenting when apps they use on a daily basis are slowed down and sandboxed for the sake of security. I get not wanting to maintain the same package in two formats, but making apt install snaps feels kind of underhanded and undermines a user's ability to customize their own system. There's a fine line to be walked between security by default (installing these apps as snaps for people who don't know better), and security by force (actively obstructing people who do know better in their attempts to install a deb package). I'll digress on that front, though, because it'd be one thing if these snaps were rock-solid and battle-tested. As will become very clear later on, however, the snap version of Thunderbird breaks privacy-critical features in a way that makes it very clear, nobody from the testing team has bothered to run this code even one single time.

What is GPG, and why is it broken?

If you've never heard of GnuPG (GPG) or PGP, the only thing you need to know to understand this problem is that it's a technology that can encrypt your emails from end to end, and it uses special files as keys to decrypt said emails when you receive them. Mozilla Thunderbird has extensive support for this technology, but the way it works by default is kind of weird: it keeps your keys on your hard drive, right next to the emails they unlock.

That's a lot like locking up your house, then leaving the keys under the doormat. It will definitely deter a crime of opportunity, but when it comes to anyone who actually wants to break in and steal your stuff, it'll be the first thing they check. How do you prevent this? The same way as in real life: you carry your keys with you. Keep those special key files on a smart card or a USB stick, like a Yubikey, and take them with you when you leave. Just like your house keys.

Thunderbird Problems

Smart cards are a relatively new technology, and a lot of email vendors haven't bothered to implement their own support for them yet. That's not normally an issue, because your email client, say, Thunderbird, can just talk to the regular GnuPG app and ask it to do all the cryptography. The problem arises when you put Thunderbird in a sandbox and don't properly test that it can talk to everyone it needs to talk to in order to get the job done. Then, you get nice opaque errors like these when you try to read and send emails:

Trying to read my email.
Trying to send an email.

Snaps are supposed to be marketed at GUI-only users, who have no desire to dig into Linux internals. For them, this is an "uninstall this shitty app" situation. Worse, it could end being a "compromise my security with the convenient alternative" situation, because they truly don't know any better. The icing on the cake is, when you google this question, you do actually come up with some relevant results. And zero of said results actually tell you how to fix the problem, so mid-level Linux hobbyists are in stuck in the same predicament. All that's left are people who grep syslog for apparmor="DENIED" when they run into opaque snap bugs, and you will certainly not be winning any elections with numbers like those. The tricky thing about security is it's not something you can do on your own, so this is pretty fucking unacceptable as far as I'm concerned.

How to Fix It

We could do what the rest of the internet tells us to do, which includes:

  1. Downloading the binary from the Thunderbird Website and subjecting ourselves to decentralized app updates whenever we go to use it. Personally, that was one of my least favorite features of Xbox, so I'll pass on this one.
  2. Using the perpetually out-of-date Mozilla PPA. Not even going to link it, hard no.
  3. Bitching out and distro-hopping. Enough shit like this and maybe I will, but not today. Secretly, they all have their bullshit to deal with, which is why Linux doesn't have any market share.

To be honest, I don't really hate the idea of sandboxing my email client. I just hate that it doesn't fucking work. So all that leaves is option D, to knuckle down and fix this shit ourselves. And that is the game plan for today, ladies and gentlemen.

Making a GPG Wrapper

The first thing that's gone wrong here is that absolutely zero people have ever tested this. The environment variables that they've set up in their GPG shim are just blatantly incorrect. This is pretty indefensible, since clearly someone wrote code with this exact use case in mind, and then never actually ran it. ???

To fix this, we're going to replace their GPG shim one that doesn't suck ass. Make a shell script called gpg.sh in ~/snap/thunderbird/common containing the following:

#!/bin/sh
HOME="$SNAP_REAL_HOME" $SNAP/usr/bin/gpg $@

In the rare event you have multiple users on your system, do this for all of them. You could also fix the actual gpg shim in /snap/thunderbird/current/bin, but any updates will re-break it.

If lazy, copy-paste these commands and go next:

cd ~/snap/thunderbird/common
echo '#!/bin/sh' >gpg.sh
echo 'HOME="$SNAP_REAL_HOME" $SNAP/usr/bin/gpg $@' >>gpg.sh
chmod +x gpg.sh

Thunderbird Settings

Next, we have to set two hidden Thunderbird settings, so open Thunderbird, click the context menu on the top right, scroll down to the bottom of the General tab, and click Config Editor:

Advanced Thunderbird settings

First, we need to enable mail.openpgp.allow_external_gnupg. This used to be enabled by default, but I guess someone eventually realized it shits a brick and decided to disable it instead of fixing. Certified engineering classic.

Enable External GnuPG

Next, we need to change the GnuPG app that Thunderbird tries to talk to from the shitty broken shim that comes in the package, to the better one that we just made. We can do this by setting mail.openpgp.alternative_gpg_path to /home/{YOUR USERNAME}/snap/thunderbird/common/gpg.sh.

Set Alternative GPG Path

Make sure you use your username in the path rather than my username.

Finally, there's the small matter of granting the permission that was supposed to gatekeep this functionality, but doesn't actually work. Just run:

snap connect thunderbird:gpg-keys :gpg-keys

AppArmor Configuration

In addition to that outrageous oversight by the package maintainers, we'll need to change the snap's AppArmor confinement to let it actually talk to your GnuPG app. This ends up being relatively simple to execute, but it's hard know what to do if you've never messed with this stuff before.

If you try to either read or send mail in Thunderbird at this stage, and then have a look at your syslog, you should see a message that looks like this:

2024-10-09T02:13:26.068887-04:00 sand kernel: audit: type=1400 audit(1728454406.068:287): apparmor="DENIED" operation="connect" class="file" profile="snap.thunderbird.thunderbird" name="/run/user/1000/gnupg/S.gpg-agent" pid=24269 comm="gpg" requested_mask="wr" denied_mask="wr" fsuid=1000 ouid=1000

This incredibly legible message just means that Thunderbird (or really, gpg on behalf of Thunderbird) tried to access a file called /run/user/1000/gnupg/S.gpg-agent with read and write permissions. That's expected, because that file is the socket used to talk to the GnuPG Agent, the process which controls all of your keys. So, we (and eventually the developers of this highly robust application) have to let it do so.

Ubuntu does weird shit regarding AppArmor profiles for Snap apps that I'm going to skip over, but basically we have to copy the default AppArmor profile for the snap from /var/lib/snapd/apparmor/profiles/snap.thunderbird.thunderbird to /etc/apparmor.d, a la:

sudo cp /var/lib/snapd/apparmor/profiles/snap.thunderbird.thunderbird /etc/apparmor.d

Then we need to edit /etc/apparmor.d/snap.thunderbird.thunderbird. Inside the block that starts with:

profile "snap.thunderbird.thunderbird" flags=(attach_disconnected,mediate_deleted) {

we need to add a line that says:

owner /run/user/[0-9]*/gnupg/S.gpg-agent rw,

This means that the owner of any file with the path structure /run/user/{USER ID}/gnupg/S.gpg-agent can read and write to said file from within Thunderbird. It doesn't matter where you add the line, but if you want you can search for the other gpg stuff and put it nearby.

Once you've done this, you can restart your computer and read/send email as normal. Alternatively, if you're one of those freaks that never restarts, you can issue this command to reload AppArmor:

sudo systemctl reload apparmor

Et voila, we've spent fifteen minutes to make something work that should've worked out of the box. Eventually I'll submit fixes upstream for this, but judging based on this PR discussion in snapd, it's going to be a colossal pain in the ass.

Copyright © 2024 Carson Fleming