Original Author
Benjamin Smee - strerror@disciplina.net
Version
0.99 NOTE - The most up to date version of this HOWTO can be found at http://www.disciplina.net/howto/HOWTO-lvm_dm-crypt_suspend2.html
Purpose
This howto sprung out of frustration from trying to setup my laptop with suspend2 but using lvm and encryption. There are a lot of howtos that deal with part of what I will be covering, but I found them all lacking in one way or another. Typically it seems people who use lvm or who use encryption over lvm seem to have simple raw partitions, or at the most they have one big lvm partition. While there are some howto's out there that explain how to do this, what they don't explain is how you would do it with multiple partitions and in particular how that would then work with something like suspend2.
Background
The ideal situation for disk management, in my opinion, has the following features:
- Each partition can be resized, up or down, on-the-fly
- Each filesystem on top of the partitions can support on-the-fly resizing
- Each partition should be able to be encrypted
The end result of this howto is that you will have this configuration, provided that you use a filesystem that supports on the fly resizing. As of writing filesystems that support this functionality are reiserfs (you do need to unmount reiserfs for SHRINKING), XFS and JFS. With that as our ideal situation how does suspend2 fit in? Suspend2 is a set of kernel patches that allows you to successfully suspend to disk and resume. This is very useful for a number of reasons.
Firstly, at the time of writing, suspend to ram (the other main acpi suspending option) is not very stable on most platforms. Secondly, suspend to ram will chew up a lot more power then if you were able to power your laptop down completely. Of course there are other benefits like being able to swap out batteries etc that are applicable here. In my opinion the best way to manage the actual suspending to disk operation is via series of scripts called "hibernate", which, along with suspend2 itself, are both actively and excellently maintained.
Suspend2 / hibernate works by writing out an image of the memory to a file / swap and then, upon reboot, allowing us to resume by loading that image back into memory. It is the functioning of suspend2 along with lvm, dm-crypt and multiple partitions that we are going to obtain.
Warning
As is customary I should put a warning in at this point. The rest of this HOWTO involves some low level, highly techinical procedures that can delete parts, or even all of your harddrive. You should NOT procede without making a backup and having some time on your hands and a supply of caffeine
Requirements
While the end point is probably able to be achieved in a variety of ways (eg using older kernels like 2.4) for the purposes of this HOWTO the following are required:
kernel >2.6.11.x
- dm-crypt support
- initramfs support
- suspend2 patchset that applies cleanly to the kernel
- swap writer must be enabled, file writer is NOT used in this HOWTO
- the hibernate scripts that go along with the suspend2 patchset cryptsetup
- lvm2 device-mapper busybox klibc
Steps
This HOWTO is aimed at people who already have a working system up and running and would like to start off by encrypting just swap. Once we have that working I will show how to migrate each of your partitions over to fully encrypted partitions. If you are installing something from scratch then most of this becomes even easier, especially if you install from a decent livecd which has all the tools required.
Firstly get the latest kernel version and ensure that there is a suspend2 patchset that will apply cleanly to it (http://www.suspend2.net/downloads/all/). Once you have obtained and unarchived the source into a directory (gentoo users : get brix's suspend2-sources from his overlay - http://dev.gentoo.org/~brix) then cd into the tree and apply the suspend2 patchset as follows:
cd /usr/src/linux patch -p1 < /tmp/suspend2/suspend.patch
Once that has applied you need to ensure that your kernel has the following things built in:
- Device Drivers
- Block Devices
CONFIG_BLOCK_DEV_RAM [*]
BLOCK_DEV_INITRD [*]
- Multi-Device Support
CONFIG_MD [*]
CONFIG_BLK_DEV_DM [*]
CONFIG_DM_CRYPT [*]
- Block Devices
Finally you will need to enable whatever ciphers you want to use in Cryptographic Options. Generally speaking I just compile in support for all.
Next install cryptsetup - most distributions now have this in their packages but if not you can get it http://www.saout.de/misc/dm-crypt/. (gentoo users: emerge cryptsetup). You will also need to install lvm2, device-mapper, busybox and klibc packages which again are almost definitely going to be provided by your distributions package managers (gentoo users: `echo "dev-libs/klibc ~x86" >> /etc/portage/package.keywords ; emerge lvm2 device-mapper busybox ; emerge -f klibc` )
It is probably best at this point that you reboot with your new kernel. Once you have done that then we will setup our encrypted swap. Lets take the following partition table as a reasonable starting point:
/dev/hda1 |
boot |
/dev/hda2 |
root |
/dev/vg0/home |
home |
/dev/vg0/opt |
opt |
/dev/vg0/swap |
swap |
/dev/vg0/tmp |
tmp |
/dev/vg0/usr |
usr |
/dev/vg0/var |
var |
In this scenario /dev/vg0/swap is our swap partition. As it is probably currently mounted we should do: swapoff /dev/vg0/swap. Now we can create our encrypted swap device with the following command: cryptsetup create crypt-swap /dev/mapper/vg0-swap It is important to note that you should make the passphrase you use for this as hard as you can, ideally in fact you can pass cryptsetup a file (perhaps a chunk of /dev/random) that will act as your key. In advanced configurations, you could even have it so that you kept the key on a usb flash or similar and in really advanced configurations you can boot off the usb device where it will act as our initramfs, but we are getting ahead of ourselves
You might need to check what name device mapper has given your swap, but for me at any rate it has the above name. If your /dev/mapper is very different then the way to find out what your swap is, would be to do: ls -la /dev/vg0/swap and then comparing minor and major nodes to those of the files listed in /dev/mapper.
Once you have successfully created the dm-crypt mapping then we need to ensure that it can be used as a swap partition by: mkswap /dev/mapper/crypt-swap and finally we need to tell our system to use it on boot via editting /etc/fstab and putting in a line like this: /dev/mapper/crypt-swap none swap sw 0 0
You can test this now by typing: swapon /dev/mapper/crypt-swap and to confirm it's working: swapon -s should return something like:
Filename Type Size Used Priority /dev/mapper/crypt-swap partition 1048568 0 -1
So now we have a encrypted mount point we have to ensure that when we reboot it will be automatically mounted, but we have a complication and that is suspend2.
In many of the HOWTOs I have read about this they often suggest using something like /dev/urandom as the key for encrypted swap, this is because in normal circumstances we don't care about the contents of swap as it is not persistant between boots and good cryptography says that if we can change it each time then we should. Unfortunately we don't have that luxury as we require the swap to be accessible in the same form as when we went into hibernation, this means that we must use a static key, hence setting it up as we have.
The other problem with many of these howto's is that they never deal with making initrd's or initramfs's because they are comparatively hard to do and there is not necessarily and hard and fast rules to how to write things like /linuxrc or /init. The final problem I had when working this all out myself was using initramfs. Initramfs is meant to be the sucessor to initrd's, and so I naturally thought I would use that instead of initrd's. Despite reading the documentation (/usr/src/linux/Documentation/early-userspace/README) I still wasn't any clearer as to how to actually IMPLEMENT initramfs. I saw that you use one like an old initrd, ie by passing a initrd= line in your boot loader, but I was very unsure as to how to use the inbuilt initramfs, which sounded a lot more elegant.
Thanks to brix and a little bit of experimentation I finally worked that out and that is what I will use for our solution. What we need to do with our initramfs is clear. We will boot into this "Early userspace" and it will provide for us a place that we can mount out partitions AND create our crypt mappings ready to pass this information back to the OS when we continue with the init process. In order to do this we need to create a script that will do all of these functions for us, this will be our /init.
In addition to the script we need to provide the environment that the script will require to work in, ie the tools that the script will call, we will do this with a file list. In effect what we will do is create a cpio listing (/usr/src/linux/scripts/gen_initramfs_list.sh can be used to create one) of all the files in the early userspace environment. We will then put the full path to the file list in the CONFIG_INITRAMFS_SOURCE option in our kernel config (under device drivers -> block devices) and when we next make the kernel it will go off and fetch those files and put them into a cpio archive that it will compress and append to the kernel.
A sample /init script can be found http://www.disciplina.net/howto/initscript and a sample file list can be found http://www.disciplina.net/howto/filelist. Those two files should be fairly easy to understand in light of the above information, there is some extra stuff in the filelist relating to fbsplash, but it is commented and can be left out if you are not using it. As you can see by the filelist there are a few things there that I have not mentioned yet, one is busybox the other is klibc and the last is the setresume2 program. One of the problems with my original versions of the init script was that when you go to setup up the resume2= parameter you had to manually work out what the minor number was and link it to /dev/dm-$(minor number). This ofcourse changed whenever you added / subtracted to the logical volumes and could potentially change per boot depending on how you setup your dm-mapper. What the setresume2 program does is take the userland NAME of the interface (eg crypt-home) and turn that into an appropriate number to pass to resume2= which is what suspend2 needs to work. The setresume2 source can be found at http://www.disciplina.net/howto/setresume2.c.
Busybox is designed to be a drop in replacement for most unix utils, and it will function like the utils it is called as (ie argv[0]). This makes it perfect for us as we can have one cp of busybox in our initramfs and then use a series of symlinks (as per the filelist example) to get all the functionality we require. This is particularly important in light of the fact that there appears to be some bugs with initramfs if you use a LARGE initramfs (in fact this cost me about 3 hours of debugging to work out as it is not obvious why it is failling) and it will break in a non obvious manner. Busybox allows us to keep the size of the initramfs to an absolute minimum.
Klibc is a slightly more complicated beast and I must confess to have not spent too much time with it, suffice it to say that I don't recommend you install it, but rather grab the tarball and unpack it. You must then create a symlink pointing to your kernel source, eg:
ln -s /usr/src/linux /tmp/klibc-1.0.8/linux
Once you cd into /tmp/klibc-1.0.8, you can now type make and it should compile. Once that is finished grab the file /tmp/klibc-1.0.8/utils/static/run-init and that is the file you reference in the filelist where noted in the example filelist. The final step of making your filelist is ensuring that all the libraries required by each of the binaries (another reason why just using busybox is a good idea) is in the early userspace. This can be done by running ldd against all of the binaries like "ldd /bin/cryptsetup". You can ignore the "linux-gate.so.1" entry but the rest must always be provided. In our case it simply means noting down the path to the library and any relevant symlinks to include in our filelist.
The initscript is fairly self explanatory and as long as you ensure that you get the right minor number for the symlink you should be fine. At this point we can now make our new kernel and it should grab the filelist, and append the initramfs to itself. When you reboot you do not need to pass initrd= to the bootloader at all as it is inbuilt, so a grub entry for this kernel would simply look like:
title example root (hd0,1)
kernel (hd0,0)/vmlinuz-test root=/dev/hda2
or with an fbsplash kernel, make that line:
kernel (hd0,0)/vmlinuz-test root=/dev/hda2 video=vesafb:ywrap,nomtrr,1280x768-32@60 splash=silent,fadein,theme:emergence CONSOLE=/dev/tty1
Upon reboot you should see the initramfs being loaded (because of the echo out lines in the script) and it should stop and ask you for the password to mount the encrypted swap. At this point it should continue booting up and you will now be using encrypted swap, whats more because of the initramfs, when you configure and run hibernate it will now work and resume flawlessly
Converting the rest of your volumes
As a final note I will briefly describe how to go about converting the rest of the system from lvm to encrypted lvm. What needs to be done is that for each current lvm partition, we need to create another one the same size, create a crypt mapping, create the filesystem and copy the files over. Then we modify the /etc/fstab to reflect these changes. In practise the following will work using the above /dev/vg0/home partition assuming it was 1gb in size. # lvcreate -L1G -n home_tmp vg0 # cryptsetup create crypt-home /dev/mapper/vg0-home_tmp # mkreiserfs /dev/mapper/crypt-home we then replace the line in /etc/fstab: /dev/vg0/home /home reiserfs defaults 0 0 with /dev/mapper/crypt-home /home reiserfs defaults 0 0
Once you have the new home partition mounted via the dm-crypt interface, (ie mount /dev/mapper/crypt-home /mnt/hometmp), then you can copy the contents of /home to /mnt/hometmp via a command something like: find /home -xdev | cpio -pvmd /mnt/hometmp then after rebooting and testing that it is ok, you can delete the old home partition, rename the home_tmp to home and you are done.
Finally I will give a quick example of how we can take advantage of our new setup. Here is how to expand /home on the fly without having to reboot or even unmount /home while keeping it encrypted: # lvextend +L1G /dev/vg0/home # resize_reiserfs /dev/mapper/crypt-home
.. and now /home is 2gb!
Note that we have to extend the underlying lvm volume, but our filesystem sits on the dm-crypt mapping so that is where we must resize the fs.
Final Thoughts
It is natural to want to put all of your partitions on lvm, however, you should think through the requirements thoroughly before doing so. When you think about it in order to boot your bootloader will need to find a kernel, and if your kernel is on a LVM partition then it won't be able to find it (AFAIK neither grub nor lilo support LVM). What this means then is that at least your /boot will generally have to be on a raw partition, if you really do want a completely lvm system then you will have to boot off something else. The most obvious canditate for that would be something like a usb flash drive, but ofcourse there are all kinds of caveats and inconveniences doing this, you must weight up the pro's and con's of these decisions based on your own criteria.
Links
(in no particular order) http://forums.gentoo.org/viewtopic-t-297990-highlight-.html http://gentoo-wiki.com/SECURITY_Encrypting_Root_Filesystem_with_DM-Crypt http://forums.gentoo.org/viewtopic.php?t=108162&highlight=encrypt http://forums.gentoo.org/viewtopic-t-298001-highlight-lvm+swsusp2.html http://www.saout.de/misc/dm-crypt/




