Custom Protocol

The fwupd project already supports a huge number of flashing protocols, everything from standardized protocols like NMVe, ATA, DFU and also a large number of vendor-specfic protocols like logitech_hidpp, synaptics_prometheus and wacom_raw.

Most vendors are using a protocol that fwupd already supports, and thus only need to upload firmware to the LVFS. In the case applying for an account is all that is required.

Note

If using DFU, please also implement the DFU runtime interface – this allows fwupd to automatically switch your device into bootloader mode without having to draw some artwork and write some translated text to explain how the user should persuade the device to enter update mode.

The easiest time to add support for updating hardware using the LVFS is during the project prototype phase. There are several things you can do that makes writing a fwupd plugin much easier.

In the case where the device protocol is a non-compatible variant or a completely custom protocol then a new fwupd plugin will be required. If you have to use a custom protocol, there are a few things that are important to consider.

The fwupd daemon needs to be able to enumerate the device without the user noticing, which means LEDs should not blink or cause the screen to flicker. Disconnecting a kernel driver, changing to bootloader mode or any other method of getting the device firmware version is not acceptable. This means the device needs to expose the current firmware version on the runtime interface, for instance using USB descriptors or PCI revision fields.

For composite devices (e.g. docks) it is much better to provide an interface to query the internal device topology rather than hardcoding it in the plugin or in a quirk file. For instance, fwupd could query the root device that would respond that it is acting as a I²C bridge to a HDMI chip with address 0xBE, rather than hardcoding it for a specific dock model. Querying the information allows the plugin author to write a generic plugin that means future devices can be upgraded without waiting for new fwupd versions to be included in popular Linux distributions and ChromeOS.

Warning

Plan and test for what happens when the user disconnects the USB cable, runs out of battery, or removes the mains plug when the new firmware is being flashed.

If the device remains in bootloader mode, is there a unique VID/PID that can be used to choose the correct firmware file to flash the device back to a functional runtime mode?

Many vendors just use the ISV-provided reference bootloader (which is fine), but fwupd does not know which runtime image to recover with if the ISV-allocated generic VID/PIDs are being used. If it is not possible to modify the bootloader VID/PID, then it may be possible to read a block of NVRAM at a hardcoded offset to identify the proper firmware to install.

When updating hardware it is important to provide feedback to the user so that they know the process has not hung. Updating firmware is intimidating to many users and so it is important to provide information about what is being done to the hardware, for instance erasing, writing and verifying. It is also a very good idea to provide percentage completion, so for an operation that is going to take 10 seconds it is better to write 1024 blocks of 16kB with percentage updates after each block rather than one block of 16Mb with just a bouncing progressbar.

Note

It is not possible to upload executable flasher code as part of the cabinet archive – only the payload is allowed.

We will not accecpt non-free executables, static libraries or “shim” layers in fwupd. The only way a custom protocol can be supported is by contributing a LGPLv2+ plugin upstream.

Some vendors will have the experience to build a plugin themselves, and some vendors may wish to use a consulting company that has the required experience.

Intellectual Property Concerns

The plugin code in fwupd is Open Source (LGPLv2+), licensed in a way that makes it possible for another vendor or an end-user to read and modify the code. Some companies have initially said that an open source plugin would be impossible due to concerns about either trade secrets, security or both. Let’s look at the trade secret or intellectual property concern by answering some questions:

  • How many firmware updater binaries were sold last year?

  • Is the update protocol significantly more complicated than read version number, switch to bootloader, erase blocks, write blocks, read back blocks to verify, switch to runtime?

  • Can a user dump the USB communication using a $20 capture tool and replay the recording to update a different device?

  • Is the shared secret token sent unencrypted as part of the update protocol?

The fact is that most OEM vendors sell physical devices to consumers and both the hosting of updates on a company webserver and the development of the update client itself is typically a cost-centre, and not a revenue stream. The fwupd project supports more than 80 different update protocols, and most of them use exactly the same design; there may be differences in required header format or CRC32 polynomials, but 95% of “secret vendor protocols” are almost exactly the same from a high-level design perspective – and thus do not constitute valuable intellectual property.

Wireshark dump showing unencrypted data transfer

Wireshark dump showing unencrypted data transfer

