[ltp] Suspend with crypted swap?

Christopher Singley linux-thinkpad@linux-thinkpad.org
Tue, 4 Sep 2007 14:45:21 -0500


--Boundary-00=_RXb3Gjw/ScaJbs+
Content-Type: text/plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On Monday 03 September 2007 02:01:10 U Kuehn wrote:
> Daniel Maier wrote:
> > On Sat, Sep 01, 2007 at 09:39:18PM +0200, Peter Jordan wrote:
> >> Hello,
> >>
> >> i have a ThinkPad R60 (debian lenny | kernel 2.6.22.6 | latest suspend
> >> patch) with a full-crypted (including swap) filesystem and now, i want
> >> to use suspend to ram/disk.
> >>
> >> My problem is that I do not know what to do?
> >>
> >> Is there anybody how can help me or knows a good howto?
> >
> > Suspend and resume with builtin swsusp do work out of the box if you
> > are using an initrd generated by initramfs-tools.
>
> C'mon guys, the original posted talked about encrypted swap. That is, on
> suspend, the kernel has the key to encrypt. But on resume, the kernel
> does not, so it cannot read the image (which is encrypted).
>
> @Peter: I don't know about the in-kernel suspend, but tux-on-ice
> (formely known as suspend2) does work that way, although at the price of
> using an initramfs. You might want to look at http://www.tuxonice.net
> and http://wiki.tuxonice.net/EncryptedSwapAndRoot (however, at the
> moment the wiki seems to be down, so the latter link is from my
> bookmarks...)
>
> Hope this helps
> Ulrich

Peter,

Although it's down, I think the tux-on-ice tutorial is the same as this one:
http://www.disciplina.net/howto/HOWTO-lvm_dm-crypt_suspend2.html
I found this very helpful in figuring out how to do what you want to do (it 
works for me) although my setup differs from his in several significant 
aspects (I don't use LVM, for one, and I skip all that rigmarole about klibc, 
which is hardly necessary for a system with plenty of RAM).

I created the encrypted containers with dm-crypt; I used the same password for 
both root & swap.  It's very important to use a persistent key for swap, 
not /dev/random or whatever as many tutorials would have you do.

You have to boot with an initramfs that contains dm-crypt, and a script to 
handle the initial booting.  To do this, I created the /etc/initramfs 
directory, and inside that created /etc/initramfs/filelist.txt 
and /etc/initramfs/initscript.sh (which I've attached to this email, 
including comments indicating the sources from which I stole certain code, so 
you can check those out yourself too).

Then I cd to /usr/src/linux, and added this kernel configuration:
General Setup > Initramfs source file(s): /etc/initramfs/filelist.txt

Then, if it exists, I rm /usr/src/linux/usr/initramfs_data.cpio.gz
Then I recompile the kernel and install it.

In my /boot/grub/grub.conf, I pass these arguments to the kernel:
kernel /vmlinuz root=/dev/hda6 swap=/dev/hda5 resume2=/dev/mapper/swap 
video=radeonfb:force_sleep=1

Of course, you'd need to change all this stuff for the version of the kernel & 
dm-crypt you're using, the actual partitions, and whatever name you've used 
for your swap.

This works well for me (both suspend & hibernate).  I also have an entry 
in /boot/grub/grub.conf with "noresume" instead of "resume2"; sometimes when 
you resume from suspend-to-disk you get these nasty error messages, and it's 
better to forget resuming & just boot into a clean environment.  This happens 
to me frequently enough that it's worth having its own entry in grub.conf, 
rather than dropping into a GRUB command line as necessary.

Best of luck,
cs

--Boundary-00=_RXb3Gjw/ScaJbs+
Content-Type: text/plain;
  charset="utf-8";
  name="filelist.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="filelist.txt"

###############################
# initramfs file list
# based on original by strerror
# q.v. http://www.disciplina.net/howto/filelist

# directory layout
dir /bin 755 0 0
dir /dev 755 0 0
dir /etc 755 0 0
dir /lib 755 0 0
dir /lib/modules 755 0 0 # needed kernel modules
dir /mnt 755 0 0 # create /mnt for usb drive
dir /proc 755 0 0
dir /root 755 0 0 # create the /root for the mount
dir /sbin 755 0 0
dir /sys 755 0 0
dir /usr 755 0 0
dir /usr/bin 755 0 0
dir /usr/lib 755 0 0
dir /usr/sbin 755 0 0
dir /var 755 0 0
dir /var/lock 755 0 0
dir /var/log 755 0 0

