Monday, 10 July 2017

Down the OVA compatibility rabbit hole

I recently volunteered to create a B2R CTF for SecTalks_BNE. It was fairly simple to create the content within the machine, however I came across a few hurdles when trying to make the machine as portable as possible. I wanted it to be easily usable on VirtualBox as well as VMware Fusion, Player and Workstation.

Before embarking on this project I had foolishly assumed I could just create the VM in VirtualBox and then "Export Appliance..." to create a portable OVA. If only it were that simple!

The OVA files that were created by VirtualBox worked fine by other VirtualBox users, but VMware users were getting various levels of success; Fusion wouldn't play nice at all.

I've created this post so that I remember what to do again down the track, and as a side bonus hopefully someone else will benefit or learn from it!

Let me explain some acronyms first

An OVA file is an Open Virtualisation Appliance. It's essentially a tarball containing an OVF, one or more disk images (usually VMDK files) and a manifest (checksum) file.

The OVF (Open Virtualisation Format) specifies the configuration of the virtual machine. The disk images contain data held by the virtual drives.

Gathering test data

To get some VMware test data I dragged my old HP N54L out of the cupboard and installed ESXi 6.5 on it. The disk performance was horrendously slow until I disabled the problematic AHCI driver as per this blog.

After creating a few OVA files from ESXi, my testing concluded that VirtualBox happily accepted a VMware OVA but VMware had a hard time working with a VirtualBox OVA.

One solution would be to do all my development on ESXi, but I quite like using VirtualBox on my laptop!

My VirtualBox solution

I decided to keep things simple and use ESXi to generate the initial OVA. I chose to target VMware 4 to keep it compatible with pretty much everything. After this step ESXi was no longer required.

I then unpacked said OVA, prepared the replacement disk image with VirtualBox and rolled my own OVA using a few commands.

The initial OVA contained the following:
$ tar xvf covfefe.ova
covfefe.ovf
covfefe.mf
disk-0.vmdk

To prepare the replacement disk-0.vmdk file, I ran through the steps in my earlier blog post and converted from VDI to VMDK with clonemedium (also mentioned in the same post).

After replacing the VMDK file, I edited the size entry in the OVF to reflect the new file:
<File ovf:href="disk-0.vmdk" ovf:id="file1" ovf:size="464093696"/>

Once I finished editing the OVF I had to create the correct checksums to use in the manifest file:
$ shasum covfefe.ovf disk-0.vmdk
249eef04df64f45a185e809e18fb285cadfcd6f0  covfefe.ovf
ae1718beb7d5eb7dfb5158718b0eceda812512a2  disk-0.vmdk

After the changes my manifest file looked like this:
$ cat covfefe.mf 
SHA1 (covfefe.ovf)= 249eef04df64f45a185e809e18fb285cadfcd6f0
SHA1 (disk-0.vmdk)= ae1718beb7d5eb7dfb5158718b0eceda812512a2

I then reassembled the OVA file:
$ tar cf covfefe.ova covfefe.ovf covfefe.mf disk-0.vmdk

Just as a test I also did the assembly using OVF Tool as it did some extra checks while assembling:
$ /Applications/VMware\ OVF\ Tool/ovftool covfefe.ovf covfefe.ova

The OVA has worked flawlessly on everything I've tested it on so far which is VirtualBox 5.1.22, VMware ESXi 6.5, Fusion 8.5.8 and Player 6.0.1.

Prepping a Linux VM for OVA export

These are the steps I recommend to prepare a Linux VM for OVA export. It should keep the size down to a minimum and prevent headaches and confusion down the track!

I'm using VirtualBox but the info applies to VMware. You'll just have to read the VMware documentation for the compacting section.

I am running these commands from a Debian Stretch live CD inside the guest, and have mounted the destination filesystem (/dev/sda1) as /mnt:
$ sudo mount /dev/sda1 /mnt

Disable systemd from renaming network interfaces

If you leave this enabled, you'll have different network interface names for VirtualBox and VMware so your interface definitions won't work in both!

I disable this by adding the kernel parameter "net.ifnames=0", you can do this within /mnt/etc/default/grub:
GRUB_CMDLINE_LINUX="net.ifnames=0"