Another important consideration is that the fwupd plugin doesn’t need to know everything about the hardware – for instance, in the Synaptics MST plugin we know the offset in the configuration header of the current firmware version, but the rest of the header is unspecified and still secret. In the PixArt plugin we know the offset of the 32 bit AA.BB.CC.DD version number, but the rest of the file is treated as a binary blob that is just sent to the device in small sections.

Another concern from vendors is that as an open source project, anyone can edit, modify, or even sabotage code that communicates with their device. Of course, the maintainers of the fwupd project will review and check carefully every proposed change. Most plugins also have tests that emulate that specific device firmware update – that get verified for each and every proposed change. Any plugins that require stronger “ownership” requirements can also add an Owners section in the per-plugin README.md file that will be used to notify responsible users that validation or functional re-testing is required before a change is merged.

Some vendors are also unwilling to agree to an open source plugin to fwupd as the payload will be discovered as unsigned or communication is unencrypted, and attackers will know how to attack the devices. Unfortunately, it’s very easy to scan a firmware payload for signatures or even to calculate the entropy. It’s even possible to perform a manual bitswap in something like the USB descriptor to know if the payload signature is being verified correctly. Security through obscurity has never been acceptable, and hackers are more than capable of dumping an unencrypted firmware update process and then modifying the code to inject malware. An attacker does not care about having source code through legitimate means and does not need permission.

The answer is either to properly implement firmware signing, or to just be okay that the current device has unsigned firmware. It is completely acceptable for devices to not implement firmware signing for example with OpenHardware devices, or devices where the user is encouraged to build custom firmware. The LVFS only allows vendors to update their own hardware (e.g. Wacom can only update devices with USB vendor ID of 0x056A) and so it is not possible for another vendor to automatically update firmware on your hardware, even if the payload is unencrypted or unsigned.

On a similar note, some vendors will not want to open the update protocol as it would allow consumers to flash the “pro” version of a firmware to the “basic” device to software-unlock features that are usually only available in a more expensive model. Whilst this is a concern if the two devices have the same signing key (they should have different keys) or if they have no signing requirement at all – it’s very easy to fool even official non-free binary updater programs just by changing how the Windows/Linux kernel reports either the device USB VID/PID or USB HID descriptor. From real world experience, the number of users that are going to disable the device checks in an open source project (a risky procedure) is going to be a staggeringly small number of people compared to the number of people that will be able to update the correct hardware with the latest firmware.

Turning this around completely, many vendors who have added new fwupd plugins have found that the RMA (return merchandise authorization) rate for hardware has actually reduced significantly. This is because the newer firmware fixes a bug, for instance a USB-4 dock not working with their existing DisplayPort monitor – where it does work with the latest dock firmware applied. Similarly, users may choose the consumer device or peripheral exactly because it has a fwupd support, and because firmware updates can be managed at scale using Windows, Linux, macOS or ChromeOS.

Depending on a new library

Please do not use model-specific or vendor-specific libraries to update or enumerate the hardware. Unless the library is already shipped by default on Ubuntu LTS and RHEL 8 then it is going to be exceptionally hard to use this library in fwupd. As fwupd is in main for Ubuntu then any library it depends on must also be part of main, which means Canonical has to officially support it. They obviously do not want to do this for vendor-specific libraries that have only existed for a few years with no API or ABI guarantees or long term stable branches.

Similarly for Red Hat; any new library or binary needs to have a Red Hat maintainer who will support it for over 10 years (!) and is willing to do the security due diligence and code review required to be included as a core package in RHEL. Getting approval for a new package is a huge amount of work and takes months.

As fwupd is running as root, any external library it depends on must be audited by several security teams, and have a proven security plan in place. Google also needs to review any new dependencies as fwupd is also being used heavily in ChromeOS now, and they take OS image size and security very seriously.

In this situation it is completely okay to include parts of the open source library (assuming the code can be licensed as LGPLv2+) in the fwupd plugin. Including them in fwupd plugins also allows us to use the fwupd helper functionalily, for instance replacing memcpy() with fu_memcpy_safe() and using high level abstractions for reading and writing to sysfs files or an ioctl. Many plugins already do this, for instance the colorhug plugin does not use libcolorhug, nvme plugin does not use the nvme command line tool and the emmc plugin itself defines EXT_CSD_FFU rather than depending on mmc-utils.

Building fwupd

Please see the fwupd documentation.