# required devices
# q.v. http://busybox.net/lists/buildroot/2006-October/000297.html
# "Your initramfs needs a /dev/console for the kernel to open stdin/stdout/stderr 
# for init before it can exec pid1, but you don't need that after init is 
# running.  I wouldn't bother to delete it either, switch_root should do that 
# for you if you remove the overmount."
nod /dev/console 644 0 0 c 5 1

# busybox takes care of our commands
file /bin/busybox /bin/busybox 755 0 0
# we need cryptsetup to create the mappings
file /bin/cryptsetup /bin/cryptsetup 755 0 0
# this is the binary (can be a script) that will be executed
file /init /etc/initramfs/initscript.sh 755 0 0

# kernel modules
file /lib/modules/usbcore.ko /lib/modules/2.6.22-suspend2/kernel/drivers/usb/core/usbcore.ko 755 0 0
file /lib/modules/uhci-hcd.ko /lib/modules/2.6.22-suspend2/kernel/drivers/usb/host/uhci-hcd.ko 755 0 0
file /lib/modules/usb-storage.ko /lib/modules/2.6.22-suspend2/kernel/drivers/usb/storage/usb-storage.ko 755 0 0
file /lib/modules/sg.ko /lib/modules/2.6.22-suspend2/kernel/drivers/scsi/sg.ko 755 0 0
file /lib/modules/sd_mod.ko /lib/modules/2.6.22-suspend2/kernel/drivers/scsi/sd_mod.ko 755 0 0
file /lib/modules/fat.ko /lib/modules/2.6.22-suspend2/kernel/fs/fat/fat.ko 755 0 0
file /lib/modules/vfat.ko /lib/modules/2.6.22-suspend2/kernel/fs/vfat/vfat.ko 755 0 0

# the libraries required by the binaries in the early userspace
# these can be worked out by using ldd against the various bins
# NOTE: this will almost definitely be different from your system
# you must work this out for yourself
# Sample output from `ldd busybox`:
#	linux-gate.so.1 =>  (0xb7fe4000)
#	libcrypt.so.1 => /lib/libcrypt.so.1 (0xb7fb2000)
#	libm.so.6 => /lib/libm.so.6 (0xb7f8d000)
#	libc.so.6 => /lib/libc.so.6 (0xb7e64000)
#	/lib/ld-linux.so.2 (0xb7fe5000)
file /lib/libcrypt-2.5.so /lib/libcrypt-2.5.so 755 0 0
file /lib/libm-2.5.so /lib/libm-2.5.so 755 0 0
file /lib/libc-2.5.so /lib/libc-2.5.so 755 0 0
file /lib/ld-linux.so.2 /lib/ld-linux.so.2 755 0 0
slink /lib/libcrypt.so.1 libcrypt-2.5.so 777 0 0
slink /lib/libm.so.6 libm-2.5.so 777 0 0
slink /lib/libc.so.6 libc-2.5.so 777 0 0

# symlinks to busybox
slink /bin/dd busybox 777 0 0
slink /bin/cp busybox 777 0 0
slink /bin/df busybox 777 0 0
slink /bin/ln busybox 777 0 0
slink /bin/ls busybox 777 0 0
slink /bin/mv busybox 777 0 0
slink /bin/ps busybox 777 0 0
slink /bin/rm busybox 777 0 0
slink /bin/sh busybox 777 0 0
slink /bin/vi busybox 777 0 0
slink /bin/ash busybox 777 0 0
slink /bin/cat busybox 777 0 0
slink /bin/pwd busybox 777 0 0
slink /bin/sed busybox 777 0 0
slink /bin/tar busybox 777 0 0
slink /bin/date busybox 777 0 0
slink /bin/echo busybox 777 0 0
slink /bin/grep busybox 777 0 0
slink /bin/gzip busybox 777 0 0
slink /bin/kill busybox 777 0 0
slink /bin/more busybox 777 0 0
slink /bin/ping busybox 777 0 0
slink /bin/sync busybox 777 0 0
slink /bin/true busybox 777 0 0
slink /bin/zcat busybox 777 0 0
slink /bin/chgrp busybox 777 0 0
slink /bin/chmod busybox 777 0 0
slink /bin/chown busybox 777 0 0
slink /bin/dmesg busybox 777 0 0
slink /bin/egrep busybox 777 0 0
slink /bin/false busybox 777 0 0
slink /bin/fgrep busybox 777 0 0
slink /bin/mkdir busybox 777 0 0
slink /bin/mknod busybox 777 0 0
slink /bin/mount busybox 777 0 0
slink /bin/pidof busybox 777 0 0
slink /bin/rmdir busybox 777 0 0
slink /bin/sleep busybox 777 0 0
slink /bin/touch busybox 777 0 0
slink /bin/uname busybox 777 0 0
slink /bin/gunzip busybox 777 0 0
slink /bin/hostname busybox 777 0 0
slink /bin/mktemp busybox 777 0 0
slink /bin/umount busybox 777 0 0
slink /bin/usleep busybox 777 0 0

