Create your multiboot USB key using Syslinux

Rémi Weislinger
7 min readMar 22, 2020
What do you think of my Ganondorf figurine? •ᴗ•

Some days ago, I came up with the idea to create a USB key which would be able to boot multiple GNU/Linux distros. This isn’t something new as you can already do this with tools like YUMI, but trying to do it from scratch ended up not being as easy as it looked like!

That’s why I wanted to share this story with you, to give you all the things I learned in this adventure.

Preparing your USB key

I used a basic 32GB stick from Kingston but there’s obviously no restrictions or constraints on the choice of the USB key. The only important thing to do is to format it as FAT32.

NOTE: Syslinux is compatible with other filesystems like ext{2,3,4} and Btrfs, but FAT32 is still the recommended format as it’s popular and allows you to read the content of your USB key on Windows smoothly!

# fdisk /dev/sdfWelcome to fdisk (util-linux 2.35.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): d
Selected partition 1
Partition 1 has been deleted.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): <ENTER>
Using default response p.
Partition number (1-4, default 1): <ENTER>
First sector (2048-60489727, default 2048): <ENTER>
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-60489727, default 60489727): <ENTER>
Created a new partition 1 of type 'Linux' and of size 28.9 GiB.Command (m for help): t
Selected partition 1
Hex code (type L to list all codes): b
Changed type of partition 'Linux' to 'W95 FAT32'.
Command (m for help): a
Selected partition 1
The bootable flag on partition 1 is enabled now.
Command (m for help): p
Disk /dev/sdf: 28.86 GiB, 30970740736 bytes, 60489728 sectors
Disk model: DataTraveler 3.0
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: 0x1fd81305
Device Boot Start End Sectors Size Id Type
/dev/sdf1 * 2048 60489727 60487680 28.9G b W95 FAT32
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
# mkfs.vfat /dev/sdf1
# fatlabel /dev/sdf MULTIBOOT

Once it’s done, you can go to the next step.

Installing Syslinux

Actually, installing Syslinux is the easiest part of this how-to, as you’ll only have to issue a few commands.

Making your key bootable

At first you obviously have to get Syslinux on your system before you can go any further (I’m running Archlinux, so some commands and paths might differ for you):

# pacman -S syslinux
# syslinux -v
syslinux 6.04 Copyright 1994-2015 H. Peter Anvin et al

Once you have Syslinux, you can install it on your USB key:

# syslinux -s -i /dev/sdf1
# dd bs=440 count=1 conv=notrunc if=/usr/lib/syslinux/bios/mbr.bin of=/dev/sdf

The two commands above will a) install Syslinux on the key, and b) write the syslinux MBR code on it.

Creating the required files

Your key is now ready to boot, but you still need some files to be able to do anything:

  • Core COM32 modules (which allow us to power off or reboot the system for example)
  • A Syslinux config file

These modules are bundled with Syslinux when you install it, so you only have to copy them onto the key. As for the config file, we will just touch it for now.

My key is automatically mounted by GNOME, but you might have to mount it manually depending on your setup.

