Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save xenophonf/2e2d1a1550b0fb8dae98 to your computer and use it in GitHub Desktop.
Save xenophonf/2e2d1a1550b0fb8dae98 to your computer and use it in GitHub Desktop.
Dual-boot Mac OS X (FileVault2) and Ubuntu (OpenZFS/LUKS)

Dual-boot Mac OS X (FileVault2) and Ubuntu (OpenZFS/LUKS)

This procedure results in a computer that runs both Mac OS X and Ubuntu in a dual-boot configuration, each operating system using full (whole) disk encryption, and with the Ubuntu root file system stored on a ZFS pool encrypted using LUKS. The specific hardware and software versions used to document this procedure are:

  • MacBookPro8,2

  • an external storage device of some kind with a capacity of at least 8 GiB

  • Mac OS X 10.7 (upgraded in place to 10.11)

  • Ubuntu 14.04.3

Hardware Preparation

The following procedure assumes that the target hard drive, /dev/sda, is blank.

Connect the Ethernet NIC to the LAN, since WiFi does not work in Ubuntu until after installing the bcmwl-kernel-source package.

Connect an empty USB flash drive or other form of external storage, /dev/sdb. Ubuntu will be installed on this device temporarily, as the installer does not support ZFS pools.

Mac OS X Installation

Apple delivers firmware updates solely through the Mac App Store, making a dual-boot configuration necessary. To begin installing Mac OS X using Internet Recovery, power on the computer while pressing Command-Option-R. NOTE: The default version of Mac OS X depends on what Apple originally shipped with the hardware, e.g., 10.7 for MacBookPro8,2.

Use Disk Utility to create two partitions, a 40-GB partition formatted as Mac OS Extended (Journaled) named Macintosh HD and the remaining space formatted as Free Space. This process uses GPT by default.

Perform a default installation of Mac OS X.

Update Mac OS X after completing the installation, and enable FileVault disk encryption after updating Mac OS X. This happens automatically as part of the upgrade to Mac OS X 10.11 (El Capitan).

Ubuntu Installation

To begin installing Ubuntu from CD/DVD, power on the computer while pressing Option. From the Startup Manager, use the arrow keys to select the optical disc icon labeled Windows, then press Enter. This performs a legacy boot of the Ubuntu installer. (An EFI boot may be possible but has not been tested.) When prompted, choose Try Ubuntu to start the live environment. From the live environment, run the icon on the desktop labeled Install Ubuntu 14.04.3 LTS, and perform a default installation of Ubuntu to the external storage device with the following exceptions:

  • Download updates while installing.

  • Install third-party software. This must be enabled now in order to install non-default device drivers later in this process.

  • When prompted to select an installation type, choose Something else.

  • Set the device for boot loader installation to the external storage device (e.g., /dev/sdb). Skipping this step might interfere with booting Mac OS X.

  • Create a single primary partition on the external storage device, formatted as Ext4 journaling file system and mounted at /.

  • Ignore warnings about a missing reserved BIOS boot area or a missing swap partition.

  • When the installer finishes, return to the live environment and open the Terminal app. The remaining steps of the Ubuntu installation process must be completed using the command line.

ZFS Pool Creation

Install OpenZFS in the live environment by running the following commands:

sudo apt-add-repository --yes ppa:zfs-native/stable
sudo apt-get update
sudo apt-get --yes install ubuntu-zfs
sudo modprobe zfs

Add two partitions, one for the boot volume (contains the kernel and initrd), and the other for the LUKS container that will host the ZFS pool:

sudo gdisk /dev/sda <<EOF
n


+1G

c
4
boot0
n



8e00
c
5
root0
w
y
EOF

Force the kernel to re-read the partition table if necessary:

sudo partprobe

Set up the ZFS pool's encrypted backing volume (this will prompt for a password twice):

sudo cryptsetup --verbose --hash sha512 --cipher aes-xts-plain64 --verify-passphrase --batch-mode luksFormat /dev/disk/by-partlabel/root0

Attach the encrypted volume (use the password specified in the previous step):

sudo ed /etc/crypttab<<EOF
a
cryptroot0 /dev/disk/by-partlabel/root0 none luks
.
w
q
EOF
sudo cryptdisks_start cryptroot0

(The cryptdisks_start command might break local echo in the terminal. To fix this problem, either open a new tab or window, or enter the reset command.)

Zero the encrypted volume, otherwise decryption errors that would naturally result from reading uninitialized sectors will be treated as hard storage errors by ZFS:

sudo dd if=/dev/zero of=/dev/mapper/cryptroot0 bs=16777216 &
pid=$!
while sudo kill -USR1 ${pid} >/dev/null 2>&1; do
  sleep 1
  clear
done

Create the ZFS pool.

sudo zpool create -f -O mountpoint=none -o altroot=/mnt -o ashift=12 rpool /dev/mapper/cryptroot0

ZFS Root Installation

Create the root file system:

sudo zfs create -o mountpoint=none rpool/ROOT
sudo zfs create -o mountpoint=/ rpool/ROOT/ubuntu
sudo zpool set bootfs=rpool/ROOT/ubuntu rpool

Format and mount the Linux boot volume, and mount the EFI System Partition:

sudo mke2fs -F /dev/disk/by-partlabel/boot0
sudo mkdir /mnt/boot
sudo mount /dev/disk/by-partlabel/boot0 /mnt/boot
sudo mkdir /mnt/boot/efi
sudo mount -t vfat /dev/disk/by-partlabel/EFI\\x20System\\x20Partition /mnt/boot/efi

