Memory erasure
In order to protect against memory recovery such as cold boot attack,most of the system RAM is overwritten when Tails is being shutdown or when theboot medium is physically removed. Also, memory allocated to processesis erased upon process termination.
The big picture
Tails now relies on the Linux kernel's freed memory poisoning feature.
But memory poisoning only works when memory is actually freed,and a regular shutdown would not free the memory used by the overlayfsread-write branch. So we use thesystemd-shutdown ability to returnto the initramfs, to ensure the root filesystem is unmounted.
The initramfs is unpacked in/run/initramfs at boot time:
- config/chroot local-includes/lib/systemd/system/initramfs-shutdown.service
- config/chroot local-includes/usr/local/lib/initramfs-restore
- config/chroot local-includes/usr/local/lib/udev-watchdog-wrapper
… so that the copy ofsystemd-shutdown that runs in the real,non-initramfs system can switch root into/run/initramfs, and runanother copy ofsystemd-shutdown that'sincludedin the initramfs. That one will unmount all filesystems, runa custom hookthat helps us automatically test this behavior, and finally performthe requested poweroff/reboot action.
To make this work, a dedicatedtmpfs filesystem ismounted on/run/initramfs:/run is mounted with thenoexec option and while our attempts to remount it withexecworked for clean shutdown, they failed for emergency shutdown, i.e.when the boot medium is physically removed.
For details about the underlying systemd mechanisms, see:
bootup(7)systemd-shutdown(8)- https://www.freedesktop.org/wiki/Software/systemd/InitrdInterface/
In our experience, jumping back to the initramfs to unmount the remainingfilesystems, as described above, was necessary but not sufficient to free thememory used by the overlayfs read-write branch. That's why additionally, wemanually delete the content of that branch viaa systemd service late in the shutdown process, before we jump back tothe initramfs. It's unclear to us why this works when the boot mediumis physically removed: in that case,systemctl --force poweroffisnot supposed to stoptails-remove-overlayfs-dirs.service, and thusthis additional clean up step should be skipped; it could be that in thisemergency shutdown situation,systemd-shutdown somehow manages to cleanthings up by itself and there's no need fortails-remove-overlayfs-dirs.service.
Triggers
Different kinds of events trigger the memory erasure process. All leadto run the shutdown process that erases memory.
First, most memory is erased at the end of a normal shutdown/rebootsequence. This is implemented by theLinux kernel's freed memorypoisoning feature, more specificallyinit_on_free=1.
Automated testsensure that the most important parts of memory are erased this way.
Second, the memory erasure process is triggered when the boot mediumis physically removed during runtime (USB boot medium is unplugged orboot DVD is ejected). This is implemented by a customudev-watchdogprogram monitors the boot medium; it's run by a wrapper, started atboot time, that brutally invokes the memory erasure process, bypassingother system shutdown scripts, when this medium happens to bephysically removed.
Note that theudev-watchdog is disabled while the system is suspended to RAM,in order to avoid a race condition when resuming from suspend, which used tooccasionally trigger the emergency shutdown (see#11729).This means that the memory erasure process is not triggered if the bootmedium is removed while the system is suspended.
- config/chroot local-includes/usr/local/lib/udev-watchdog-wrapper
- config/chroot local-includes/usr/src/udev-watchdog.c
- config/chroot local-hooks/52-udev-watchdog
- config/chroot local-includes/lib/systemd/system/tails-shutdown-on-media-removal.service
- config/chroot local-hooks/52-update-systemd-units
- config/chroot local-includes/lib/systemd/system/gdm.service.d/restart.conf
- config/chroot local-includes/lib/systemd/system-sleep/toggle-tails-shutdown-on-media-removal.sh
Making sure needed files are available
Thememlockd daemon, appropriately configured, ensures every fileneeded by the memory erasure process is locked into memory from bootto memory erasure time.
- memlockd
- config/chroot local-includes/etc/memlockd.cfg
- config/chroot local-patches/keep memlockd on shutdown.diff
- config/chroot local-includes/lib/systemd/system/memlockd.service.d/oom.conf
Limitations
As discussed inan email threadwith the authors ofPAX_MEMORY_SANITIZE, kernel memory poisoningdoes not clearall kinds of memory once it's freed:
we enable free poisoning for the buddy allocator, the slub/slabones, and heap memory, but there may be other ways the Linux kernel allocatesmemory, that are not subject to poisoning;
on shutdown all process memory is freed (and thus erased), but somekernel memory is not erased on shutdown, and is currentlynot erased.
It's not obvious that our previous approaches (see below) did anybetter, and this one is much more reliable, so we think this trade-offis the most sensible one with the resources and skills currentlyavailable for Tails.
Obsolete approaches
The initial implementation of the Tails memory erasure featuresuffered from flaws that were demonstrated byexternalaudit. In short, itonly erased free memory and let data in the union filesystem read-write branch inrecoverable state.
Then, in order to erase the biggest possible part of the system memory,a new implementation, shipped from Tails 0.7 to 2.12, runs in afresh environment provided by a newly started Linux kernel. This way,a given part of the memory either isused by the memory erasureprocess itself or it is considered as free and thuserased by thisprocess; in any case, it is at least overwritten once.
Sadly, this approach suffered from severe usability and reliabilityproblems (e.g.#12354,#11786).So it was removed in Tails 3.0.