slink /sbin/switch_root ../bin/busybox 777 0 0
slink /sbin/modprobe ../bin/busybox 777 0 0
slink /sbin/insmod ../bin/busybox 777 0 0
slink /sbin/rmmod ../bin/busybox 777 0 0
slink /sbin/mdev ../bin/busybox 777 0 0
slink /sbin/halt ../bin/busybox 777 0 0
slink /sbin/init ../bin/busybox 777 0 0
slink /sbin/klogd ../bin/busybox 777 0 0
slink /sbin/route ../bin/busybox 777 0 0
slink /sbin/poweroff ../bin/busybox 777 0 0
slink /sbin/swapoff ../bin/busybox 777 0 0
slink /sbin/syslogd ../bin/busybox 777 0 0
slink /sbin/ifconfig ../bin/busybox 777 0 0
slink /sbin/reboot ../bin/busybox 777 0 0
slink /sbin/pivot_root ../bin/busybox 777 0 0
slink /sbin/swapon ../bin/busybox 777 0 0

# more busybox commands, just in case - symlinks require no room ;)
slink /usr/bin/[ ../../bin/busybox 777 0 0
slink /usr/bin/du ../../bin/busybox 777 0 0
slink /usr/bin/id ../../bin/busybox 777 0 0
slink /usr/bin/tr ../../bin/busybox 777 0 0
slink /usr/bin/wc ../../bin/busybox 777 0 0
slink /usr/bin/cmp ../../bin/busybox 777 0 0
slink /usr/bin/cut ../../bin/busybox 777 0 0
slink /usr/bin/env ../../bin/busybox 777 0 0
slink /usr/bin/tee ../../bin/busybox 777 0 0
slink /usr/bin/tty ../../bin/busybox 777 0 0
slink /usr/bin/yes ../../bin/busybox 777 0 0
slink /usr/bin/chvt ../../bin/busybox 777 0 0
slink /usr/bin/find ../../bin/busybox 777 0 0
slink /usr/bin/expr ../../bin/busybox 777 0 0
slink /usr/bin/free ../../bin/busybox 777 0 0
slink /usr/bin/head ../../bin/busybox 777 0 0
slink /usr/bin/deallocvt ../../bin/busybox 777 0 0
slink /usr/bin/tail ../../bin/busybox 777 0 0
slink /usr/bin/sort ../../bin/busybox 777 0 0
slink /usr/bin/test ../../bin/busybox 777 0 0
slink /usr/bin/time ../../bin/busybox 777 0 0
slink /usr/bin/uniq ../../bin/busybox 777 0 0
slink /usr/bin/wget ../../bin/busybox 777 0 0
slink /usr/bin/dirname ../../bin/busybox 777 0 0
slink /usr/bin/killall ../../bin/busybox 777 0 0
slink /usr/bin/clear ../../bin/busybox 777 0 0
slink /usr/bin/bzcat ../../bin/busybox 777 0 0
slink /usr/bin/reset ../../bin/busybox 777 0 0
slink /usr/bin/unzip ../../bin/busybox 777 0 0
slink /usr/bin/which ../../bin/busybox 777 0 0
slink /usr/bin/xargs ../../bin/busybox 777 0 0
slink /usr/bin/strings ../../bin/busybox 777 0 0
slink /usr/bin/logger ../../bin/busybox 777 0 0
slink /usr/bin/openvt ../../bin/busybox 777 0 0
slink /usr/bin/hexdump ../../bin/busybox 777 0 0
slink /usr/bin/uptime ../../bin/busybox 777 0 0
slink /usr/bin/whoami ../../bin/busybox 777 0 0
slink /usr/bin/readlink ../../bin/busybox 777 0 0
slink /usr/bin/install ../../bin/busybox 777 0 0
slink /usr/bin/basename ../../bin/busybox 777 0 0
slink /usr/bin/bunzip2 ../../bin/busybox 777 0 0

slink /usr/sbin/chroot ../../bin/busybox 777 0 0

--Boundary-00=_RXb3Gjw/ScaJbs+
Content-Type: application/x-shellscript;
  name="initscript.sh"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="initscript.sh"

#!/bin/sh
# init script for use in initramfs, supporting encrypted root
# and suspend/resume from encrypted swap.
# based on the original by strerror
# q.v. http://www.disciplina.net/howto/initscript
# enhanced to use busybox mdev & switch_root
# can unlock either with P/W or keyfile on USB flash
PATH="/bin:/sbin:/usr/bin:/usr/sbin"

# USER CONFIGS
keypath=keys/thinkpad.key # relative to USB mountpoint

# FUNCTION DEFINITIONS
open(){
    mapname=$1
    eval device='$'$mapname
    if [ "$2" ]
    then
        keyfile="--key-file $2"
    else
        keyfile=""
    fi
    echo "initramfs: attaching $device as $mapname"
    cryptsetup $keyfile luksOpen $device $mapname
}

usbscan(){
    # ripped off almost verbatim from Puppy Linux
    # http://www.murga-linux.com/puppy/viewtopic.php?t=9865
    SLPCNT="0";
    USBSTORAGES="0";
    USBSTORAGESAVAILABLE="0";
    while true;do
        USBSTORAGES="`/bin/dmesg | grep -o "usb-storage: device found at.*" | wc -l | sed -e 's/ //g'`";
        USBSTORAGESAVAILABLE="`/bin/dmesg | grep -o "usb-storage: device scan complete" | wc -l | sed -e 's/ //g'`";
        if [ ${USBSTORAGES} -gt 0 ]; then
            if [ ${USBSTORAGES} -eq ${USBSTORAGESAVAILABLE} ]; then
                #echo "initramfs: USB device scan complete, found ${USBSTORAGESAVAILABLE} devices"
                break
            fi
        fi
        if [ $SLPCNT -gt 5 ]; then
            #echo "initramfs: USB device scan time-out $SLPCNT secs, found $USBSTORAGESAVAILABLE of $USBSTORAGES device(s)."
            break
        fi
        sleep 1
        SLPCNT=`expr $SLPCNT + 1`
    done
}

findkey(){
# We assume that any key will be located in the first partition of /dev/sd*
unset foundkey
for partition in /dev/sd*1
do
    if [ -e $partition ]
    then 
        mount -n $partition /mnt
        if [ -r /mnt/$keypath ]
        then
    #         echo "initramfs: crypto key found on USB device $partition"
            foundkey="/mnt/$keypath"
            break
        else
            umount /mnt
        fi
    fi
done
}

# MAIN PROGRAM

# Magic pseudo-filesystems
# In particular, to mount USB devices we need /dev; mdev relies
# on sysfs.  Also we'll want /proc to handle hotplug events.
mount -nt proc none /proc
mount -nt tmpfs mdev /dev
mkdir /dev/pts
mount -nt devpts devpts /dev/pts
mount -nt sysfs sysfs /sys

# Set up mdev to handle hotplug events & populate /dev
mdev -s
echo /sbin/mdev > /proc/sys/kernel/hotplug

# Save commandline to pass it to init
CMDLINE=`cat /proc/cmdline`
 
for param in $CMDLINE ; do
    case "$param" in
    root=*|swap=*|init=*)
        eval "$param"
        ;;
    esac
