Ben Stienstra

Linux, Unix, network, radio and more...

User Tools

Site Tools


isolated_multi-boot

Isolated Multi-Boot

This is an investigation into pure UEFI isolated multi-boot. Multiple operating systems on an external drive with separate boot managers chainloaded from GRUB.

A few take-home points:

  • UEFI USB booting will look for /EFI/BOOT/BOOT<arch>.EFI, in this document BOOTX64.EFI. This is a PE32+ executable starting the GRUB2 bootloader.
  • Some UEFI Firmware does not work well, or not at all with multiple EFI System Partitions (ESPs) on the same disk, or even machine.
  • The UEFI firmware's bootmenu is local to the machine, new entries will not be available on other machines.
  • Booting an encrypted Arch Linux OS from another machine, it might not be possible to enter the pass phrase because the keyboard isn't recognised. For example, using a USB-keyboard on the one and PS/2 on the other machine. You can fix this with running mkinitcpio again so it detects the keyboard, or add the atkbd hid_generic ohci_pci usbhid modules to mkinitcpio.conf and generate a new initramfs.
  • Passphrase iteration is determined by cryptsetup depending on CPU power. Decrypting on other hardware might be slower (too slow, or faster). Lookup with cryptsetup luksDump.
  • If you are creating a new ESP partition using parted, then you also need the boot flag to set the correct partition type.
  • Use filesystem or partition UUIDs where possible. This persistent naming solves problems when names differ between machines.
  • Secure Erase an SSD over USB does not work properly!

Requirements / basic assumptions

  • External drive (SSD over USB with UAS) is /dev/sdX.
  • GPT Partitioning.
  • Linux host (using Fedora 26 here) with GRUB2.

Partitioning

In this section we will create the required ESP and the first partition for Arch Linux.

Secure erase the SSD

First, lets secure erase the SSD. If you trust the vendor then follow along. Else well, don't store anything in the clear before encrypting the device. Also, don't rely on this procedure if the SSD is USB attached.

  • Make sure the device is not frozen:
    # hdparm -I /dev/sdX
    ...
    Security: 
    	Master password revision code = 65534
    		supported
    	not	enabled
    	not	locked
    --->	not	frozen
    	not	expired: security count
    		supported: enhanced erase
    	2min for SECURITY ERASE UNIT. 2min for ENHANCED SECURITY ERASE UNIT.
    ...
  • Set password, any password will do, it will be reset to NULL after erasing.
    # hdparm --user-master u --security-set-pass randomDae6up6A /dev/sdX
    security_password: "randomDae6up6A"
    
    /dev/sda:
     Issuing SECURITY_SET_PASS command, password="randomDae6up6A", user=user, mode=high
  • Check that password is enabled:
    # hdparm -I /dev/sdX
    Security: 
    	Master password revision code = 65534
    		supported
    --->		enabled
  • Secure erase SSD:
    # time hdparm --user-master u --security-erase randomDae6up6A /dev/sdX
    security_password: "randomDae6up6A"
    
    /dev/sda:
     Issuing SECURITY_ERASE command, password="randomDae6up6A", user=user
  • Verify: check that master password is supported, and not enabled:
    # hdparm -I /dev/sdX
    Security: 
    	Master password revision code = 65534
    		supported
  • Verify: make sure old data is removed:
    partprobe /dev/sdX
    lsblk
    dd if=/dev/sdX bs=512 count=63 | hexdump -C

Partition table, ESP and OS-partition

Write a GUID Partition Table (GPT), ESP partition and first OS-partition to the disk.

  • Partiton the drive using the parted command:
    # Start at sector 65535, for correct alignment of my SSD.
    # 512MiB UEFI ESP
    # 32GiB partition for Arch Linux
    parted --script /dev/sdX              \
        mklabel gpt                       \
        unit mib                          \
        mkpart ESP fat32 65535s 1114095s  \
        toggle 1 boot                     \
        mkpart Arch 1179630s 68287470s
  • Format the ESP:
    mkfs.fat -F32 -n ESP /dev/sdX1