Then run update-grub from within a chroot:
$ sudo mount --bind /dev /mnt/dev
$ sudo mount --bind /proc /mnt/proc
$ sudo mount --bind /sys /mnt/sys
$ sudo chroot /mnt
# update-grub
# exit
$ sudo umount /mnt/dev /mnt/proc /mnt/sys

You'll now want to adjust /etc/network/interfaces (or equivalent) accordingly to reflect eth0 instead of enp0s17 or whatever.

Sanitise the log directory

Nuke the contents but leave files in place:
$ sudo find /mnt/var/log -type f -exec sh -c 'cat /dev/null > {}' \;

Discard unallocated blocks

Unmount the filesystem then discard unallocated blocks:
$ sudo umount /mnt
$ sudo e2fsck -E discard /dev/sda1

Compact the disk image

This is done from the host, not the guest.

If you're using a VDI file, you can use modifymedium --compact:
https://www.virtualbox.org/manual/ch08.html#vboxmanage-modifyvdi

If you're using a VMDK file, you can use clonemedium:
https://www.virtualbox.org/manual/ch08.html#vboxmanage-clonevdi

Wednesday, 26 April 2017

Installing Raspbian on the Raspberry Pi 3 using raspbian-ua-netinst

I really like using the Raspbian unattended netinstaller (raspbian-ua-netinst) for doing headless installs of Raspbian to Raspberry Pi devices. You pretty much write the installer image to SD, create a configuration file, then insert the SD into the Pi and let it do the rest.

I wasn't able to install Raspbian to my Raspberry Pi 3 using the current latest build (1.0.9) of raspbian-ua-netinst as it still lacks support for this newer hardware.

Below is a quick guide on what I did to get it up and running successfully. I ran this from a Raspberry Pi but you could just as easily use any Linux machine:

Pull down the v1.1.x branch from GitHub:
$ git clone -b v1.1.x https://github.com/debian-pi/raspbian-ua-netinst.git

Download and build:
$ cd raspbian-ua-netinst
$ ./build.sh

Create the images you can then write to SD, this requires root for the loopback setup:
$ sudo ./buildroot.sh

If using a Raspberry Pi with limited swap like myself, you may get an error when creating the xz archive due to it being unable to allocate sufficient memory to xz. It's no problem as you can use the uncompressed or bz2 image.

As an example you could run bzcat raspbian-ua-netinst-20170426-gited24416.img.bz2 redirected to the destination SD card (the card itself, not a partition device).

Hopefully this post will be redundant soon when a newer raspbian-ua-netinst is released with Raspberry Pi 3 support, but until then I hope this is useful to someone!

Monday, 19 December 2016

Issue where KVM guest freezes just before installation of CentOS 7

I've been playing around with KVM on CentOS 7 in preparation for the RHCE exam. I was experiencing an issue where the guest virtual machine would freeze just before attempting an install (again, CentOS 7 as the guest).

The testing machine is quite old (has an Intel Core 2 6400 CPU) but it hasn't shown any other symptoms of hardware issues.

The logs didn't appear to show anything of interest other than some debugging information which is apparently normal:
[20389.379023] kvm [19537]: vcpu0 unhandled rdmsr: 0x60d
[20389.379034] kvm [19537]: vcpu0 unhandled rdmsr: 0x3f8
[20389.379039] kvm [19537]: vcpu0 unhandled rdmsr: 0x3f9
[20389.379043] kvm [19537]: vcpu0 unhandled rdmsr: 0x3fa
[20389.379048] kvm [19537]: vcpu0 unhandled rdmsr: 0x630
[20389.379053] kvm [19537]: vcpu0 unhandled rdmsr: 0x631
[20389.379057] kvm [19537]: vcpu0 unhandled rdmsr: 0x632

Anyway, I was able to work around the issue by feeding the "--cpu host" option to virt-install, or by ticking "Copy host CPU configuration" under the CPUs tab of the VM configuration.

Hope this helps save someone else some time!

Monday, 10 October 2016

Installing Debian on the APU2

This is a short post detailing the install of Debian on the PC Engines APU2 using PXE.

