The update-grub2 script regenerates grub's configuration by calling the
/etc/grub.d/* scripts, it tries to determine the root= parameter for
each parameter. If an installation uses cryptsetup for the root
partition, this parameter needs to point to the dm-crypt mapping for
the opened device, which is usually opened through a script in the
initramfs asking the user for a key.
The "10_linux" script responsible fails to handle this situation
correctly for installations other than the one currently running which
use a different dm-crypt root partition.
The script simply points "root=" to the currently mounted root
partition, which may be wrong for other installation and render those
installations unbootable. Because update-grub2 regenerates all entries
on every launch, this even corrupts a configuration that was correctly
set up by the user.
To illustrate: I was running an installation that maps encrypted
/dev/sda1 to encrypted /dev/mapper/alpha, using this as its root
device. I also have another installation that maps encrypted /dev/sdb2
to /dev/mapper/bravo and uses it as root. Running update-grub2 on the
first installation will tell installation 2 to boot by mounting a disk
with /dev/mapper/alpha's UUID as root. This will always break
installation 2.
My proposed fix is to look at the initramfs of every installation
before creating its installation. When Debian uses a dm-crypt device as
root, it creates a script "conf/conf.d/cryptroot" in the initramfs.
This script contains all information necessary to retrieve the correct
root= parameter for the installation. Some string manipulation extracts
the device target, i.e. the name under which the decrypted device will
show up under /dev/mapper/.
Note that /dev/mapper/sdXX_crypt is a purely arbitrary name generated
by the installer and has nothing to do with /dev/sdXX. My proposed fix
thus also works if the encrypted device happens to be at a node other
than /dev/sdXX as long as the dm-crypt device is mounted by its UUID,
not by its node.
Patch follows:
--- /etc/grub.d/10_linux 2015-10-10 18:45:08.755900038 -0700
+++ ./10_linux_fix 2015-10-10 18:36:45.725983101 -0700
@@ -177,8 +177,18 @@
linux ${rel_dirname}/${basename}.efi.signed
root=${linux_root_device_thisversion} ro ${args}
EOF
else
+ cryptroot=$(zcat /boot/${initrd} | cpio -i --to-stdout
conf/conf.d/cryptroot | cut -d, -f1 -| cut -d= -f2)
+ if [ x"$cryptroot" != "" ]; then
+# printf "${basename}" "is using cryptsetup, overriding ROOT to
" "$newroot";
+
+ rootparam="/dev/mapper/"$cryptroot;
+ echo ''
+ else
+ rootparam="UUID="${linux_root_device_thisversion};
+ fi
+
sed "s/^/$submenu_indentation/" << EOF
- linux ${rel_dirname}/${basename}
root=${linux_root_device_thisversion} ro ${args}
+ linux ${rel_dirname}/${basename} root=$rootparam ro
${args}
EOF
fi
if test -n "${initrd}" ; then