A couple of weeks ago I’ve added some new functionality to
dfu-tool which is shipped in fwupd. The dfu-tool utility (via libdfu) now has the ability to forward-patch binary files, somewhat like
bsdiff does. To do this it compares the old firmware with the new firmware, finding blocks of data that are different and storing the new content and the offset in a .dfup file. The reason for storing the new content rather than a binary diff (like bsdiff) is that you can remove non-free and non-redistributable code without actually including it in the diff file (which, you might be doing if you’re neutering/removing the Intel Management Engine). This does make reversing the binary patch process impossible, but this isn’t a huge problem if we keep the old file around for downgrades.
$ sha1sum ~/firmware-releases/colorhug-1.1.6.bin 955386767a0108faf104f74985ccbefcd2f6050c ~/firmware-releases/colorhug-1.1.6.bin $ sha1sum ~/firmware-releases/colorhug-1.1.7.bin 9b7dbb24dbcae85fbbf045e7ff401fb3f57ddf31 ~/firmware-releases/colorhug-1.1.7.bin $ dfu-tool patch-create ~/firmware-releases/colorhug-1.1.6.bin ~/firmware-releases/colorhug-1.1.7.bin colorhug-1_1_6-to-1_1_7.dfup -v Dfu-DEBUG: binary growing from: 19200 to 19712 Dfu-DEBUG: add chunk @0x0000 (len 3) Dfu-DEBUG: add chunk @0x0058 (len 2) Dfu-DEBUG: add chunk @0x023a (len 19142) Dfu-DEBUG: blob size is 19231 $ dfu-tool patch-dump colorhug-1_1_6-to-1_1_7.dfup checksum-old: 955386767a0108faf104f74985ccbefcd2f6050c checksum-new: 9b7dbb24dbcae85fbbf045e7ff401fb3f57ddf31 chunk #00 0x0000, length 3 chunk #01 0x0058, length 2 chunk #02 0x023a, length 19142 $ dfu-tool patch-apply ~/firmware-releases/colorhug-1.1.6.bin colorhug-1_1_6-to-1_1_7.dfup new.bin -v Dfu-DEBUG: binary growing from: 19200 to 19712 Dfu-DEBUG: applying chunk 1/3 @0x0000 (length 3) Dfu-DEBUG: applying chunk 2/3 @0x0058 (length 2) Dfu-DEBUG: applying chunk 3/3 @0x023a (length 19142) $ sha1sum new.bin 9b7dbb24dbcae85fbbf045e7ff401fb3f57ddf31 new.bin
Perhaps a bad example here, the compiler changed between 1.1.6 and 1.1.7 so lots of internal offsets changed and there’s no partitions inside the image; but you get the idea. For some system firmware where only a BIOS default was changed this can reduce the size of the download from megabytes to tens of bytes; the largest thing in the .cab then becomes the XML metadata (which also compresses rather well). Of course in this case you can also use bsdiff if it’s already installed — I’ve not yet decided if it makes sense for fwupd to runtime require tools like bspatch as these could be needed by the firmware builder bubblewrap functionality, or if it could just be included as statically linked binaries in the .cab file. Comments welcome.