Hardened Gentoo on the XPS: Developer Edition
Signing all the things

Intro

This post is a small introduction to install a hardened Gentoo on your 2015 XPS. You’ll end up with a laptop that

Disclaimer: Though everything should work regardless of your exact model, you might have to reconfigure the kernel if you’re not using an XPS 9343.

I will not go over every detail. If yo are a Gentoo user you’ve probably installed your fair share of stage3 tarballs already. If in doubt, consult the Gentoo Handbook.

What you need

Instead of using an ethernet adapter you might try to download all necessary drivers beforehand and place them on the USB stick to work around the wifi not working out of the box.

I used this ethernet adapter which has linux support via the asix module out of the box. The total cost cost was around ~8 Euros.

Bios configuration

General ->
  Boot Sequence ->
    # We're enabling UEFI to make use of the secure boot feature later on
    Boot List Option = UEFI

  Advanced Boot Options ->
    # Required for secure boot
    Enable Legacy Option ROMs = false

System Configuration ->
  # Required so Linux properly recognizes the SSD
  SATA Operation = AHCI

  # Require to boot Ubuntu from the USB Stick
  USB Configuration = Enable Boot Support

Security ->
  # It's always a good idea to set a BIOS password
  Admin Password = Your Password

  # Without this enabled, most PaX features are non-functional
  CPU XD Support = Enable

  # Disable this for now
  Secure Boot = Disabled

Also make sure that you delete all existing secure-boot keys if you actually want to sign your kernel. Without removing them, you’ll be unable to set any new ones from within the operating system. This is by-design as to not allow an attacker with root-privileges to disable secure boot and replace your kernel.

After you’ve configure your BIOS, plug in the USB Stick and press F12 when you see the Dell-Logo. This should give you the option to boot Ubuntu.

Formatting and encrypting your drive

You should’ve booted Ubuntu and opened a terminal by now. In the shell code below I’m assuming that /dev/sda is your SSD. If that’s not the case, substitute it with the correct device.

# Run fdisk on your harddrive
root@ubuntu:~# fdisk /dev/sda

# Create a new GPT diskable
Command (m for help): g
Created a new GPT disklabel (GUID: FCD46C6A-C7C2-487C-8BC2-2763C7AB9DBA).

# /boot parition
Command (m for help): n
Partition number (2-128, default 2):
First sector (6144-500118158, default 6144):
Last sector, +sectors or +size{K,M,G,T,P} (6144-500118158, default 500118158): +256M

Created a new partition 2 of type 'Linux filesystem' and of size 256 MiB.

# Swap
Command (m for help): n
Partition number (3-128, default 3):
First sector (530432-500118158, default 530432):
Last sector, +sectors or +size{K,M,G,T,P} (530432-500118158, default 500118158): +16G

Created a new partition 3 of type 'Linux filesystem' and of size 16 GiB.

Command (m for help): t
Partition number (1-3, default 3): 3
Hex code (type L to list all codes): 19

Changed type of partition 'Linux filesystem' to 'Linux swap'.

# Root parition
Command (m for help): n
Partition number (4-128, default 4):
First sector (34084864-500118158, default 34084864):
Last sector, +sectors or +size{K,M,G,T,P} (34084864-500118158, default 500118158):

Created a new partition 4 of type 'Linux filesystem' and of size 222.2 GiB.

# Write your partition table
Command (m for help): p

Next up, you want to format and encrypt your new paritions:

# Formatting your partitions, boot and swap will be unencrypted
root@ubuntu:~# mkfs.ext2 /dev/sda2
root@ubuntu:~# mkswap /dev/sda3
root@ubuntu:~# swapon /dev/sda3

# Encrypting your root partition
root@ubuntu:~# dd if=/dev/zero of=/dev/sda4
root@ubuntu:~# cryptsetup -caes-xts-plain64 -s512 -hsha512 -i10000 -y luksFormat /dev/sda4
root@ubuntu:~# cryptsetup luksOpen /dev/sda4 root

# Create filesystem on root and mount boot
root@ubuntu:~# mkdir /mnt/gentoo
root@ubuntu:~# mkfs.ext4 /dev/mapper/root
root@ubuntu:~# mount /dev/mapper/root /mnt/gentoo
root@ubuntu:~# mkdir /mnt/gentoo/boot
root@ubuntu:~# mount /dev/sda2 /mnt/gentoo/boot

Installing the base system

At this point you’ve got an empty, encrypted harddrive that’s mounted at /mnt/gentoo. We’ll need to to download the stage3 tarball and get the basic configuration in place before we can chroot into our new system and start building the kernel.

You should consult the gentoo handbook at this point if you don’t know all the steps by heart.

The make.conf configuration I’m using below is un-opinionated, so you might want to add some additional useflags depending on what window manager you want to install. Make sure the DRACUT_MODULES section is included because we’ll need that to boot from our encrypted drive.

# File: /etc/portage/make.conf

CFLAGS="-O2 -pipe -march=core-avx2 -mabm -madx -mavx256-split-unaligned-load -mavx256-split-unaligned-store -mprfchw -mrdseed"
CXXFLAGS="${CFLAGS}"
CHOST="x86_64-pc-linux-gnu"
USE="bindist"
CPU_FLAGS_X86="aes avx avx2 fma3 mmx mmxext popcnt sse sse2 sse3 sse4_1 sse4_2 ssse3"
VIDEO_CARDS="intel i965"
INPUT_DEVICES="evdev synaptics"
DRACUT_MODULES="crypt"
GRUB_PLATFORMS="efi-64"
PORTDIR="/usr/portage"
DISTDIR="${PORTDIR}/distfiles"
PKGDIR="${PORTDIR}/packages"

