In this blog post, I will document how we created a working port of fwupd for FreeBSD, as well as the biggest challenges we encountered.
We found we had to implement 3 basic functionalities in order to have a basic FreeBSD port:
- Gathering information about applicable updates for attached devices,
- Updating firmware of devices attached via USB,
- Updating the system firmware via the UEFI Update Capsule mechanism.
Identifying available updates
One difference between Linux and FreeBSD 12.2, on which we started development,
is the lack of
memfd_create(), a function that creates an anonymous,
temporary file in memory and returns a file descriptor. This is an alternative
to creating a temporary file and having to manage it manually, and fwupd
utilizes it for handling downloads.
Older (pre-13.0) versions of FreeBSD and other BSD distributions do not have an equivalent API - so we had to emulate it by creating a temporary unlinked file. The pull request adding this functionality is available here.
As you can see from the logs below, we are now able to identify available updates for our machine - in this case, a Dell XPS 15 9560.
Applying USB updates
Next, we encountered a problem with USB device updates: We tried to update the firmware of a ColorHug2, and after rebooting it to the device’s bootloader mode, it didn’t return to the operating system.
fwupd uses the libgusb library, a GLib wrapper around libusb. The usual flow of an update is as follows:
- Issue command to the device to enter bootloader mode - in the case of ColorHug2, a custom HID-based flashing mode
- Write an update to the device
- Upon successful update, return the device to runtime mode
The issue occurred after the first step - we were unable to reattach the device to the host. After issuing a command to reset the device back to normal operation, the OS would not recognize and reattach it - it would stay gone.
Because libgusb uses libusb’s asynchronous API, fwupd would close a
device after an update before all events had been processed. Upon processing
such an event, libusb would detect that the device is gone and mark it with
device_is_gone flag. This meant that on all future requests, libusb would
fail with a
This turned out to be another difference between the Linux and FreeBSD APIs. The way fwupd utilizes the libusb API was legal under the Linux version of libusb. Therefore, we decided to change FreeBSD’s behavior to more closely match that of Linux. We did so by making it so that a device can only be marked as gone if it’s currently open.
The patch was submitted and accepted into the FreeBSD tree and is available here.
And with that, we can now perform a successful update of a ColorHug2:
UEFI Update Capsule
From the perspective of security, UEFI updates are absolutely critical and implementing this functionality for FreeBSD was a priority. There were a couple of parts that would need to be implemented in order to make it work:
- UEFI ESRT table support in FreeBSD, and support for it in fwupd
- FreeBSD efivar backend for fwupd - on Linux, efivar support is implemented
sysfsinterface, while FreeBSD has a C API
bsdiskssupport in fwupd
- adding support in an
fwupddaemon plugin - the UEFI update capsule plugin
UEFI ESRT (EFI System Resource Table) is a standard interface for firmware updates available since UEFI 2.5. It exposes, among other data, information about the currently installed firmware versions and the status of last update attempt. It’s used by fwupd for detection and matching available updates. Support for these tables was missing in FreeBSD - so we added it. Upstream patches available here.
fwupd applies firmware updates by installing a small EFI binary along with the
update capsule into the ESP and setting the EFI bootnext variable to point to it.
The machine reboots and launches the EFI binary which then calls
UpdateCapsule(), which in turn tells the UEFI to apply the capsule. The
actual flashing is handled by the UEFI implementation itself.
This requires efivar support, and FreeBSD has a different, programmatic API, so support for it had to be added in fwupd. Furthermore, since FreeBSD has a disk management API that differs slightly from the Linux standard UDisks2 API, support for it also had to be added. The patches ( 1, 2 ) were accepted by upstream.
With these patches, it is currently possible to install a UEFI update - but keep in mind that this is an early implementation and bugs are more than likely to occur. Bug reports are welcome.
If you think we can help in improving the security of your firmware or you
looking for someone who can boost your product by leveraging advanced features
of used hardware platform, feel free to book a call with us
or drop us email to
contact<at>3mdeb<dot>com. If you are interested in similar
content feel free to sign up to our newsletter