My blog post explaining what this is all about and why this might be a good idea.

Checking iso9660

I’m starting with a distribution of Parrot Linux because it is coincidentally very similar to how I want my system to be. It has made many very sensible choices about interface (Mate, for example) and browser hardening (Noscript). It also has a load into cache option (which I think Debian itself does too, but this one is very easy to use).

The first thing to do is to obtain the ISO image.


Normally you would install this on a USB flash drive with a simple dd transfer. But before doing that, it’s good to check its ISO9660 system. Here’s what it looks like from the iso file as downloaded.

:->[usb64][/mnt/sda/xed/os]$ xorriso -dev stdio:Parrot-lite-3.7_amd64.iso
xorriso 1.4.6 : RockRidge filesystem manipulator, libburnia project.

xorriso : NOTE : ISO image bears MBR with  -boot_image any partition_offset=16
xorriso : NOTE : Loading ISO image tree from LBA 0
xorriso : UPDATE : 1260 nodes read in 1 seconds
xorriso : NOTE : Detected El-Torito boot information which currently is set to be discarded
Drive current: -dev 'stdio:Parrot-lite-3.7_amd64.iso'
Media current: stdio file, overwriteable
Media status : is written , is appendable
Boot record  : El Torito , MBR isohybrid cyl-align-on
Media summary: 1 session, 592760 data blocks, 1158m data, 69.4g free
Volume id    : 'ParrotSec'

Note especially the line with "ISO image bears MBR". This seems critical in getting it to boot (from flash drives anyway).

For reference, here’s what the iso looks like installed on a flash drive.

$ _ xorriso -dev stdio:/dev/sdg1
xorriso 1.4.6 : RockRidge filesystem manipulator, libburnia project.

xorriso : NOTE : Loading ISO image tree from LBA 0
xorriso : UPDATE : 1260 nodes read in 1 seconds
Drive current: -dev 'stdio:/dev/sdg1'
Media current: stdio file, overwriteable
Media status : is written , is appendable
Boot record  : (system area only) , not-recognized
Media summary: 1 session, 592744 data blocks, 1158m data,     0 free
Volume id    : 'ParrotSec'

Modifying the iso9660 file system

A USB flash drive system is really emulating a live CD (or DVD), some kind of optical media. That means its real file system at that level is iso9660. This is a read only file system (because of traditional CDs) and to change it you have to extract all its files to a new writeable file system, make your changes, and then remaster a new iso9660 file system image.

This webpage covers Debian iso mastering tools. You may need to start with apt-get install xorriso.

To get started, the iso image file (note loop option) must be mounted and then its contents replicated somewhere writeable.

sudo mount -o ro,loop -t iso9660 Parrot-lite-3.7_amd64.iso /mnt/iso
rsync -aP /mnt/iso /tmp/isocontents

Now make your changes to /tmp/isocontents. Specifically, see the next section on doing the same kind of routine with the squashfs. These are nested operations; basically you need to "gosub" to the next section and return here when that is complete. Go on, go do that now and then come back here.

Once you have a new squashfs image file the way you want it replace the one in your writeable iso directory.

sudo cp squashcontents/filesystem.squashfs isocontents/live/filesystem.squashfs

Now it’s almost time to compose a new iso9660 system. Before you can do that, you need to extract a master boot record from the original iso image to use in the new one. This avoids generating a new one from scratch which may not be quite right. Here’s how to get the first 512 bytes (the MBR) from the iso image. This is used later.

sudo dd if=Parrot-lite-3.7_amd64.iso bs=512 count=1 of=./orig.mbr

Once you have a master boot record in a file that you can use, run the messy command xorrisofs as seen here.

sudo xorrisofs -v -J -r \
-V ParrotSec \
-o Parrot-lite-3.7_amd64-xed.iso \
-isohybrid-mbr orig.mbr  \
-c isolinux/  \
-b isolinux/isolinux.bin  \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot  \
-e boot/grub/efi.img \
-no-emul-boot \
-isohybrid-gpt-basdat \

This runs quite quickly and should produce a new bootable iso image file, Parrot-lite-3.7_amd64-xed.iso from the contents of /tmp/isocontents. This iso file should be able to be installed on a USB flash drive directly with something like this.

sudo dd if=Parrot-lite-3.7_amd64-xed.iso of=/dev/sdg status=progress

If you’re not sure about which exact drive should be the target (of=output file) device, use the lsblk command before and after inserting the target USB drive. Needless to say that it is very, very bad to use dd to write over an important hard drive by mistake. And of course your USB flash drive will forsake its previous contents.

At this point, you should be able to tell your computer’s BIOS to boot the USB drive (see my notes on this for clues). You can then choose to load into "RAM Mode" at the boot menu and once it boots, you can remove the flash drive. 100% integrity. Enjoy!

Modifying the squashfs file system

The main location for all the files of the live distribution reside in a squashfs filesystem. Like the iso9660 system that encapsulates it, this must be unpacked into a normal (ext4?) file system, modified and then repacked back into a squashfs.

sudo mkdir /tmp/squashfs_contents
cd /tmp/squashfs_contents
sudo unsquashfs /tmp/isocontents/live/filesystem.squashfs

This will fill up your current directory with the contents of the squashfs system. Make your changes to squashfs_contents.

Again, go to the next section, make the content changes and return here. You need to mentally keep track of your stack depth.

When you are finished making your changes, you have to repack all that back up.

sudo mksquashfs squashfs-root/ filesystem.squashfs \
          -noappend -always-use-fragments -comp xz

This can take several minutes and it will admirably fully use all of your CPU cores.

Once you have a new squashfs file containing your custom stuff, you have to put that new file into the isocontents file tree, overwriting the original filesystem.squashfs. At this point, return to the iso section and resume packing that up.

Modifying the actual stuff you care about

Here’s where you finally get to change the things that are meaningful to the end user. Given all that trouble to change things, what can be changed? The first place to look is probably /etc/skel. This is both obvious and weird. It’s obvious because it’s the traditional place to put things that will be instilled into new accounts upon creation; it’s weird because you don’t think of it as needing to create an account. But these Debian live systems do create a new account on boot, just like the Guest systems (which presumably use the same location).

For example, if you want your own .bashrc to be active for the user (UID=1000) user, replace the one in /etc/skel in the squashfs. When the live image boots, the user account will get created with your .bashrc and you’ll get what you want.


It seems that the .config/dconf/user file is particularly important for settings. It’s in some annoying registresque format. Thankfully Parrot comes with dconf-editor. You can make your changes using the System Control Center menus the normal way. Once it’s how you like it, isolate the new updated user file, offload it to where you are customizing, and just overwrite the one in your image’s skeleton.

After making your actual desired improvements to the system, return to the squash section to pack everything up.

Other Resources