Ubuntu – Can Ubuntu 14.04 use encrypted swap without resorting to unofficial hacks

14.04bootencryptionswap

On a fresh install of Ubuntu 14.04, I get this error message during boot

the disk drive for /dev/mapper/cryptswap1 is not ready yet or not present

and the swap partition is never activated. From my searches so far I have found:

  • It is a widespread problem, probably affecting every Ubuntu 14.04 install on which encrypted swap was activated.
  • Part of the problem is an easy to fix bug causing the encrypted swap header (generated during boot) to overwrite the unencrypted swap header, which makes it impossible to find the correct partition again during the next boot.
  • All the proposed solutions to get it work appears to be simply workarounds amounting to: 1. Disable swap by setting it as noauto in fstab. 2. Create an /etc/rc.local file (or define your own service to be activated during boot), which activates the swap partition.

Is it possible to use encrypted swap on Ubuntu 14.04 without using this sort of hack? I am perfectly comfortable updating all the installed packages and fix those configuration files, which got initialized with incorrect content due to buggy install scripts. I'd rather avoid having to use my own script to activate swap, as that sort of approach have a tendency to break when packages are updated.

This is what my /etc/crypttab looks like:

cryptswap1 /dev/sda6 /dev/urandom swap,cipher=aes-cbc-essiv:sha256,offset=16

And the relevant line from my /etc/fstab is:

/dev/mapper/cryptswap1 none swap sw 0 0

What I have tried so far:

I have found message disk drive for /dev/mapper/cryptswap1 is not ready yet or not present even after trying various options asking about what might be the same scenario.

But the only answer is suggesting to using un-encrypted swap.

I have found http://ubuntuforums.org/showthread.php?t=2200995 which claims to have a solution, but the solution makes no sense to me.

The first part of the proposed solution is to rewrite the encrypted swap header using mkswap. However since this header is encrypted with a key, that is not persistent across reboots, this step wouldn't help getting the swap working after the next reboot.

It also suggests updates to /etc/fstab, but it appears my fstab is already looking correctly.

The post assumes LVM, which I do not use. I am unaware of any way, that would make a difference.

I have found https://bugs.launchpad.net/ubuntu/+source/ecryptfs-utils/+bug/1310058 which helped me understand the issue with the swap header being overwritten and that adding offset to crypttab and regenerating the unencrypted swap header, can resolve this problem.

However the overwritten header is not the only issue at play, there is another issue, which I do not fully understand yet.

Other things I have found out about the problem:

From reading /lib/cryptsetup/cryptdisks.functions I learned that during boot, the device is supposed to be created using the name cryptswap1_unformatted then the encrypted swap header is to be written, and the device is to be renamed as cryptswap1. In the kernel log I find this error message:

[   39.419429] device-mapper: ioctl: Unable to change name on mapped device cryptswap1_unformatted to one that already exists: cryptswap1

Confusingly the outcome of that turns out to be that the device does end up having the name cryptswap1, but the swap header never got written.

Swap works during those boots where a file system check was performed. It is only when no file system checks is performed, that I get the dreaded cryptswap1 is not ready yet error.

In /var/log/upstart/cryptdisks.log I find the error message

Device cryptswap1_unformatted already exists.

However by adding some additional logging to /lib/cryptsetup/cryptdisks.functions, I learned that there is a race between /etc/init.d/cryptdisks-early and /etc/init/cryptdisks.conf. Any logging I add to cryptdisks.functions can influence how the actions of the two scripts are interleaved, and occasionally, it ends up working.

It is clear that the two are not supposed to be handling the same device in parallel. How can I get the two scripts serialized, such that swap works on every boot?

Best Answer

There are two separate problems which must be resolved in order to get cryptswap1 working correctly in Ubuntu 14.04.

Problem 1: Overwritten swap header

The partition has originally been formatted with an unencrypted swap header, which is used to find the correct partition to use during boot. Because the encryption key changes at each boot, the encrypted swap header will be rewritten at each boot. Due to a bug in generation of /etc/crypttab, the encrypted swap header overwrites the unencrypted swap header. This will prevent the swap partition from being found at all future boots.

Problem 2: Race condition during boot

There is a race condition during boot between /etc/init.d/cryptdisks-early and /etc/init/cryptdisks.conf. Both will simultaneously try to activate all devices listed in crypttab. In the case of encrypted swap, the outcome of the race condition most of the time will be, that it doesn't work at all. Some sanity check fails causing writing of the encrytped swap header to be skipped in order to prevent potential data loss.

Fixing and working around the problems

The first problem can easily be fixed. The second can be worked around. In /etc/crypttab identify the swap line. It should look like this (except that the UUID will be different):

cryptswap1 UUID=f9a0f20c-fac4-408c-a8b9-47300216f727 /dev/urandom swap,cipher=aes-cbc-essiv:sha256

In my case this was the only line in /etc/crypttab. To fix the overwriting of the swap header, an offset must be added. Sources disagree on what exactly the correct value to use is, but using a too large value doesn't hurt. I got it working using an offset of 16.

Additionally I added noearly which causes /etc/init.d/cryptdisks-early to ignore this line and that way works around the race condition.

The resulting line looks like:

cryptswap1 UUID=f9a0f20c-fac4-408c-a8b9-47300216f727 /dev/urandom swap,cipher=aes-cbc-essiv:sha256,offset=16,noearly

This will prevent the unencrypted swap header from being overwritten again, but we still need to recreate it on the partition. At this step it is crucial to use the correct partition because using the wrong partition will cause data loss. I used fdisk -l to find the correct partition, which in my case is /dev/sda6.

Now use mkswap to rewrite the unencrypted swap header.

mkswap /dev/sda6 -U f9a0f20c-fac4-408c-a8b9-47300216f727

The UUID is the one the swap partition had before it was overwritten (which you can still see in /etc/crypttab). Once this is done a reboot is needed, and it should all work.

Verifying correct operation

I recommend rebooting three times to verify that it keeps working.

The error message the disk drive for /dev/mapper/cryptswap1 is not ready yet or not present remains visible briefly during boot. This appears not to be a problem though, as it does become ready before the boot process completes.

Log in and type cat /proc/swaps to see that swap is active. You should see a swap partition with the name /dev/dm-0 where dm indicates that it is indeed using the device mapper layer, which provides the encryption.

Related Question