Install the GRUB2 boot loader

  • Mount the ESP:
    mount /dev/sdX1 /mnt
  • Install GRUB:
    grub2-install --removable --boot-directory=/mnt/boot --efi-directory=/mnt
  • The ESP should look like this:
    /mnt
    ├── boot
    │   └── grub2
    │       ├── fonts
    │       │   └── unicode.pf2
    │       ├── grubenv
    │       ├── locale
    │       │   ├── ast.mo
    <snip>
    │       │   └── zh_TW.mo
    │       └── x86_64-efi
    │           ├── acpi.mod
    │           ├── adler32.mod
    │           ├── affs.mod
    │           ├── afs.mod
    <snip>
    │           ├── zfscrypt.mod
    │           ├── zfsinfo.mod
    │           └── zfs.mod
    └── EFI
        └── BOOT
            └── BOOTX64.EFI
    

UEFI Shell, our first boot entry

To test the concept, lets create a simple first entry starting the UEFI Shell. If you want to program your own UEFI binaries see Rodericks Hello World example: http://www.rodsbooks.com/efi-programming/hello.html

  • Download the EFI Shell. https://github.com/tianocore/tianocore.github.io
    mkdir /mnt/EFI/UEFI-Shell
    cd /mnt/EFI/UEFI-Shell
    curl -OL https://github.com/tianocore/edk2/raw/master/ShellBinPkg/UefiShell/X64/Shell.efi
  • Lookup the ESP filesystems UUID, here's two ways:
    # lsblk -f /dev/sdX1
    NAME FSTYPE LABEL UUID                                 MOUNTPOINT
    sdX1 vfat   ESP   7A65-AEC7                            /mnt
    # grub2-probe -t fs_uuid -d /dev/sdX1
    7A65-AEC7
  • Edit /mnt/boot/grub2/grub.cfg, lookup UUID with lsblk -f or grub2-probe -t fs_uuid -d /dev/sda1
    timeout=5
    
    menuentry 'UEFI Shell' {
      insmod chain
      insmod search_fs_uuid
      search --set=root --fs-uuid 7A65-AEC7
      chainloader ($root)/EFI/UEFI-Shell/Shell.efi
    }
  • To test, unmount the ESP and boot the drive!

Arch linux, the second boot entry

