Files
fips/docs/releases/release-notes-v0.5.1.md
T
Johnathan Corgan f0ee81ec7c Prepare the v0.5.1 release content
Move the staged changelog entries under a 0.5.1 heading dated 2026-09-06,
and add an entry for the deb-install hang: the suite started a oneshot unit
that requires the daemon, so a daemon that could not execute left the start
job undispatched and the suite reported nothing at all. That is the whole
class of fault the suite exists to find, and it protects the run that gates
artifact publication, so it is owed an entry.

Add the release notes and mirror them to the root file. The notes lead with
who should upgrade and who is unaffected, because for most users this
release changes nothing and for Debian 12 and Ubuntu 22.04 users the daemon
has never run at all. They state what was measured and what was not, and
give an objdump line that reads the floor of a binary already installed:
2.34 from this release, 2.39 from any earlier one.

The root mirror is not byte-identical to the versioned copy and cannot be.
The two files sit at different depths, so a link that resolves in one breaks
in the other; the mirror is content-identical with the relative link paths
rewritten, and the check is a diff whose every hunk is a link path. Here
that is two hunks, both confirmed to resolve.

The currency audit found five stale version sites and two claims that do
not match the tree, all corrected here. The status badge, the release-notes
link and the status sentence in the README follow the release, as they did
at v0.4.2. The FreeBSD install line gave a filename that does not exist,
since the tree is 0.5.1-dev; it now takes a version placeholder so it stops
going stale at every bump, and the example above it keeps a concrete name.

The design document recorded the first lookup fix and not the second: it
still said a returning copy is dropped as a duplicate, which the next commit
in this release exists to stop doing. It now names the counter that actually
receives the drop.

The README claimed the .deb is exercised per release. The install suite is
real and covers the five distributions it names, but it runs on push and
pull request, not at a tag, and no workflow installs the published artifact.
The sentence now says that, so the released package being checked by hand is
written down rather than assumed.

Getting-started gains the statement this release should have produced:
which distributions are supported and why the binaries run on all of them.
Until now the policy and the floor lived only in the build environment file,
so an operator had nowhere to read either.
2026-09-06 19:10:43 +00:00

8.8 KiB

FIPS v0.5.1

Released: 2026-09-06

v0.5.1 is a maintenance release on the v0.5.x line and it exists for one reason: every Linux artifact from v0.3.0 through v0.5.0 installs cleanly on Debian 12 and Ubuntu 22.04 and then cannot start. The package installs, the package manager reports success, and the daemon fails to load with GLIBC_2.39 not found. If you run FIPS on either of those distributions from a published package, you have never had a working daemon, and this release is the fix.

It carries two discovery fixes as well, one of them an external contribution. There is no wire format change and no new configuration.

At a glance

Who should upgrade

  • Debian 12 and Ubuntu 22.04, from a package: upgrade. The daemon on those systems has never run. Nothing you can configure works around it.
  • Any other Linux: upgrade at your convenience. Your daemon was running, and you gain the two discovery fixes.
  • macOS, Windows, FreeBSD and OpenWrt: nothing changed for you. The defect was in how the Linux artifacts were built. Those artifacts are rebuilt from the same source and are otherwise as v0.5.0 shipped them.
  • From source: you were never affected. A binary you built runs against the C library you built it on.

Before you upgrade

Nothing to do. No configuration key was added, removed or given a new meaning, and no configuration that loaded under v0.5.0 fails to load here.

What changed

  • Linux packages and the systemd tarball now install and run on Debian 12 and Ubuntu 22.04.
  • A node no longer relays away the answer to its own lookup.
  • A returning copy of a node's own lookup request is no longer counted against the peer that delivered it.

The Linux packaging defect

What went wrong. Every Linux artifact from v0.3.0 onward was built on the newest available runner. That runner's C library turns the standard library's pidfd references into a hard GLIBC_2.39 version requirement, instead of the weak, runtime-checked references they are meant to compile to. The loader refuses an image on that entry alone, so fips, fipstop and fips-gateway could not start on any system with an older C library. fipsctl was unaffected, which is why an install checked by running a command looked healthy while the daemon was dead.

No source code caused this and none was changed. The defect was in the build environment, and the release contains no behavioral change to the daemon.

Why the declared dependency did not stop it. The .deb said it needed libc6 with no version, which every glibc satisfies. So a package whose binaries required 2.39 installed happily on a system with 2.35.

What is different now. The Linux artifacts are built in a container pinned to the oldest supported distribution, declared in packaging/build-floor.env. Every producer runs testing/check-glibc-floor.sh on what it made, so an artifact that would not load fails the build rather than reaching you. The declared dependency is derived from the binaries themselves rather than written by hand, so it states the floor it was actually built against and re-derives per architecture. One script now produces the Linux artifacts, and the systemd tarball takes its binaries out of the package rather than from a second, unchecked set.

