Skip to content

Reading a kernel version out of a bzImage

 2 min hexdump plus strings pulls the version string from a kernel image via the x86 boot protocol’s version pointer at offset 0x20E.
Published

Aug 15, 2014

A boot-time btrfs rollback hook has a specific problem: after you select an older root subvolume, the kernel sitting inside it may not be the kernel already running. To decide whether to kexec into the on-disk one, the hook needs the on-disk kernel’s version—from the image file alone, in a busybox initramfs, with no booted userland to ask.

The x86 boot protocol answers this. A 2-byte little-endian pointer lives at offset 0x20E; it gives the offset of the version string, relative to 0x200. Two hexdump calls and strings extract it:

kver() {
    local offset=$(hexdump -s 526 -n 2 -e '"%d"' "$1")
    hexdump -s $(( 0x200 + offset )) -n 128 -e '"%.2s"' "$1" | strings -n10
}

526 is 0x20E in decimal; -n 2 -e '"%d"' reads the pointer as one number. The second call seeks to 0x200 + offset and dumps 128 bytes, which strings -n10 trims to the printable version line. Compare that against uname -r/uname -v, and if they differ, copy kernel and initrd to /tmp, unmount the subvolume, and boot that kernel:

kexec -f "/tmp/linux" --initrd="/tmp/initrd" --reuse-cmdline --append="kexeced"

The copy-to-/tmp-then-umount ordering is load-bearing: once you unmount the subvolume the files are gone, so they must already be somewhere the kexec can read.

The loop terminator is the part I like. --append="kexeced" adds a bare word to the command line. On the next boot that bare word becomes a set shell variable in the initramfs, so [ -z "$kexeced" ] guarding the whole handoff is false the second time through and the hook does not kexec again. A kernel command-line token doubling as a “we already did this” flag, with no state file anywhere.

The rollback architecture and its __active/__snapshot/__rollback frame are mine. The kexec handoff and the original version probe were added by Michael Göhler; the compact hexdump form above and the implicit-boolean kexeced trick are Dave Reisner’s, from a later cleanup. The hook accumulated all three contributions.