Configuration

Once you’ve chrooted into the freshly unpacked tarball, it’s time to configure the rest of the system. At this point you should check out the following git repositiory, which contains an optimized kernel configuration among some other file that will be useful later: https://github.com/invokr/xps-9343-linux

You should also go through the kernel configuration to check that you are fine with any of the PaX settings. Some of the things I configured may not be to everyones liking:

The former forces you to have any and all USB devices plugged in at boot. I particularly like this because it means that someone sticking their USB-Stick in my laptop at a conference is not going to have any effect. The later just strips all kernel symbols, which makes debugging harder but prevents some rootkits from working correctly.

# Select the hardened profile
root@ubuntu:~# eselect profile list
root@ubuntu:~# eselect profile set XX # hardened/linux/amd64

# Update all packages with the new useflags
root@ubuntu:~# emerge --ask --update --deep --newuse @world

# Configure locales
root@ubuntu:~# nano -w /etc/locale.gen
root@ubuntu:~# locale-gen
root@ubuntu:~# eselect locale list
root@ubuntu:~# eselect locale set X
root@ubuntu:~# env-update && source /etc/profile

# Wireless driver
root@ubuntu:~# emerge -a net-wireless/broadcom-sta net-misc/dhcpcd net-misc/netifrc net-wireless/wpa_supplicant
root@ubuntu:~# cp /etc/init.d/net.lo /etc/init.d/net.wlp2s0
root@ubuntu:~# rc-update add net.wlp2s0 default

# Applications to configure pax / rbac
root@ubuntu:~# emerge --ask paxctl gradm

# Install and configure the kernel
root@ubuntu:~# emerge -av hardened-sources dracut

# Copy the configuration from the github repository to /usr/src/linux/.config
root@ubuntu:~# make -j5 && make modules_install

# Copy the etc/efi directory from the repository to /etc and generate keys to sign our kernel
# The generate script is from the git repositiory mentioned above
# For extra security, you should encrypt your EFI directory using LUKS
root@ubuntu:~# mkdir /etc/efi
root@ubuntu:~# chmod 700 /etc/efi
root@ubuntu:~# sh generate.sh

# Don't forget the root password
root@ubuntu:~# passwd

Now that you have a working kernel and the keys to sign it, we want to add those keys to the bios’s key-store. This prevents any unsigned kernel from booting. Note that this only works if you have remove the existing Microsoft keys as mentioned in the beginning of the post.

cd /etc/efi

# Backup all the old keys
root@ubuntu:~# efi-readvar -v PK -o old_PK.esl
root@ubuntu:~# efi-readvar -v KEK -o old_KEK.esl
root@ubuntu:~# efi-readvar -v db -o old_db.esl
root@ubuntu:~# efi-readvar -v dbx -o old_dbx.esl

# Assign the new keys. Note that booting windows will be impossible from here on out, once secure boot is enabled again
root@ubuntu:~# efi-updatevar -e -f old_dbx.esl dbx
root@ubuntu:~# efi-updatevar -c KEK.crt KEK
root@ubuntu:~# efi-updatevar -c db.crt db
root@ubuntu:~# efi-updatevar -f PK.auth PK

With PK.auth reset, it will now be impossible to overwrite any of the already added keys unless they are cleared in the bios again. Should you want to ever go back to windows, deleting all the keys and reimporting the old ones will do the trick. The Dell BIOS also has a reset option that will roll-back the windows key automatically.

It’s also possible to dual boot if you combine your keys with Microsoft’s. I’m not going to go into that as there is plenty information available online on how to do it.

The next step is to sign our kernel and generate an efi-stub that is bootable. Because the XPS’s Bios does not pass any parameters to the kernel during boot, meaning it’s impossible to specify the root / luks device directly, we need an initrd-image that already includes all the parameters.

It might be possible to hardcode these with gentoolkit, I couldn’t get this work though, so instead of using gentoolkit I recommend using dracut, which is easy to setup and worked without any issues for me.

# Export our CMDLINE for the kernel
root@ubuntu:~# export CMDLINE="rd.luks.uuid=luks-{Your luks harddrive uuid} resume=UUID={swap UUID} root=UUID={uuid of encrypted luks drive} rootfstype=ext4 rootflags=rw,realtime,data=ordered"

# Create a signed boot image
root@ubuntu:~# dracut --kernel-cmdline="$CMDLINE" --uefi --kernel-image /usr/src/linux/arch/x86/boot/bzImage --force -a crypt /boot/EFI/gentoo/BOOT.x64.efi
root@ubuntu:~# sbsign --key /etc/efi/db.key --cert /etc/efi/db.crt --output /boot/EFI/gentoo/BOOT.x64.efi /boot/EFI/gentoo/BOOT.x64.efi.signed

The only thing that’s left to do is reboot, go into your bios and select /boot/EFI/gentoo/BOOT.x64.efi.signed in the EFI section. Afterwards, you can enable secureboot and you should be good to go!

You know have an encrypted harddrive that only boots your signed kernels.

*****
Written by Robin Dietrich on 01 March 2017, tagged as linux, security