First of all you'll need to ensure you are running version 160311 or newer BIOS. You can find the BIOS update details here. If the PXE options are missing then there's a good chance you aren't running a new enough BIOS!

Connect to the system's console via the serial port using a baud rate of 115,200. I typically use screen on Linux/macOS or PuTTY on Windows.

Start the APU2 and press Ctrl+B when prompted to enter iPXE, or choose iPXE from the boot selection menu (F10).

Attept boot from PXE using DHCP:
iPXE> autoboot

If all is well you will get to the "Debian GNU/Linux installer boot menu" heading, press TAB to edit the Install menu entry.

This should bring up something along the lines of:
> debian-installer/amd64/linux vga=788 initrd=debian-installer/amd64/initrd.gz --- quiet

You'll want to define the serial console by adding the console parameter to the end (and preseed parameter if used):
> debian-installer/amd64/linux vga=788 initrd=debian-installer/amd64/initrd.gz --- quiet console=ttyS0,115200

Press enter and you should be on your way!

PXE boot Debian using RouterOS as PXE server

I would typically use a Linux server for the purposes of PXE booting, but this is so straightforward it's a very attractive option. I'm using a MikroTik RB2011 (RouterOS v6.34.6) successfully.

This example assumes your router's LAN IP is 172.16.8.1 and the local subnet is 172.16.8.0/24.

First of all, download the netboot archive to a Linux machine (I'm using a Raspberry Pi here):
tim@raspberrypi /tmp $ wget http://ftp.au.debian.org/debian/dists/jessie/main/installer-amd64/current/images/netboot/netboot.tar.gz
tim@raspberrypi /tmp $ wget http://ftp.au.debian.org/debian/dists/jessie/main/installer-amd64/current/images/SHA256SUMS

Check that your archive matches the checksum file:
tim@raspberrypi /tmp $ grep `sha256sum netboot.tar.gz` SHA256SUMS
SHA256SUMS:460e2ed7db2d98edb09e5413ad72b71e3132a9628af01d793aaca90e7b317d46  ./netboot/netboot.tar.gz

Extract the archive to a tftp directory:
tim@raspberrypi /tmp $ mkdir tftp && tar xf netboot.tar.gz -C tftp

Copy tftp folder to the MikroTik:
tim@raspberrypi /tmp $ scp -r tftp admin-tim@172.16.8.1:

On the MikroTik, configure TFTP on MikroTik with a base directory of /tftp (omitting req-filename matches all):
[admin-tim@MikroTik] /ip tftp add ip-address=172.16.8.0/24 real-filename=tftp

Configure DHCP for PXE booting:
[admin-tim@MikroTik] /ip dhcp-server network set [ find address=172.16.8.0/24 ] boot-file-name=pxelinux.0 next-server=172.16.8.1

Thursday, 4 August 2016

Electric bike build part 5

Continued from Electric bike build part 4.

After about 6 revisions I finally had a workable design for mounting my accessories. I decided to design a mount in two parts that when brought together form a ring around the stem to allow a second "row" of stuff to be mounted.

Here's the final design:


It is all held together only by the accessories mounted to it, but it seems quite solid. Originally the top and bottom parts were identical, but I had to change to an offset design to mount the light higher. The larger lobe is to accomodate the headlight's mount which is designed for an oversized bar.

Here's everything bolted up and in place, I'm very happy with the result:


The throttle is easily within reach of my left thumb when not in the drops, and I can safely keep my right hand near the front brake at the same time. I also really like having the Bafang display quite far forward as it makes it always easy to see. The IPS display looks amazing even in direct sunlight:


I took the bike for a test ride and wasn't able to wipe the grin from my face! Talk about making cycling effortless!

Here's the bike fully completed, although disregard the low seat hight:


The 42/11-30 gearing seems to work quite well for my intended purpose of using this bike as a commuter.

I have a warning though; I have used the bike four times now and have done about 90km. In the last 10km I noticed a bit of a clicking noise when pedalling, it turns out the lock ring had become slightly lose. This surprised me as I used thread locker and applied the correct amount of torque to the lock ring, I assumed the ones having trouble weren't doing the install correctly. Today I re-tightened the lock ring to "epic tight" and will monitor it.