Disclaimer: this is not a definitive guide, but rather a write-up of my working solution. I'm pretty sure that there will be better and more sophisticated methods/approaches to accomplish this task, so consider this as PoC and therefore don't blame me Moreover I want to to say that I tried to report all sources from which I took useful informations, but of course I lost/forgot some of them in this long journey so I apologize in advance.
My configuration:
Host OS: Debian Buster
BIOS: Legacy mode
Bootloader: GRUB2
The story so far...
I want to launch Kali Live on my laptop but... Two of my 3 USB ports burned out (obviously the USB 3.0 ones) and my laptop doesn't boot from SD-Card. Thus I tried with an USB hub to launch live USB, and attach my wifi dongle(s) but I realized that performances are really bad, so I searched for other ways and I found this article [0] where it argue how to boot iso images from HDD (there is also a section concerning kali live - wow what a luck!). But i know that life is cruel [1] and the guide provided by the article refers to "plain"/simple partition scheme, while I have LUKS+LVM (legacy bios *not* UEFI) ..
Roughly speaking, the problem is that if I would access to the ISO image that is located on this partition/disk, first I have to open the LUKS partition (and LVM volume). But wait.. Is GRUB2 able to perform this task? Luckily according to [2] it seems to be possible, and it is also possible to manage LVM volumes. So most of our work seems to be done..
How-To
Ok, let's start and take a look to [0] and then to its proposed grub menu entry:
Code:
menuentry 'Kali Linux Live' {
set isofile="/live/kali-linux-2020.2-live-i386.iso"
insmod ext2
insmod loopback
insmod iso9660
loopback loop (hd0,msdos1)$isofile
search --no-floppy --fs-uuid --set=root 3b87d941-8ee7-4312-98fc-1f26828d62ab
linux (loop)/live/vmlinuz boot=live fromiso=/dev/sda1/$isofile noconfig=sudo username=root hostname=kalilinux
initrd (loop)/live/initrd.img
}
So following that guide, first of all we have create /live folder in our root partition (see [3] if you want to know why we put iso in /live folder)
next copy our kali iso to this folder (I renamed it to a simpler name to avoid stupid typo errors)
Code:
# cp ~/Downloads/kali-linux-2020.3-live-amd64.iso /live/kali.iso
and execute this command to prepare our grub menu entry file:
Code:
# cp /etc/grub.d/40_custom /etc/grub.d/41_kali_live
Now we should get the UUID of the partition where our iso is located, so i ran the blkid command and, in my case, i got the following output:
Code:
# blkid
/dev/sda1: UUID="e45e8ef8-25fe-4805-a4d4-7e649c025731" TYPE="ext2" PARTUUID="96004b47-01"
/dev/sda5: UUID="87694137-578b-46d9-9fa0-702f2adf2ae0" TYPE="crypto_LUKS" PARTUUID="96004b47-05"
/dev/mapper/sda5_crypt: UUID="N11Wpn-ljbP-MN1E-Cnt1-syF8-Mc6B-gt01Q2" TYPE="LVM2_member"
/dev/mapper/asd--vg-root: UUID="998da96f-87df-4a46-985e-2b2dfefae403" TYPE="ext4"
where
- /dev/sda1 is my unencrypted boot partition
- /dev/sda5 is my encrypted partition
- /dev/mapper/sda5_crypt refers to my dm-crpyt mounted disk
- /dev/mapper/asd--vg-root refers to my unique LVM partition inside LUKS partition (it's my configuration but can be different if you have /home, /usr etc.. mounted elsewhere)
Now comes the tricky part Remember that our iso is located in the LUKS+LVM partition, so to mount our iso on the loopback device we first need to open our LUKS partition. According to [2] we have to load this modules in grub menu entry
after loading these modules, we are able to open our crypto partition/disk, so type:
Code:
cryptomount -u UUID_1 (UUID_1 is the UUID of crypto partition - /dev/sda5 in my case - and has to be stripped out from dash!!!)
next we define two variables useful to simplify the writing of our grub directives
- isofile: define the full ISO image path on our partiton
- vmpart: define our LVM partition where ISO image file is located (we have to adopt grub naming convention [4] to identify the device/parition, so we have lvm/PART_NAME. You can see this name by issuing these commands on grub console:
Code:
insmod cryptodisk
insmod luks
insmod lvm
cryptomount -u UUID_1
ls <--- this will show you also the lvm partition/disk
or in a simpler way we'll always have 'lvm/' string and the PART_NAME is the lvm parition name - see previous blkid command)
Next we have to load other useful modules (part_msdos, ext2, lvm, loopback, iso9660) and define our root variable by executing this command:
Code:
search -u UUID_2 --no-floppy --set=root --hint=${lvmpart} (where UUID2 is the UUID of lvm partition - here with dash..)
Next mount our iso
Code:
loopback loop0 $isofile
and finally we can load our kernel and initrd image. But wait. Again. We first need to open our LUKS partition because the rootfs of the live (that is in the iso image file) is located there, so we need to tell the kernel (better, initrd) how to accomplish this task. After many days spent on searching on the internet and trying all more creative proposed solutions (obviously none of them worked ), I decided to extract initrd image and take a look to the scripts inside it (See the section below for details) and there I finally found the magical parameter to pass to the kernel that i need [5].
So the resulting kernel line will be:
Code:
linux (loop0)/live/vmlinuz boot=live cryptopts=target=CRYPTO_DEVICE,source=UUID=UUID_1,key=none,luks,discard live-media=LVM_PARTITION findiso=live/kali.iso
and at the end we can load the initrd image
Code:
initrd (loop0)/live/initrd.img
The resulting grub menu entry file will be:
Code:
#!/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 "Kali live" {
insmod cryptodisk
insmod luks
# UUID_1 without dash!!
cryptomount -u UUID_1
set isofile="/live/kali.iso"
set lvmpart='lvm/asd--vg-root'
insmod part_msdos
insmod ext2
insmod lvm
insmod loopback
insmod iso9660
search -u UUID_2 --no-floppy --set=root --hint=${lvmpart}
loopback loop0 $isofile
linux (loop0)/live/vmlinuz boot=live cryptopts=target=CRYPTO_DEVICE,source=UUID=UUID_1,key=none,luks,discard live-media=LVM_PARTITION findiso=live/kali.iso components
initrd (loop0)/live/initrd.img
}
As you can see there are some values that have to be defined and that are specific to your configuration
- CRYPTO_DEVICE = /dev/sda5_crypt
- UUID_1 = UUID of crypto_LUKS parition (/dev/sda5)
- UUID_2 = UUID of LVM parition (/dev/mapper/asd--vg-root)
- LVM_PARTITION = /dev/mapper/asd--vg-root
The flag "components" was found in grub.cfg of live iso grub menu entry.
Done! Now run update-grub, reboot and enjoy your kali live.
Thanks to int80h for the review , lordzen to listen my continuous computer delusions and Crash for help and politeness in IRC channel.
initramfs inspection
In this section I'm going to explain how I found the cryptopts params needed to passed to kernel to open LUKS partition with initrd (I know that now all Debian/Linux/kernel developers will hate me, but try to restrain yourselves from blame me )
As I said before i extracted the initdrd image file and inspected the scripts inside.
First of all we need to create some temp folders to mount and unpack all our needed resources.
Code:
# mkdir /tmp/kali-initrd # this folder will contain the kali initrd image
# mkdir /tmp/kali-iso # in this folder we mount the iso of kali live
Next, we mount our iso
Code:
# mount -o loop /live/kali.iso /tmp/kali-iso
and copy the kali initrd image in our initrd folder and then umount our iso
Code:
# cp /tmp/kali-iso/live/initrd.img-5.7.0-kali1-amd64 /tmp/kali-initrd
# umount /tmp/kali-iso
According to [6] let's check our initrd image file
Code:
# cd /tmp/kali-initrd
# file -L initrd.img-5.7.0-kali1-amd64
it turns out thath it's a ASCII cpio archive (SVR4 with no CRC), so the initrd image has microcode prepended and we need to extract it
Code:
# cpio -i < ./initrd.img-5.7.0-kali1-amd64
5862 blocks
As we can see from command output now we have to skip 5862 blocks from initrd image file to get our basic initrd
Code:
# dd if=initrd.img-5.7.0-kali1-amd64 of=initrd.img bs=512 skip=5862
Again check our (new) initrd file
Code:
# file -L initrd.img
initrd.img: gzip compressed data, ...
and now we can finally extract our initrd
Code:
# zcat initrd.img | cpio -i
Now type 'ls' to see what we have now in our folder
Code:
# ls
bin conf cryptroot etc init initrd.img initrd.img-5.7.0-kali1-amd64 kernel lib lib32 lib64 libx32 run sbin scripts usr var
As you can see there is a cryptoroot folder with a crypttab file inside (according to [7]). Let's look into this file to see its content
Code:
# cat cryptroot/crypttab
Obviously this file is empty and this is the reason why the initrd doesn't know how mount our "root" partition (the LUKS partition where our iso is located). So let's look inside scripts folder and we can see that there are many files/dirs. In particular let's look to 'scripts/local-top/cryptroot' file. From line 176 you can see kernel boot arguments section
Code:
# Do we have any kernel boot arguments?
if ! grep -qE '^(.*\s)?cryptopts=' /proc/cmdline; then
# ensure $TABFILE exists and has a mtime greater than the boot time
# (existing $TABFILE is preserved)
touch -- "$TABFILE"
else
# let the read builtin unescape the '\' as GRUB substitutes '\' by '\\' in the cmdline
tr ' ' '\n' </proc/cmdline | sed -n 's/^cryptopts=//p' | while IFS= read cryptopts; do
# skip empty values (which can be used to disable the initramfs
# scripts for a particular boot, cf. #873840)
[ -n "$cryptopts" ] || continue
unset -v target source key options
IFS=","
for x in $cryptopts; do
case "$x" in
target=*) target="${x#target=}";;
source=*) source="${x#source=}";;
key=*) key="${x#key=}";;
*) options="${options+$options,}$x";;
esac
done
[...]
so according to [5] we have to pass to kernel these parameters finding the UUID of our crypto partition/disk as described in previous section and we are ready to create our custom menu entry.
Bonus track (boot from SD CARD)
In a very short moment of despair I gave up with open LUKS partition but I find a quick way to boot from SD Card.
First, flash the iso to your SD Card (oh, really?).
Next, copy vmlinuz and initrd files from your mounted live iso to your unencrypted /boot parition (they are located in "live" folder; I renamed it in vmliunz-kali and initrd-kali.img).
Now, supposing your boot partition following grub naming convention [4] is in (hd0, msdos1), write this menu entry:
Code:
menuentry "Kali live SD CARD" {
insmod part_msdos
insmod ext2
linux (hd0,msdos1)/vmlinuz-kali boot=live live-media=/dev/mmcblk0p1 components
initrd (hd0,msdos1)/initrd-kali.img
}
Enjoy
[0] - https://www.tecmint.com/run-linux-li...disk-in-linux/
[1] - https://dettieproverbi.it/proverbi/c...china-e-merda/
[2] - https://www.gnu.org/software/grub/ma...yptomount.html
[3] - https://manpages.debian.org/buster/l...boot.7.en.html
[4] - https://www.gnu.org/software/grub/ma...onvention.html
[5] - https://cryptsetup-team.pages.debian...-boot-argument
[6] - https://wiki.debian.org/initramfs#Ho...pect_initramfs
[7] - https://manpages.debian.org/jessie/c...ttab.5.en.html
Other useful (for me) links:
https://kernel-team.pages.debian.net...initramfs.html
https://wiki.debian.org/initramfs
https://man7.org/linux/man-pages/man7/boot.7.html
https://man7.org/linux/man-pages/man7/bootparam.7.html
https://www.kernel.org/doc/html/v4.1...arameters.html
https://wiki.archlinux.org/index.php...g_encrypt_hook
https://mirrors.edge.kernel.org/pub/...acut.html#_lvm