Grub: like chainloading, works with EFI and full disk encryption

How to dual-boot multiple linux installs with EFI and full disk encryption

I have dual boot setup, with two linux installs both using full disk encryption, both booting with EFI. To get it working and enable easy switching between the OS-es, a few tweaks are needed as using EFI effectively prohibits grub chainloading another grub (it works in some linux distros I think), and using full disk encryption for me prevented grub to find the other install and add it to the boot menu.

The following solution uses the /boot setup of each system as it is, in effect when booting the primary OS one can select to load the grub configuration of the other OS. Precondition is that both OS-es use a somewhat similar version of grub.

System presumptions (replace with your configuration as needed):

Disk:

/dev/nvme0p1 EFI
/dev/nvme0p2 boot partition of primary OS
/dev/nvme0p3 root partition of primary OS
/dev/nvme0p4 boot partition of secondary OS
/dev/nvme0p5 root partition of primary OS

To get uuid-s of the disks or partitions issue

ls -l -a /dev/disk/by-uuid

To get it running do the following:

1. Install both OS-es, and boot into the primary OS. In case you can’t you can also run the commands from your secondary OS, boot into the primary OS afterwards and repeat the process there.

2. Add custom boot configuration on primary OS. Edit /etc/grub.d/40_custom to conatin the following (you just need to add the lines after “menuentry”):

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry 'Other - grub' --class gnu-linux --class gnu --class os $menuentry_id_option 'other-<uuid of boot partition of secondary OS>' {
  if [ x$feature_platform_search_hint = xy ]; then
    search --no-floppy --fs-uuid --set=root  <uuid of boot partition of secondary OS>
  else
    search --no-floppy --fs-uuid --set=root <uuid of boot partition of secondary OS>
  fi
  configfile /grub/grub.cfg
}

where you insert the uuid of your secondary boot partition in the appropriate places, and then re-generate bootloader configuration with

sudo update-grub

In case your bootloader keeps booting to the second OS by default, issue

sudo grub-install /dev/nvme0

from your primary OS.

At this point you can reboot and select “Other” in the boot menu, which will boot the other OS. However, the first time the other OS updates grub or any kernel images, it will overwrite this configuration.

3. To prevent the second OS from overwriting the bootloader boot the second OS and run

sudo debconf-show grub-pc

which will show the device / partition (“install_devices”) where grub will install the bootloader when it updates the config. In order to prevent this, clear that variable by setting it to empty string

echo "set grub-efi/install_devices" | sudo debconf-communicate

And this is it.

In the current setup, the bootloader is maintained from the primary OS, which loads the “grub.cfg” of the second install when selecting “Other” in the boot loader. The “grub.cfg” of the second install is maintained by the second OS. One can also add a reverse-other option in the second OS’s boot menu by repeating the point 2. on the second OS, with correct uuids, or add boot options for as many OS-es as desired.

I suspect that this kind of setup should, in principle (note: I haven’t throughly checked this), enable UEFI secure booting into both systems, with full disk encryption in both, therefore mitigating agains rootkits that infect the system’s boot images. As the grub configurations are kept separate, one encrypted system can also live without knowing anything about the other system, thus keeping both systems maximally isolated.