Mount the Ubuntu installation on the external storage device (e.g., /dev/sdb1) and copy it to the ZFS root file system:

sudo mkdir /target
sudo mount /dev/sdb1 /target
(cd /target && sudo find . -depth -print | sudo cpio -pdmv /mnt)

Snapshot the ZFS root file system, as this simplifies the process of reverting to the original Ubuntu installation in case of any problems:

sudo zfs snapshot rpool/ROOT/ubuntu@`date -u +%Y-%m-%dT%H:%M:%SZ`

Configure the swap volume:

sudo zfs create -V 16G rpool/swap
sudo ed /etc/crypttab<<EOF
a
cryptswap0 /dev/zvol/rpool/swap /dev/urandom swap,cipher=aes-xts-plain64,hash=sha512
.
w
q
EOF

Update the lists of encrypted volumes and file system mount points:

sudo cp /etc/crypttab /mnt/etc/crypttab
sudo rm /mnt/etc/fstab
sudo ed <<EOF
a
/dev/disk/by-partlabel/boot0 /boot ext2 defaults,nosuid,nodev,noexec 0 0
/dev/disk/by-partlabel/EFI\\x20System\\x20Partition /boot/efi vfat ro,fmask=133,noauto 0 0
/dev/mapper/cryptswap0 none swap defaults 0 0
.
w /mnt/etc/fstab
q
EOF

APT requires that the /dev, /dev/pts, /proc, and /sys pseudo-file systems be mounted:

sudo mount --bind /dev /mnt/dev
sudo mount --bind /dev/pts /mnt/dev/pts
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys

Temporarily enable name resolution within the ZFS root:

sudo cp /run/resolvconf/resolv.conf /mnt/run/resolvconf/resolv.conf

At a minimum the ubuntu-zfs, zfs-initramdisk, cryptsetup, and refind packages must be added to---and the grub-pc and intel-microcode packages removed from---the Ubuntu installation in order for the dual-boot process to function:

sudo chroot /mnt add-apt-repository --yes ppa:zfs-native/stable
sudo chroot /mnt add-apt-repository --yes ppa:rodsmith/refind
sudo chroot /mnt apt-get update
sudo chroot /mnt apt-get --yes purge grub-pc intel-microcode
sudo chroot /mnt apt-get --yes install ubuntu-zfs zfs-initramfs
sudo chroot /mnt apt-get --yes install cryptsetup

When prompted install rEFInd to the ESP.

sudo modprobe efivars
sudo chroot /mnt apt-get --yes install refind

Configure rEFInd:

sudo ed <<'EOF'
a
"Boot with standard options" "boot=zfs"
.
w /mnt/boot/refind_linux.conf
q
EOF

Install a version of the initramfs-tools hook script cryptroot modified to support ZFS pools, and update the initial RAM disk image:

wget https://raw.githubusercontent.com/irtnog/helper-scripts/master/ubuntu-15.04/initramfs-tools/hooks/cryptroot
chmod a+x cryptroot
sudo cp cryptroot /mnt/etc/initramfs-tools/hooks
sudo chroot /mnt dpkg-reconfigure cryptsetup

(Note that the intel-microcode package causes the update-initramfs command to fail silently.)

Use the ubuntu-drivers command to identify which non-default drivers must be added to the installation in order for the computer to operate normally:

sudo ubuntu-drivers devices
sudo chroot /mnt apt-get --yes install bcmwl-kernel-source

(Note that these drivers can only be found in the non-main repositories.)

Cleanup

Restore the original DNS resolver configuration, which should re-create the symbolic link from /etc/resolv.conf to ../run/resolvconf/resolv.conf:

sudo dpkg-reconfigure --default-priority resolvconf

Unmount all file systems except for the ZFS pool:

sudo umount /target
sudo umount /mnt/sys
sudo umount /mnt/proc
sudo umount /mnt/dev/pts
sudo umount /mnt/dev
sudo umount /mnt/boot/efi
sudo umount /mnt/boot

Create another snapshot of the ZFS root file system, again to make reverting easier:

sudo zfs snapshot rpool/ROOT/ubuntu@`date -u +%Y-%m-%dT%H:%M:%SZ`

Unmount the ZFS pool:

sudo zpool export rpool

Shut down (or reboot) the Ubuntu live environment.

rEFInd Activation

rEFInd must be blessed before it will replace the Apple Startup Manager; refer to "Installing rEFInd Manually Using Mac OS X" for the particulars (particularly step 8). If the computer was upgraded to Mac OS X 10.11 (El Capitan), make certain to temporarily disable System Integrity Protection (SIP) as part of the activation procedure.

To perform the activation procedure using OS X Recovery, power on the computer while pressing Command-R. From the Utilities menu, select Terminal. The remaining steps of the rEFInd activation process must be completed using the command line.

Disable SIP:

csrutil disable

Mount the EFI System Parition (ESP):

mkdir /Volumes/ESP
mount -t msdos /dev/disk0s1 /Volumes/ESP

Bless rEFInd:

bless --mount /Volumes/ESP --setBoot --file /Volumes/ESP/EFI/BOOT/bootx64.efi

Unmount the ESP:

umount /Volumes/ESP

Re-enable SIP:

csrutil enable

Shut down (or reboot) the OS X Recovery environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment