Dell XPS – add disk encryption

The Dell XPS and Precision laptops with Linux pre-installed are great for personal and business use. Unfortunately, they lack an important feature: their disks have been factory pre-installed without encryption. Read below how to add that to the system without having to reinstall.

The factory setup for Dell XPS and Precision with Linux is using just plain /dev/nvm0n1p1, p2 and p3 unencrypted partitions. So no matter how fancy your password is – all of your data may be exposed, should your laptop fall in the wrong hands. Fixing this is a relatively straight forward job, which I’ll describe below. You will need a large micro SD card – large enough to contain all of your data, plus an Ubuntu live CD (another 4Gb). I used a 256G micro SD card. (In the example a much smaller micro SD card is used).

What we’ll do is: 1) prepare your system for LVM2 and LUKS, and make a backup; 2) prepare the micro SD card; 3) start the system from this card; 4) copy the root file system to an LVM2 volume on this card. 5) We’ll check – double-check; 6) then erase /dev/nvm0n1p3; make a new p3 and a p4; 7) we’ll prepare p4 to be an LVM2 physical volume and finally use pvmove to put the root file system back.

Step 1. Install lvm2 and cryptsetup on your laptop. (Should you happen to have an Ubuntu minimal install, then these packages have not been installed, so we better make sure they are there). So go apt-get install lvm2 cryptsetup. Then make a proper backup. Doesn’t matter where you put it, but do make a backup. I personally use “rsync” a lot, something like sudo rsync -ax –numeric-ids –delete / /media/…./something should do the job.

Step 2. Download an installer CD for Ubuntu. Write it to your micro SD card using the Startup Disk Creator. This will create a 3Gb “iso9660” filesystem (a “DVD”), and an EFI partition of 4Mb. In the example below, our SD card can be found in /dev/mmcblk0.

Now use “fdisk” to add an extra partition. Please note the “wipe” option – seemingly necessary to prevent fdisk from removing the iso9660 signature.

$ sudo fdisk --wipe never /dev/mmcblk0
 Welcome to fdisk (util-linux 2.34).
 Changes will remain in memory only, until you decide to write them.
 Be careful before using the write command.
 Command (m for help): n
 Partition type
    p   primary (2 primary, 0 extended, 2 free)
    e   extended (container for logical partitions)
 Select (default p): p
 Partition number (3,4, default 3): <enter>
 First sector (5999872-30277631, default 6000640): <enter>
 Last sector, +/-sectors or +/-size{K,M,G,T,P} (6000640-30277631, default 30277631): <enter>
 Created a new partition 3 of type 'Linux' and of size 11,6 GiB.
 Command (m for help): w
 The partition table has been altered.
 Syncing disks.
 
$ sudo fdisk -l /dev/mmcblk0
 Disk /dev/mmcblk0: 14,45 GiB, 15502147584 bytes, 30277632 sectors
 Units: sectors of 1 * 512 = 512 bytes
 Sector size (logical/physical): 512 bytes / 512 bytes
 I/O size (minimum/optimal): 512 bytes / 512 bytes
 Disklabel type: dos
 Disk identifier: 0x2cf4ba3a
 Device         Boot   Start      End  Sectors  Size Id Type
 /dev/mmcblk0p1 *          0  5999871  5999872  2,9G  0 Empty
 /dev/mmcblk0p2      5271500  5279499     8000  3,9M ef EFI (FAT-12/16/32)
 /dev/mmcblk0p3      6000640 30277631 24276992 11,6G 83 LinuxDisk /dev/mmcblk0: 14,45

Let’s make this an LVM2 physical volume right away:

$ sudo pvcreate /dev/mmcblk0p3 
   Physical volume "/dev/mmcblk0p3" successfully created.
$ sudo vgcreate vg42 /dev/mmcblk0p3
   Volume group "vg42" successfully created
$ sudo lvcreate -l 100%FREE -n root vg42
   Logical volume "root" created.
$ sudo mkfs -t ext4 /dev/vg42/root
 mke2fs 1.45.5 (07-Jan-2020)
 Discarding device blocks: done                            
 Creating filesystem with 3034112 4k blocks and 758880 inodes
 Filesystem UUID: 6fe69999-5ee7-46ae-9c82-a4352806dd36
 Superblock backups stored on blocks: 
         32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208
 Allocating group tables: done                            
 Writing inode tables: done                            
 Creating journal (16384 blocks): done
 Writing superblocks and filesystem accounting information: done 

As you can see, I am not encrypting the SD card. This means that you should properly wipe your copy once you’re done, because all of your files will be readable from this micro SD card. You could argue that an encrypted /dev/mmcblk0p3 is better, feel free to implement that, it’s not hard (cryptsetup luksFormat, then luksOpen and finally make the lvm disk on the luks opened device).

