Skip to main content
RunBook Academy

LinuxLXIX · Hardware HealthFirmware

Firmware lifecycle - the layer your package manager cannot see

Advanced⏱ ~14 minfwupdmgrdmidecodeipmitool

What you'll learn

  • Enumerate the firmware present on a host and its current versions
  • Apply firmware updates through fwupd and recognise when a vendor bundle is required
  • Treat firmware version drift across a fleet as a defect rather than cosmetic
  • Plan a firmware change knowing that rollback is frequently unavailable

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-11

Not yet marked complete on this device.

Ask a well-run fleet what version of openssl it is running and you will get an exact answer in seconds. Ask the same fleet what version of NIC firmware is on its hosts and the honest answer is usually that nobody knows.

That gap matters because firmware is where a specific and frustrating class of production bug lives. An NVMe drive that drops off the bus under sustained write load, a NIC that corrupts checksums when a particular offload is enabled, a RAID controller that stalls during a rebuild, a CPU errata that needs a microcode update to fix — none of these are visible to apt list --upgradable, and all of them present as “the application is broken” for as long as nobody thinks to look below the operating system.

What counts as firmware on a server

ComponentTypical update pathReboot needed
System BIOS / UEFIfwupd (UEFI capsule) or vendor bundleYes
CPU microcodeOS package, loaded every boot, or BIOSYes (or a fresh boot)
BMCVendor tool or the BMC web interfaceBMC restarts; host keeps running
RAID controllerVendor tool (storcli, ssacli)Usually
NVMe and SAS drivesnvme fw-download/fw-commit, or vendor bundleUsually
NICfwupd or vendor toolUsually
Backplane, PSU, expanderVendor bundleSometimes

The column that surprises people is the third one. Firmware updates are not uniformly “reboot the box”; a BMC update restarts only the BMC, and a drive firmware commit may take effect on the next drive reset rather than the next host boot. Knowing which is which is what lets you batch the disruptive ones into a single window.

Auditing what you have

Start with the platform identity, which you already have from the inventory lesson:

sudo dmidecode -t bios      # BIOS vendor, version, release date
sudo dmidecode -t system    # product name and service tag

Then ask fwupd, which enumerates every device that has a firmware version it can read — whether or not it can update it:

Read-only / Safefwupd audit
$ fwupdmgr get-devices
fwupdmgr refresh
fwupdmgr get-updates
ACME R740xd
│
├─System Firmware:
│     Device ID:          8b6b5c1e...
│     Current version:    2.19.0
│     Vendor:             ACME (DMI:ACME)
│     Update State:       Success
│
├─Embedded Controller:
│     Current version:    1.4.2
│
└─SSD 960GB:
    Current version:    QDV1RE14
    Vendor:             ACME (NVME:0x1234)

Successfully downloaded new metadata: 3 local devices supported

ACME R740xd
│
└─System Firmware:
    Device ID:          8b6b5c1e...
    Current version:    2.19.0
    Update Version:     2.22.1
    Update Remote ID:   lvfs
    Update Checksum:    SHA256(9c1e...)
    Update Description: Fixes a memory training failure on
                        hosts populated with 16 DIMMs, and
                        includes microcode for CVE-2025-XXXXX.

Illustrative output

fwupd draws its metadata from the Linux Vendor Firmware Service, which covers a growing share of enterprise hardware. Where it does not, the vendor bundle is the path — a Dell System Update repository, an HPE Service Pack, a Lenovo update utility — and the discipline in this lesson applies unchanged.

Applying an update

# Update everything fwupd knows about, with confirmation prompts
sudo fwupdmgr update

# Or one device at a time, which is what you want in production.
# Take the ID from the get-devices output above.
DEVICE_ID=8b6b5c1e
sudo fwupdmgr install "$DEVICE_ID"

# For updates staged into the ESP and applied on the next boot
sudo fwupdmgr get-history

UEFI capsule updates do not apply when the command returns. fwupd writes the capsule to the EFI system partition and sets a flag; the firmware picks it up and flashes during the next boot, before any operating system runs. So the sequence is install, then reboot, then verify — and the verification is mandatory, because a capsule that the firmware rejected leaves you on the old version with a successful-looking command in your history.

# After the reboot
sudo dmidecode -t bios | grep -i version
fwupdmgr get-history            # did the capsule report Success or Failed?

Microcode is a special case

CPU microcode arrives two ways and the difference is operationally significant. The BIOS carries a copy, applied at POST. The distribution also ships one — intel-microcode or amd64-microcode — which the kernel loads from the initramfs very early in boot, overriding the BIOS copy when it is newer.

# What did the kernel load this boot?
sudo journalctl -k --grep='microcode'
grep -m1 microcode /proc/cpuinfo

# After installing the package, the initramfs must be rebuilt
sudo apt install intel-microcode
sudo update-initramfs -u

The OS-supplied microcode is re-applied on every boot and never persists in the CPU, so it is genuinely reversible: remove the package, rebuild the initramfs, reboot. That makes it the one firmware-adjacent change in this lesson with a real rollback, and it is why security microcode is normally shipped through the package manager rather than through a BIOS campaign.

Firmware version drift is a defect

Two nodes with identical package sets, identical configuration and different NIC firmware are not identical nodes. They will diverge under load, and the divergence will look like a load balancer problem or a noisy-neighbour problem for as long as nobody compares firmware.

Capture firmware versions in the same inventory export as everything else, and diff across the fleet:

# On the control node
ansible -i /etc/ansible/prod webservers -b \
  -m ansible.builtin.command \
  -a "dmidecode -s bios-version" \
  | sort | uniq -c

Any group of hosts that is supposed to be interchangeable and reports more than one BIOS version has a finding. It is not always worth fixing immediately, but it should be recorded, not discovered during an incident.

Firmware is a change like any other

Everything the rolling-maintenance part says applies here, and more strictly, because there is no rollback:

  • One node at a time. A firmware bug that bricks a NIC will brick every NIC you flash in that batch.
  • Health-gate between nodes rather than working to a timer.
  • Hold the first node longer than feels necessary. Storage and network firmware bugs are load-dependent, and a node that has not carried peak traffic has not been tested.
  • Record the versions before and after, per host, in the change record.

Knowledge check

Knowledge check · 4 questions

  1. Q1. sudo fwupdmgr install completes successfully for a system firmware update. What is the state of the host?

  2. Q2. If a firmware update causes a regression, fwupdmgr downgrade provides a reliable rollback.

  3. Q3. What should be done before updating BMC firmware on a cluster node? Select all that apply.

  4. Q4. Which firmware-adjacent update genuinely can be reverted, and why?

Passing score: 75%. Answers are checked in this browser.