What was measured. The .deb and the tarball were built and floor checked on x86_64 and aarch64; both architectures carry a 2.34 floor, which clears the 2.35 the packaging declares. Five distributions install the package and start the daemon in CI. Separately, a project that consumes FIPS inside an initramfs reports five machines of five unlocking an encrypted root over the mesh, including Debian 12 and Ubuntu 22.04, both of which fell back to a console prompt on v0.5.0.

What was not measured. No published v0.5.1 artifact existed when this was written; the checks above ran against artifacts built by the same scripts the release workflow uses. Reproducibility was measured same-machine at v0.4.2 and cross-machine reproducibility has never been tested.

Discovery fixes

A node relayed away the answer to its own lookup

A lookup request is flooded to every tree peer whose bloom filter claims the target, so a false positive can send a copy into the wider network and circulate it back to the node that started it. The only identity test on arrival asked whether the request named this node as the target, which a lookup this node originated never satisfies. The returning copy was therefore filed as ordinary transit under the node's own request id. When the target answered, the reply was reverse-path forwarded to the peer that had looped the request back, the pending lookup was never satisfied, and discovery reported that its requests went unanswered while the answers were in fact arriving.

An inbound response is now matched against this node's outstanding lookups before the transit dedup record, and a returning copy of the node's own request is dropped rather than recorded, so that id never enters the transit cache.

This was a race rather than a hard failure: a reply that beat the looped copy found a clean cache and succeeded. It grew likelier as the bloom fill ratio rose, which means it got worse as a mesh grew. Contributed by Arjen.

req_duplicate counted something it does not mean

The fix above drops the returning copy, and it first recorded that drop under the existing req_duplicate rejection, whose documented meaning is that a peer resent a request. A returning copy has a nonzero floor in healthy operation and rises with the bloom fill ratio, so folding the two together put a permanent number on a counter an operator reads as neighbour misbehaviour, and made the two events indistinguishable.

It now has its own rejection reason and counter, req_own_loopback, shown in fipstop as "Own Loopback". req_duplicate returns to meaning only what it says.

If you watch these counters, expect req_duplicate to drop and a new non-zero Own Loopback to appear. That is the same traffic, correctly attributed, not a new fault.

Compatibility

v0.5.1 is wire-compatible with v0.5.0. No frame gains, loses or resizes a field, so a mixed mesh works and nodes can be upgraded one at a time with no coordinated restart. The two discovery changes alter what a node does with a message it already parsed; neither changes what is on the wire.

The library surface is unchanged. Configuration is unchanged.

Upgrade notes

Package upgrade, Debian and Ubuntu. The usual upgrade replaces the binaries and restarts the service. On Debian 12 and Ubuntu 22.04 the daemon will start for the first time, so this is a first start rather than a restart: check fipsctl status afterwards and expect to see peer establishment, not a resumed session.

Check what you actually have. If you want to confirm the floor of an installed binary rather than trust the version string:

objdump -T /usr/bin/fips | grep GLIBC_ | sed 's/.*GLIBC_//' | sort -uV | tail -1
```text

An artifact from this release reports 2.34. One from v0.5.0 or earlier
reports 2.39.

**Rolling upgrade.** No coordination is needed. Upgrade nodes in any
order.

## Getting v0.5.1

- **Linux x86_64 / aarch64**: `.deb` and tarball at the
  [v0.5.1 release page](https://github.com/jmcorgan/fips/releases/tag/v0.5.1).
- **Arch Linux**: `fips` from the AUR.
- **macOS**: `.pkg` at the v0.5.1 release page.
- **Windows**: ZIP at the v0.5.1 release page.
- **FreeBSD (x86_64)**: `.pkg` at the v0.5.1 release page.
- **OpenWrt**: `.ipk` (OpenWrt 24.x and earlier) or `.apk` (OpenWrt 25+)
  at the v0.5.1 release page.
- **From source**: `cargo build --release` from a checkout of the v0.5.1
  tag (Rust 1.94.1 per `rust-toolchain.toml`; `libclang-dev` is a
  required Linux build prerequisite).
- **Nix / NixOS**: `nix build .#fips` from a checkout of the v0.5.1 tag
  builds the binaries from source with the pinned toolchain and no
  manual prerequisites (see the Nix section of `packaging/README.md`).

There is no Android daemon artifact. Android is supported as an embedded
crate.

The full per-commit changelog lives in
[`CHANGELOG.md`](../../CHANGELOG.md). Issues and discussion at
[github.com/jmcorgan/fips](https://github.com/jmcorgan/fips). Security
reports have a private channel; see [`SECURITY.md`](../../SECURITY.md).

## Contributors

Thanks to everyone who contributed code, packaging work, bug reports, or
reviews to this release.

- [@jmcorgan](https://github.com/jmcorgan) (Johnathan Corgan): release
  shepherd; the Linux build and floor-checking work, the loopback
  rejection counter, and the install-suite fix that made the defect
  visible instead of hanging.
- [@Origami74](https://github.com/Origami74) (Arjen): the lookup
  originator fix, so a node accepts the answer to its own lookup instead
  of relaying it away
  ([#141](https://github.com/jmcorgan/fips/pull/141)).