3) Now start your laptop from this live Ubuntu system on the new SD card. That will probably involve some BIOS setup trickery, telling your laptop to “boot from sd card” and turning “fast bios” off. Please ask the internet how to proceed, it’s not in this blog post.

Select “Try Ubuntu” once the graphical desktop is visible. Then start a terminal and type “sudo -i” to become root.

4) mount both the original root-filesystem from your laptop and the newly made LVS partition. Proceed as follows:

# mkdir /mnt/source /mnt/target
# mount -o ro /dev/nvm0n1p3 /mnt/source
# mount /dev/vg42/root /mnt/target

You are now ready to copy everything from source to destination. Choose your favourite copying program. You can use “cp” (but mind any hidden directories that your root fs could theoretically have) or use “rsync”:

# cp -a /mnt/source/* /mnt/target/
or use
# rsync -a /mnt/source/ /mnt/target/
... or when you are resuming an aborted copy, you might want to
# rsync -a --delete /mnt/source/ /mnt/target/ 

So let’s assume you copied everything and are ready to try start your new root filesystem. This is going to be a bit tricky: we are going to tell the operating system to start from our new /dev/vg42/root, but in order to do that, we must change files in the original root directory.

Yes, you read that right: the boot sequence of the laptop will, for now, be unchanged and it will first try to start a boot loader from the EFI partition; and in turn, this bootloader will fetch its configuration from the /boot directory inside /dev/nvm0n1p3. So here is our next step:

# mount -o remount,rw /mnt/source/
Fire up your favourite editor and edit grub.cfg
# nano /mnt/source/boot/grub/grub.cfg

Find menuentry “Ubuntu” and change the root filesystem from UUID=…. to /dev/vg42/root:

menuentry 'Ubuntu' --class ubuntu --class [...] {
[...]
         fi
         linux   /vmlinuz-5.11.0-43-generic root=/dev/vg42/root ro  quiet splash $vt_handoff
         initrd  /initrd.img-5.11.0-43-generic
 }

Also, to not annoy the OS too much, we’ll change /etc/fstab to be in sync with our new setup: our root filesystem now is on LVM2, and is called /dev/vg42/root.

# nano /mnt/target/etc/fstab
change UUID=...... to /dev/vg42/root
# umount /mnt/target

If you’re feeling confident, adventurous or simply irresponsible, you could use sed to change the file for you, replace the nano command above with:

# sed -i 's#^UUID.* / #/dev/vg42/root / #' /mnt/target/etc/fstab(

Unmount /mnt/source and reboot the laptop. It should now boot with /dev/vg42/root as its root filesystem. (However, beware: if you run “update-grub”, your change will be gone and the original /dev/nvm0n1p3 will be used for root filesystem). We’re half way now, and ready to encrypt the disk.

This is the tricky part: removal of the original root filesystem, repartitioning the hard drive and setting up the encrypted filesystem. Oh, for reasons too complicated to explain, my example doesn’t use a GPT partition table. That is why the question about a “primary” or “extended” partition comes up. Please ignore this.

We will use fdisk to remove the original /dev/nvm0n1p3, add a small 500Mb boot partition /dev/nvm0n1p3 and an encrypted /dev/nvm0n1p4:

~# fdisk /dev/nvm0n1
Command (m for help): d
 Partition number (1-3, default 3): 3
 Partition 3 has been deleted.
 Command (m for help): n
 Partition type
    p   primary (2 primary, 0 extended, 2 free)
    e   extended (container for logical partitions)
 Select (default p): p
 Partition number (3,4, default 3): 3
 First sector (10741760-488397167, default 10741760): <enter>
 Last sector, +/-sectors or +/-size{K,M,G,T,P} (10741760-488397167, default 488397167): +500M
 Created a new partition 3 of type 'Linux' and of size 500 MiB.
 Partition #3 contains a ext4 signature.
 Do you want to remove the signature? [Y]es/[N]o: y
 The signature will be removed by a write command.
 Command (m for help): n
 Partition type
    p   primary (3 primary, 0 extended, 1 free)
    e   extended (container for logical partitions)
 Select (default e): p
 Selected partition 4
 First sector (11765760-488397167, default 11765760): <enter>
 Last sector, +/-sectors or +/-size{K,M,G,T,P} (11765760-488397167, default 488397167): <enter>
 Created a new partition 4 of type 'Linux' and of size 227,3 GiB.
 Command (m for help): w
 The partition table has been altered.
 Syncing disks.