Let's install our next OS onto the external drive. We're going to install a full encrypted Arch linux OS, even /boot will be encrypted! For more information read the Arch Linux installation guide

  • Since we're installing from Fedora, we'll need some tools:
    dnf install squashfs-tools
  • Download the Arch Linux LiveCD image:
    curl -O http://ftp.nluug.nl/os/Linux/distr/archlinux/iso/2017.07.01/arch/x86_64/airootfs.sfs
  • Extract the image
    unsquashfs airootfs.sfs
  • chroot into the install image:
    mount --bind squashfs-root squashfs-root
    mount -t proc none squashfs-root/proc
    mount -t sysfs none squashfs-root/sys
    mount -o bind /dev squashfs-root/dev
    mount -o bind /dev/pts squashfs-root/dev/pts  ## important for pacman (signature check)
    cp -L /etc/resolv.conf squashfs-root/etc      ## this is needed for networking within the chroot
    
    modprobe efivarfs
    mount -t efivarfs efivarfs squashfs-root/sys/firmware/efi/efivars
    
    chroot squashfs-root bash
  • Initialize pacman:
    pacman-key --init
    pacman-key --populate archlinux
  • Select a mirror in /etc/pacman.d/mirrorlist and refresh and update the packages
    pacman -Syyu
  • Setup encryption:
    cryptsetup luksFormat /dev/sdX2
    cryptsetup open /dev/sdX2 cryptroot
  • Create the filesystem:
    mkfs.ext4 /dev/mapper/cryptroot
  • Mount the new filesystem:
    mount /dev/mapper/cryptroot /mnt
  • Install Arch linux onto the new filesystem:
    pacstrap /mnt base
  • Create a new fstab file:
    $ blkid /dev/mapper/cryptroot
    /dev/mapper/cryptroot: UUID="3ca1ba61-388f-452c-886b-a36d1a88d785" TYPE="ext4"
    
    vi /mnt/etc/fstab
    UUID=3ca1ba61-388f-452c-886b-a36d1a88d785	/         	ext4      	defaults	0 1
  • chroot into the new Arch Linux install:
    arch-chroot /mnt
  • Configure the time zone:
    ln -sf /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime
  • Set the Hardware Clock from the System Clock, and update the timestamps in /etc/adjtime.
    hwclock --systohc
  • Select locales in /etc/locale.gen and generate the locales:
    locale-gen
    localectl set-locale LANG="en_US.UTF-8"
  • Configure the hostname in /etc/hostname and /etc/hosts
  • Change the root password and create new users:
    passwd root
    useradd ...
  • Add the encrypt to hook in /etc/mkinitcpio.conf:
    HOOKS="base udev autodetect modconf keyboard keymap block encrypt filesystems fsck"
  • Generate a new initramfs:
    mkinitcpio -p linux
  • Install GRUB:
    pacman -S grub
  • Configure GRUB:
    # blkid /dev/sda2
    /dev/sda2: UUID="628f049e-c5ea-4ef4-8876-50392a5ca1f6" TYPE="crypto_LUKS" PARTLABEL="Arch" PARTUUID="096a076a-e3fd-474e-864d-09aa78fad601"
    
    vi /etc/default/grub
    GRUB_ENABLE_CRYPTODISK=y
    GRUB_CMDLINE_LINUX="cryptdevice=UUID=628f049e-c5ea-4ef4-8876-50392a5ca1f6:cryptroot"
    
    grub-mkconfig -o /boot/grub/grub.cfg
  • If you want to use the Gnome desktop, install the following packages and services:
    pacman -S gnome gnome-extra gdm
    systemctl enable gdm
    systemctl enable NetworkManager
  • Exit the chroots:
    exit    # arch-chroot
    exit    # livecd chroot
  • Mount the ESP and add the new Arch Linux install the boot menu. Note: modify the UUIDs:
    mount /dev/sdX1 /mnt
    vi /mnt/boot/grub2/grub.cfg 
    
    menuentry 'Arch Linux' {
      insmod gzio
      insmod part_gpt
      insmod cryptodisk
      insmod luks
      insmod gcry_rijndael
      insmod gcry_sha256
      insmod ext2
      cryptomount -u 628f049ec5ea4ef4887650392a5ca1f6
      set root='cryptouuid/628f049ec5ea4ef4887650392a5ca1f6'
      configfile /boot/grub/grub.cfg
    }
  • Unmount the filesystems mounted from the external drive and test your new Arch Linux install!