$ cd /run/media/closingin/53C2-0342/
$ mkdir -p boot/syslinux
$ cp /usr/lib/syslinux/bios/*.c32 boot/syslinux/
$ touch boot/syslinux/syslinux.cfg

Getting your distros on the key

For this tutorial we will focus on 4 distros, but you can obviously add as much of them as you have space left on your device!

Creating the required directories

$ cd /run/media/closingin/53C2-0342/
$ mkdir -p systems/{ubuntu,archlinux,tails,kali}

Copying the files

Getting the distros on the key is pretty much straightforward. Download the system images using the links below:

Then copy them using the following commands (repeat it for every image):

# mount -t iso9660 -o loop,ro ~/Downloads/ubuntu-18.04.4-desktop-amd64.iso /mnt
$ cp -r -v --preserve=all /mnt/* ./systems/ubuntu

For Tails, which uses an .img file, the mount command will be slightly different (see this link to calculate the offset value):

# mount -o loop,ro,offset=1048576 ~/Downloads/tails-amd64-4.4.img /mnt
$ cp -r -v --preserve=all /mnt/* ./systems/tails

Because the filesystem of your key is FAT32, the copy will display some Operation not permitted errors while trying to copy symbolic links, which aren’t supported. You can safely ignore them, it won’t create any problems later on.

Writing the config

Here comes the hard part, but luckily for you I already did all the research! Writing a Syslinux config is actually pretty easy if you read the HOWTOs from the Syslinux wiki, but managing to boot your 4 systems successfully can end up being a nightmare (and trust me it drove me crazy).

Here is a working config that you can put in your boot/syslinux/syslinux.cfg file :

DEFAULT ubuntu
PROMPT 0
TIMEOUT 50
UI menu.c32
MENU TITLE MULTIBOOT
LABEL ubuntu
MENU LABEL UBUNTU 18.04.4 LTS (64 BITS)
LINUX ../../systems/ubuntu/casper/vmlinuz
INITRD ../../systems/ubuntu/casper/initrd
APPEND root=LABEL=MULTIBOOT rw live-media=/dev/disk/by-label/MULTIBOOT live-media-path=/systems/ubuntu/casper file=/systems/ubuntu/preseed/ubuntu.seed boot=casper quiet splash
LABEL archlinux
MENU LABEL ARCHLINUX 2020.03.01 (64 BITS)
LINUX ../../systems/archlinux/arch/boot/x86_64/vmlinuz
INITRD ../../systems/archlinux/arch/boot/intel_ucode.img,../../systems/archlinux/arch/boot/amd_ucode.img,../../systems/archlinux/arch/boot/x86_64/archiso.img
APPEND root=LABEL=MULTIBOOT rw archisobasedir=/systems/archlinux/arch archisolabel=MULTIBOOT quiet
LABEL tails
MENU LABEL TAILS 4.4 (64 BITS)
LINUX ../../systems/tails/live/vmlinuz
INITRD ../../systems/tails/live/initrd.img
APPEND root=LABEL=MULTIBOOT rw live-media-path=/systems/tails/live boot=live config live-media=removable nopersistence noprompt timezone=Etc/UTC block.events_dfl_poll_msecs=1000 noautologin module=Tails slab_nomerge slub_debug=FZP mce=0 vsyscall=none page_poison=1 init_on_alloc=1 init_on_free=1 mds=full,nosmt union=aufs quiet splash
SYSAPPEND 0x40000
LABEL kali
MENU LABEL KALI LINUX 2020.1 (64 BITS)
LINUX ../../systems/kali/live/vmlinuz
INITRD ../../systems/kali/live/initrd.img
APPEND root=LABEL=MULTIBOOT rw live-media=removable live-media-path=/systems/kali/live boot=live components noeject quiet splash

Here you can see why putting a label on our USB key is important. It helps the system find the device on which the files are located. We could also have used the device’s UUID instead of its label (using root=UUID=53C2-0342 and /dev/disk/by-uuid/5C32-0342 in my case), but I find labels more practical in the case you’d have to use another key or want to share your configuration.

Keep in mind that I didn’t find the required boot parameters on my own except for some of them. Most (if not all) of the distros already use Syslinux to boot, so they already have a config file which you can open to see its required boot parameters. I just had to adapt them to my directory structure.

Booting

Reboot your computer, boot on your key, and voilà! If it doesn’t detect your key, ensure that it’s not plugged in on a USB3 port.

Postmortem

To give you an insight of how hard it was to get everything up and working, Ubuntu uses an initramfs-tools hook called casper to boot its live system. The problem is that casper looks for the live system at the root of the USB key, which can’t work for us as it lies under the /systems/ubuntu subdirectory.

Using the live-media-path boot option is not enough as casper doesn’t know on which device to look for this path, so I needed to also use live-media, of which the usage is not documented anywhere. The man page of casper says it accepts a DEVICE parameter but doesn’t define what it can be. And obviously it couldn’t be as easy as LABEL=MULTIBOOT.

I had to go through the entire script file to see how it parsed the parameter and used it to mount the filesystem. In the end it was as simple as adding live-media=/dev/disk/by-label/MULTIBOOT, but it took me a few hours to sort it out ¯\_(ツ)_/¯

Bonus #1: Tweaking your boot menu

Being able to boot your system is great, isn’t it? But as you might already know, it’s possible to customize your boot menu using a COM32 module called vesamenu. Here is a sample config to get the menu that’s on my article. I’m using a modified version of the background from the “Tela” GRUB2 theme you can find on vinceliuice’s repository, but I won’t upload it to respect his work, and I’m sure you will find an image to suit your needs!

You have to overwrite the UI menu.c32 and MENU TITLE lines with the following config:

UI vesamenu.c32MENU TITLE MULTIBOOT
MENU AUTOBOOT Starting Ubuntu in # seconds
MENU VSHIFT 10
MENU HSHIFT 32
MENU ROWS 20
MENU WIDTH 60
MENU RESOLUTION 1024 768
MENU BACKGROUND splash_1024x768.jpg
MENU TABMSGROW 24
MENU CMDLINEROW 24
MENU TIMEOUTROW 26
MENU HELPMSGROW 28
MENU COLOR screen 37;40 #ffffffff #00000000 none
MENU COLOR border 30;40 #00000000 #00000000 none
MENU COLOR title 1;30;40 #9033ccff #a0ffffff std
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
MENU COLOR unsel 37;44 #50ffffff #00000000 std
MENU COLOR help 37;40 #c0ffffff #a0000000 std
MENU COLOR timeout_msg 37;40 #ffffffff #00000000 std
MENU COLOR timeout 1;37;40 #ffffffff #00000000 std
MENU COLOR msg07 37;40 #90ffffff #a0000000 std
MENU COLOR tabmsg 31;40 #30ffffff #00000000 std

If you want the same spacing between entries that I have on my picture, just use some MENU SEPARATOR between your menu entries.

Bonus #2: Adding some utilities

What about giving some love to these COM32 modules lying on your USB key ? And running a memory test ? Archlinux bundles memtest within its iso, it would be a shame to not use it.

LABEL memtest
MENU LABEL Memtest86+
LINUX ../../systems/arch/arch/boot/memtest
LABEL hdt
MENU LABEL HDT (Hardware Detection Tool)
COM32 /boot/syslinux/hdt.c32
LABEL reboot
MENU LABEL Reboot
COM32 /boot/syslinux/reboot.c32
LABEL poweroff
MENU LABEL Poweroff
COM32 /boot/syslinux/poweroff.c32

--

--

Rémi Weislinger

French web developer, I’m also interested in whatever is related to programming or security. I create art with my code.