~# mkfs -t ext4 /dev/nvm0n1p3 
 mke2fs 1.45.5 (07-Jan-2020)
 Discarding device blocks: done                            
 Creating filesystem with 128000 4k blocks and 128000 inodes
 Filesystem UUID: 61094874-5c78-4688-b1b2-133314347e6e
 Superblock backups stored on blocks: 
     32768, 98304
 Allocating group tables: done                            
 Writing inode tables: done                            
 Creating journal (4096 blocks): done
 Writing superblocks and filesystem accounting information: done

Now partitioning is done, we’ll first populate the new /boot partition. This one is not encrypted, which means someone with physical access to your laptop could still try to mess up your kernel and/or initrd in order to gain access to your files. It is possible to encrypt grub and the /boot partition – read all about it. But hey: here we are just encrypting your root and home, we aren’t hardening your laptop. So let’s proceed:

~# umount /boot/efi 
~# mv /boot/ /boot_orig
~# mkdir /boot
~# mount /dev/nvm0n1p3 /boot
~# mv /boot_orig/* /boot
~# rmdir /boot_orig
~# echo "UUID=`lsblk -no UUID /dev/nvm0n1p3` /boot ext4 defaults 0 2" >> /etc/fstab
~# mount /boot/efi

Our nvm0n1p3 is ready as a /boot disk. Please note that in order for the grub bootloader to find it, we will need to run grub-install – we will do that after our encrypted partition is ready. Let’s proceed to encrypt nvm0n1p4:

~# cryptsetup luksFormat /dev/nvm0n1p4 
 WARNING!
 This will overwrite data on /dev/nvm0n1p4 irrevocably.
 Are you sure? (Type uppercase yes): YES
 Enter passphrase for /dev/nvm0n1p4: <some-very-secret-password>
 Verify passphrase: <some-very-secret-password>
~# cryptsetup luksOpen /dev/nvm0n1p4 datavault
 Enter passphrase for /dev/nvm0n1p4: <some-very-secret-password>
~# echo "datavault UUID=`lsblk -no UUID /dev/nvm0n1p4` none luks,discard" >> /etc/crypttab 
~# grub-install
 Installing for x86_64-efi platform.
 Installation finished. No error reported.
~# update-initramfs -u -k all
update-initramfs: Generating /boot/initrd.img-5.11.0-43-generic
update-initramfs: Generating /boot/initrd.img-5.11.0-27-generic
~# update-grub
 Sourcing file /etc/default/grub' Sourcing file/etc/default/grub.d/init-select.cfg'
 Generating grub configuration file …
 Found linux image: /boot/vmlinuz-5.11.0-43-generic
 Found initrd image: /boot/initrd.img-5.11.0-43-generic
 Found linux image: /boot/vmlinuz-5.11.0-27-generic
 Found initrd image: /boot/initrd.img-5.11.0-27-generic
 Adding boot menu entry for UEFI Firmware Settings
 done

All right. We are almost there. Let’s try to reboot. If all goes well, we will have a booted Linux machine, starting from /dev/vg42/root, and because we have setup a crypttab entry, it will ask for a password during the boot sequence.

If all is well, you can re-login. Check that /dev/mapper/datavault exists and if it does, proceed to move all data back to the internal disk:

~# pvcreate /dev/mapper/datavault 
   Physical volume "/dev/mapper/datavault" successfully created.
~# vgextend vg42 /dev/mapper/datavault 
   Volume group "vg42" successfully extended
~# pvmove /dev/mmcblk0p3 
   /dev/mmcblk0p3: Moved: 0,17%
   /dev/mmcblk0p3: Moved: 3,95%
   /dev/mmcblk0p3: Moved: 7,59%
   /dev/mmcblk0p3: Moved: 11,20%
   /dev/mmcblk0p3: Moved: 14,85%
….

This could take a while. In the mean time, you can use your laptop. And when Moved is a 100% ready, you’ll just need to remove /dev/mmcblk0p3 from the LVM2 volumes. For some odd reason (hidden deep inside the initrd), removing PV /dev/mmcblk0p3 will prevent initrd from asking the crypt password for /dev/nvm0n1p4. You must re-generate initrd to fix this:

~# vgreduce vg42 /dev/mmcblk0p3
removed "/dev/mmcblk0p3" from volume group "vg42"
~# pvremove /dev/mmcblk0p3
Labels on physical volume "/dev/mmcblk0p3" successfully wiped
~#  update-initramfs -u -k all
update-initramfs: Generating /boot/initrd.img-5.11.0-43-generic
update-initramfs: Generating /boot/initrd.img-5.11.0-27-generic

You may now eject the SD card and reboot once more. Your root disk has been encrypted. (Don’t forget to erase the micro SD card that you used to copy the files to. Do not just use “blkdiscard”, but empty the disk with “dd” or by other means if you are really paranoid).

Leave a Reply

Your email address will not be published. Required fields are marked *