Debian Stretch (9)

  • Add a new 32GiB partition:
    parted /dev/sdX
    init mib
    mkpart Debian 76807020s 143914861s
    quit
    
    partprobe /dev/sdX
  • Setup encryption:
    cryptsetup luksFormat /dev/sdX4
    
    cryptsetup open /dev/sdX4 cryptroot
  • Create an ext4 filesystem:
    mkfs.ext4 /dev/mapper/cryptroot
  • Mount the filesystem:
    mkdir /mnt/debianroot
    mount /dev/mapper/cryptroot /mnt/debianroot
    mkdir -p /mnt/debianroot/boot/efi
  • Install debootstrap:
    dnf install debootstrap
  • Install Debian:
    # Path is needed when installing from Fedora...
    PATH="$PATH:/bin:/sbin:/usr/sbin" debootstrap --arch amd64 stretch /mnt/debianroot http://ftp.nl.debian.org/debian
    ..
    ..
    I: Base system installed successfully.
  • Enter the chroot:
    mount -t proc none /mnt/debianroot/proc
    mount -t sysfs none /mnt/debianroot/sys
    mount -o bind /dev /mnt/debianroot/dev
    mount -o bind /dev/pts /mnt/debianroot/dev/pts  ## important for pacman (for signature check)
    cp -L /etc/resolv.conf /mnt/debianroot/etc  ## this is needed to use networking within the chroot
    
    modprobe efivarfs
    mount -t efivarfs efivarfs /mnt/debianroot/sys/firmware/efi/efivars
    
    XTERM=xterm-color LANG=C.UTF-8 PATH="$PATH:/bin:/sbin:/usr/sbin" chroot /mnt/debianroot bash
  • Edit the fstab:
    lsblk -f /dev/sdX4 # outside chroot)
    
    vi /etc/fstab
    UUID=cbd33fa1-9d89-4308-a24f-b3128671874a /     ext4    defaults        0 1
  • Configure Debian:
    apt install locales
    dpkg-reconfigure locales tzdata
    
    # Install kernel, efibootmgr, grub
    apt install linux-image-amd64 efibootmgr grub-efi-amd64 cryptsetup initramfs-tools
    # dont install the grub bootloader yet...
    
    vi /etc/crypttab # lookup UUID with blkid /dev/sdX4
    cryptroot UUID=<UUID> none luks
    
    Modify "CRYPTSETUP=y" in /etc/cryptsetup-initramfs/conf-hook
    
    update-initramfs -ut
    
    vi /etc/default/grub
    GRUB_ENABLE_CRYPTODISK=y
    
    grub-mkconfig -o /boot/grub/grub.cfg
    
    
    set hostname in /etc/hostname
    
    passwd root
    useradd...
    
    tasksel install desktop
    tasksel install laptop
    
    exit
    umount -R /mnt/debianroot
  • Add Debian to grub:
    menuentry 'Debian' {
      insmod gzio
      insmod part_gpt
      insmod cryptodisk
      insmod luks
      insmod gcry_rijndael
      insmod gcry_sha256
      insmod ext2
      cryptomount -u 63a124c1f7744493a20ab5a45bc5e06f
      set root='cryptouuid/63a124c1f7744493a20ab5a45bc5e06f'
      configfile /boot/grub/grub.cfg
    }
    

Tais (live system ISO)

This is an example on how to boot a live ISO.

  • Create a 4GiB Tails partition that holds the ISO using gdisk or parted.
    parted /dev/sdX
    mkpart Tails fat32 68353005s 76741485s
    quit
    
    partprobe /dev/sdX
  • Format the filesystem:
    mkfs.fat -F32 -n TAILS /dev/sdX3
  • Mount the filesystem:
    mount /dev/sdX3 /mnt
  • Copy the Tails ISO to the new filesystem:
    cp tails-amd64-3.0.1.iso /mnt/
    umount /mnt
  • Add Tails to GRUB2, first lookup the filesytem UUID:
    # blkid /dev/sdX3
    /dev/sdb3: LABEL="TAILS" UUID="CD8C-F556" TYPE="vfat" PARTLABEL="Tails" PARTUUID="78a43e07-3453-4be8-bacb-6793b5e74737"
  • Add Tails to GRUB:
    mount /dev/sdX1 /mnt
    
    vi /mnt/boot/grub2/grub.cfg  # Change the UUID!
    menuentry "Tails 3.0.1" {
      insmod all_video
      insmod search_fs_uuid
      search --set=root --fs-uuid CD8C-F556
      set isofile="/tails-amd64-3.0.1.iso"
      loopback loop ($root)$isofile
      linux (loop)/live/vmlinuz boot=live config noswap nopersistent iso-scan/filename=$isofile nomodeset
      initrd (loop)/live/initrd.img
    }
    umount /mnt
isolated_multi-boot.txt · Last modified: 2017/08/10 12:06 by admin