Skip to content

fix(linux): verify the FFmpeg download against a pinned checksum - #530

Merged
thcp merged 1 commit into
0.16.1from
fix/518-linux-ffmpeg-checksum
Aug 31, 2026
Merged

fix(linux): verify the FFmpeg download against a pinned checksum#530
thcp merged 1 commit into
0.16.1from
fix/518-linux-ffmpeg-checksum

Conversation

@thcp

@thcp thcp commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes #518. Targets fix/516-drain-child-pipes -- last of the sequential Rust changes. Merge #529 first.

The problem

download_linux_ffmpeg fetched a tarball from a rolling URL on a single non-CDN host, extracted it with the system tar, marked the binaries executable and ran them -- with no integrity check of any kind.

  • Windows verifies against BtbN's published checksums.sha256
  • macOS verifies against four pinned hashes
  • Linux verified nothing

verify_ffmpeg only proves the binary runs and has the encoders StemDeck needs. That says nothing about where it came from.

Why a pinned SHA256 rather than upstream's .md5

The obvious move was the .md5 companion, matching the Windows shape. I checked it and it is worth less than it looks:

  • MD5 is broken for collisions
  • The companion is served by the same host as the tarball. Anyone able to replace one can replace the other. It evidences corruption, not authenticity.
  • Upstream publishes no .sha256 (confirmed: 404)

So this pins our own SHA256, the way the macOS path already does. The pinned value was computed from the artifact whose MD5 matched upstream's published 7fa72b652e19bf84c9461e332ea1cdf3, so the pin is anchored to what upstream currently vouches for.

url    .../ffmpeg-release-amd64-static.tar.xz   (last-modified 2024-08-24)
md5    7fa72b652e19bf84c9461e332ea1cdf3          (matches upstream)
sha256 abda8d77ce8309141f83ab8edf0596834087c52467f6badf376a6a2a4c87cf67

Trade-off: the URL is rolling, so this needs a manual bump when upstream publishes a new build. A stale pin fails closed with a checksum error rather than silently accepting whatever arrives, which is the right direction to fail. STEMDECK_FFMPEG_URL still overrides and skips the check -- an override points somewhere we cannot have a hash for, matching how the macOS override already behaves.

Verification -- and a gap reviewers should know about

This code cannot be compiled on macOS, and ci.yml does not build the Rust shell at all -- Linux Rust is compiled only by linux-release.yml, at release time. So a type error here would first surface during a release.

To check it locally I temporarily widened the cfg gate on the two constants and download_linux_ffmpeg from #[cfg(all(unix, not(target_os = "macos")))] to #[cfg(unix)] and ran cargo check:

error count: 0

Then restored all 7 gates (verified by count).

cargo fmt --check   OK
cargo clippy        0 errors
cargo test          59 passed, 1 failed (the known port flake, fails on base too)

Worth filing separately

There is no linux-check.yml. #421 added macos-check.yml and windows-check.yml precisely because ci.yml is 100% ubuntu and could not compile cfg-gated code for those platforms -- but nothing compiles the Linux Rust either, despite the runner being ubuntu. That is a real hole and it is what made this PR awkward to verify. Happy to open an issue.

@thcp
thcp force-pushed the fix/516-drain-child-pipes branch from e24e0a7 to 845b5ac Compare August 31, 2026 21:10
Base automatically changed from fix/516-drain-child-pipes to 0.16.1 August 31, 2026 21:13
@thcp
thcp marked this pull request as ready for review August 31, 2026 21:13
download_linux_ffmpeg fetched a tarball from a rolling URL on a single host,
extracted it with the system tar, marked the binaries executable and ran them,
with no integrity check of any kind. Windows verifies against BtbN's published
checksums.sha256 and macOS against four pinned hashes; Linux verified nothing.
verify_ffmpeg only proves the binary runs and has the encoders we need, which
says nothing about where it came from.

Pinned rather than verified against upstream's .md5 companion, which was the
obvious move but is worth less than it looks: MD5 is broken for collisions,
and the companion is served by the same host as the tarball, so anyone able to
replace one can replace the other. It evidences corruption, not authenticity.

The pinned hash was computed from the artifact whose MD5 matched upstream's
published 7fa72b652e19bf84c9461e332ea1cdf3, so this pin is anchored to what
upstream currently vouches for.

The URL is a rolling one, so this needs a manual bump when upstream publishes
a new build; the current one is dated 2024-08-24. A stale pin fails closed
with a checksum error rather than silently accepting whatever arrives.
STEMDECK_FFMPEG_URL still overrides, and skips the check -- an override points
somewhere we cannot have a hash for, so vouching for it is the caller's
business, matching how the macOS override already behaves.

Note this code cannot be compiled on macOS or by ci.yml, which does not build
the Rust shell at all. It was type-checked by temporarily widening its cfg
gate to #[cfg(unix)]; cargo check reported no errors.

Refs #518
@thcp
thcp force-pushed the fix/518-linux-ffmpeg-checksum branch from 474b483 to 1ab8c74 Compare August 31, 2026 21:14
@thcp
thcp merged commit aaead5c into 0.16.1 Aug 31, 2026
3 of 10 checks passed
@thcp
thcp deleted the fix/518-linux-ffmpeg-checksum branch September 3, 2026 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant