Skip to content

Build the same enclave image on every machine - #7

Merged
aruokhai merged 1 commit into
mainfrom
reproducible-zfs-modules
Oct 15, 2026
Merged

aruokhai merged 1 commit into
mainfrom
reproducible-zfs-modules

Conversation

@aruokhai

Copy link
Copy Markdown
Contributor

The same commit (c4a0b96) measured to two PCR0s: 458969f7… built by CI, and 7bdd3f85… built on a workstation. PCR0 is what KMS releases the key against and what clients pin, so it has to come out the same for anyone who rebuilds.

What differed

I extracted both EIFs section by section:

  • kernel, cmdline and ramdisk1 were identical.
  • In ramdisk2, every file but two was identical: lib/zfs/spl.ko and lib/zfs/zfs.ko.

ZFS's assertions use __FILE__, so the modules contain the directory they were compiled in. That is /build/source/module/… in a sandboxed Nix (CI) and /tmp/nix-build-zfs-kernel-2.4.3-6.6.150.drv-0/source/module/… in a Nix without a sandbox (the workstation runs nix-portable).

The fix

  • nix/kernel-zfs.nix: the ZFS module build gets KCFLAGS=-ffile-prefix-map=$NIX_BUILD_TOP=/build, which maps the build directory to the sandbox's own path. A sandboxed build is unchanged by it.
  • nix/eif.nix: faketime '1970-01-01 00:00:01' instead of '@…'. With @, faketime starts the clock there and lets it run, so BuildTime in the image metadata differed in its nanoseconds. No PCR covers that metadata, but it kept the two files from being byte-identical.

What was run (on the workstation, Nix without a sandbox)

  • nix build .#eif-qemu gives PCR0 458969f7226521dfacf5aa0a1988d1193420d6e441d188d0e51dd11e53b585711f288e4a4924572768427653df3e05c3, CI's published value. Every measured section is byte-identical to CI's image.
  • nix build .#eif-qemu --rebuild passes: two builds produce the same file.
  • Since the mapping changes nothing in a sandbox, the PCR0 of images already built in one, CI's and production's, stays what it was.

What was not run

  • .#eif, the production image, separately. It takes its ZFS modules from the same kernel-zfs.nix.

🤖 Generated with Claude Code

The same commit measured to two PCR0s: 458969f7 from CI, 7bdd3f85 from a
workstation. Taking both images apart, the kernel, the command line, the
boot ramdisk and every file of the rootfs but two were identical. The
two were the ZFS modules, spl.ko and zfs.ko: ZFS's assertions carry
__FILE__, so the modules recorded where they were compiled, /build/source
in a sandboxed Nix and /tmp/nix-build-zfs-kernel-…/source in one
without a sandbox.

The module build now maps its build directory to /build, the sandbox's
own path. A sandboxed build is unchanged by it, and a workstation's now
measures to CI's PCR0: 458969f7 from both. PCR0 for every image already
built in a sandbox stays what it was.

eif_build's clock is also frozen rather than started at the epoch: with
the @ faketime let it run, and BuildTime's nanoseconds differed between
builds. That is metadata, which no PCR covers, but it kept the files from
being identical; `nix build .#eif-qemu --rebuild` now passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aruokhai
aruokhai merged commit 0022862 into main Oct 15, 2026
3 checks passed
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