done

if [ -z "$root" ]; then
    echo "No root filesystem specified"
    echo "Please append a correct \"root=\" boot option"
    echo "Dropping you to a limited shell."
    echo "press CTRL-ALT-Del for reboot"
    exec /bin/sh
fi

# Load kernel modules for USB storage devices
# USB devices appear as virtual SCSI
for mod in usbcore uhci-hcd usb-storage sg sd_mod
do
    insmod /lib/modules/${mod}.ko
done

# Wait to see if USB devices come up
usbscan

# Try to find an encryption key on a USB flash drive.
findkey

# Open encrypted devices, using a cryptokey if one's been found
open swap $foundkey
open root $foundkey

# Mount our open dm-crypt before umounting /dev
echo "initramfs: mounting $root"
mount -n /dev/mapper/root /root -o ro

# Since we use the sysfs interface, cue suspend2 to do its thing
# before umounting /sys.
echo "initramfs: activating suspend2" 
echo 1 > /sys/power/suspend2/do_resume

# Unmount filesystems
echo -n "initramfs: umounting filesystems used by initramfs..."
if [ `awk '{if ($2 == "/mnt") print $1}' /proc/mounts` ]
then
    echo -n " mnt"
    umount /mnt
fi

for device in /dev/pts /dev /sys /proc
do
    echo -n " $device"
    umount $device
done
echo " ...done."

echo "initramfs: removing kernel modules used by initramfs"
for mod in sd_mod sg usb-storage uhci-hcd usbcore
do
    rmmod $mod
done

echo "initramfs: switching root to $root and handing over to init"
exec switch_root /root /sbin/init $init

--Boundary-00=_RXb3Gjw/ScaJbs+--