Skip to content

Bare metal: a key is made only from a hardware generator - #1051

Merged
pdfinn merged 5 commits into
masterfrom
claude/kind-euler-f3ufm5
Nov 3, 2026
Merged

pdfinn merged 5 commits into
masterfrom
claude/kind-euler-f3ufm5

Conversation

@pdfinn

@pdfinn pdfinn commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Summary

On bare metal, a key is now made only from a hardware generator. A board whose generator is missing or not working used to hand libsec's key generators, #c/notquiterandom and #c/random a predictable counter after one console line. It now fails closed. The Pi's generators are also read under a lock, and the RNG200's own health-test flags are now heeded.

This follows up the open question left in #658, now that the Pi boards are real. Refs: INFR-404, INFR-342 (F2/F4).

Changes

  • os/port/random.c now owns genrandom, prng and prngtry, which all six boards had copied. genrandom waits for real bytes and says why every five seconds. prngtry answers -1 at once with no generator, as libsec.h documents.
  • The hwrandom contract: bytes (>0), dry (0), or no generator (-1). It never makes bytes up.
  • insecurerandom on the boot command line gives an emulator a labelled counter. The harness passes it to QEMU's raspi4b, and os/mpfs/qemu-icicle.dts sets it. A board's cmdline.txt must not.
  • os/port/devcons.c: the seed behind nrand, used for port and TCP sequence numbers, no longer reads the pool, so networking never waits.
  • os/bcm/rng200.c (new) is shared by the Pi 4 and, once its port merges, the Pi 5. It sits at the board's RNG200REGS, reads a word under a lock, and resets the block when the NIST-fail or lockout flag is set, as Linux's iproc-rng200 does. os/bcm2711/random.c is removed. The BCM2837 leaves the file out.
  • os/bcm2837/random.c: the check for a word and its read are one step under a lock, and the spin counter is per call.
  • os/mpfs/random.c: -1 when the nonce service refused at boot. If the service stops later, keys wait instead of switching silently to the counter.
  • os/virt/random.c, os/riscvvirt/random.c: -1 with no source. Calls before the probe read as dry.
  • Docs: the changelog, docs/TLS-ENTROPY.md (whose opening table was stale), docs/BAREMETAL-BOARD-INTERFACE.md, and the board READMEs.

Testing

Run locally under QEMU: 9.2.4 with the repo's patches for AArch64, 8.2 for RISC-V.

  • tests/host/baremetal_test.sh: 527 passed, 1 failed, 1 skipped.
    • The failure is the bcm2837 JIT nil-dereference check. Its output has every expected line, but the shell prompt landed at the start of one, and the check matches at line start. I did not rerun it on master.
    • The skip is the fsck.fat image check.
  • tests/host/baremetal_riscv64_test.sh: 70 passed, 0 failed, 0 skipped.
  • New on virt with no virtio-rng: the machine reaches its shell; reads of /dev/notquiterandom and /dev/random wait and say why; no counter appears; nothing panics. With insecurerandom, both answer and the counter is labelled.
  • raspi4b reaches the Lucifer desktop with insecurerandom and checks the label. So does the Icicle Kit.
  • The Pi 5 (feat/pi5-port with this merged, plus a small patch) builds with the shared driver.

Not verified:

  • Nothing has booted on a physical board.
  • The RNG200 health-flag reset has never executed: QEMU has no RNG200.
  • The Pi 4's fail-closed path is not covered under QEMU on its own, since every Pi 4 boot passes insecurerandom. Only virt checks the refusal.

Checklist

  • Code follows the existing style of the file(s) modified
  • No .dis build artifacts committed from appl/ or tests/
  • Documentation updated
  • No secrets, API keys, or credentials included

Follow-ups (not in this PR)

  • The Pi 5 adaptation (delete os/bcm2712/random.c, add RNG200REGS) belongs on feat/pi5-port once it takes this.
  • A ChaCha20 conditioner in front of the hardware and a repeat-word health test on raw output.
  • An SP 800-90B measurement on each board.

🤖 Generated with Claude Code

https://claude.ai/code/session_0195u6z4TJx1xi2fTM3X596h

… are read under a lock

Three faults in the bare-metal random sources, found reading them now
that the boards are real (#658 left the Pi's open question for a board).

Fail closed. A board with no working generator -- the Pi 4's RNG200 not
answering, the PolarFire's nonce service refusing, a QEMU virt without
virtio-rng -- handed libsec's key generators, #c/notquiterandom and
#c/random a counter stirred with the time, after one line on the
console. The PolarFire did the same if its service stopped after boot.
On a board that means a driver or map at fault; on a Pi 5, which no
emulator models, it could mean nothing else. hwrandom now never makes
bytes up: it returns -1 when the machine has no generator. genrandom,
prng and prngtry, which all six boards copied, move to os/port/random.c,
wait for real bytes and say why every five seconds; prngtry answers -1
at once, as libsec.h says it does. The machine still boots and talks to
the network: devcons.c's seedrand, behind nrand's port and sequence
numbers, no longer reads the pool. The word "insecurerandom" on the
command line gives an emulator the labelled counter; the harness passes
it to raspi4b and qemu-icicle.dts says it.

Locks. The Pi 3 and Pi 4 drivers tested for a word and read it with no
lock, on four cores with preemption: two readers could both see one word
waiting and both read it, and what an empty FIFO reads as is not
documented. The test and the read are now one step under an ilock.

The RNG200's health test. It reports a failed NIST test in its
interrupt status; nothing read it. As Linux's iproc-rng200 does, a
failure now resets the block before another word is taken. The driver
moves to os/bcm/rng200.c for the Pi 4 and the Pi 5, at the board's
RNG200REGS; the BCM2837 leaves it out.

Tests: a virt boot with no virtio-rng reaches its shell, refuses key
material and #c/random alike and says why; with insecurerandom both
answer and the counter is labelled. raspi4b and the Icicle Kit check the
label.

Refs: INFR-404 INFR-342

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195u6z4TJx1xi2fTM3X596h
…rerandom

The release card's Pi 4 boot under QEMU failed on #1051 (bcm2711 job):
QEMU's raspi4b models no RNG200, so the machine has no entropy source,
and the kernel now makes no key on such a machine. The first-boot login
waited for one, and so did DNS, whose query ids come from /dev/random --
the profile names the LLM server, so the serial shell never answered.

A board has the generator, so the card is right as it is: its cmdline.txt
does not say insecurerandom, and must not. The emulator lacks it, so the
word goes on QEMU's command line, as baremetal_test.sh's raspi4b boots
already do. raspi3b models the BCM2835's generator and is unchanged.

Reproduced locally (QEMU 9.2.4, the repo's patches): rpi4b 12/3 before,
15/0 after; rpi3bplus 15/0.

The changelog and os/port/random.c said a machine with no generator
"still uses the network": the kernel's does, and DNS waits. Now they say
so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195u6z4TJx1xi2fTM3X596h

pdfinn commented Nov 1, 2026

Copy link
Copy Markdown
Member Author

iOS Build & Simulator Test is red here, and it is not this PR's.

  • What fails: the app builds and installs on the simulator, then verify gets an empty console and no hello_test PASS. It reports VERIFY FAILED: expected test PASS output not found (job).
  • The base is red the same way. Master's head, 62ce2a6, fails the same job with the same empty console and the same line (job). It passed on 5ca892f, this PR's original base.
  • The diff can't reach it. This PR changes only the bare-metal kernels under os/, their QEMU tests, and docs. The iOS app builds the hosted emulator (emu/) and bundles dis, tests and lib, none of which changed. Master's commits since 5ca892f are Raspberry Pi Imager metadata, which doesn't reach iOS either.
  • No fix exists yet. I could not re-run the job, because this integration gets a 403 on re-runs.

The earlier red, on the bcm2711 job, was this PR's: the release's Pi 4 card was booted under a QEMU with no RNG200, and d580729 fixes it.


Generated by Claude Code

#1037, #1038, #1039 and #1040 merged around the registry (#1036), so
master's devletters_test failed: #K prof, #X vm, #x bench, #z wmsz and
#h tfa were in use and still "reserved" here. Their rows are in use;
#P is arch only; #b, #w and #F are free here, at their precedents'
meanings, #w and #F now reserved for a watchdog and flash. The planned
moves are the moves made.

tools/devletters.py --check: PASS, 36 letters in use across 20 builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T5tjh7MFpJjYJnvTT33utv
(cherry picked from commit d147d1b)

pdfinn commented Nov 1, 2026

Copy link
Copy Markdown
Member Author

Linux AMD64 Host Tests (1) is red with two failures, and neither is this PR's. Master's head, 62ce2a6, fails the same shard with the same two tests (job).


Generated by Claude Code

pdfinn commented Nov 1, 2026

Copy link
Copy Markdown
Member Author

macOS ARM64 Build & Test went red on d580729, but none of its build or test steps failed. The one failed step is "Upload macOS build artifacts" (step 20): Failed to CreateArtifact: Unable to make request: ECONNRESET, a connection reset during the upload to GitHub (job).

The wallet persistence lines in that log are marked non-fatal in CI, and master's passing run of this job prints the same ones. That head has been superseded by 87c4d6d, which runs the job again. I can't re-run jobs from this session; the integration gets a 403.


Generated by Claude Code

pdfinn commented Nov 1, 2026

Copy link
Copy Markdown
Member Author

macOS ARM64 Build & Test and iOS Build & Simulator Test never ran on 87c4d6d. GitHub cancelled both after 15 minutes: "The job was not acquired by Runner of type hosted even after multiple attempts," with a macOS arm64 capacity warning. Neither has a result to judge.

They need a re-run. I can't trigger one from this session, because the integration gets a 403.

The rest of CI on this head: every bare-metal job passed (bcm2837, bcm2711 with the card boot, virt, and both RISC-V jobs). devletters_test now passes. The only test failure left is tools9p_integration_test, which is red on master too, as described above.


Generated by Claude Code

pdfinn commented Nov 2, 2026

Copy link
Copy Markdown
Member Author

Linux AMD64 SDL3 GUI Build & Test timed out on 87c4d6d, and the base is red in the same step.

  • What happened here: the job hit its 60-minute limit inside "Run Xenith and display host tests" (step 17). GitHub keeps no log for it (BlobNotFound), so I can't name the test that ran long.
  • Master is red in the same step. On master's head, 62ce2a6, that step failed with wmsize_test: FAIL: /dev/wmsize gave '', want 'm 640 400 ...' (job).
  • The diff can't reach it. This PR changes only the bare-metal kernels under os/, their QEMU tests and docs. The GUI job builds and runs the hosted emulator, Xenith and the display tests, none of which this PR touches.

No fix exists that I can port. I can't re-run the job from this session.


Generated by Claude Code

pdfinn pushed a commit that referenced this pull request Nov 3, 2026
The Pi 5 takes the shared generator, os/bcm/rng200.c, by naming where it
is, and loses its own copy of what os/port/random.c now owns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195u6z8JjsAy9yrE5TqKxzx
pdfinn and others added 2 commits November 3, 2026 08:38
docs/DEVICE-LETTERS.md: master's, from #1052, which makes the same five-row update this branch made to get devletters_test passing (prof #K, vm #X, bench #x, wmsz #z, tfa #h). tools/devletters.py --check passes. The merge also brings in #1052 and #1053, which fix the master failures this PR showed in Host Tests (1) and the SDL3 GUI job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195u6z6W3TbdAx7jg6RqhYy
@pdfinn
pdfinn merged commit e5bdc52 into master Nov 3, 2026
34 checks passed
@pdfinn
pdfinn deleted the claude/kind-euler-f3ufm5 branch November 3, 2026 07:14
pdfinn added a commit that referenced this pull request Nov 7, 2026
The Pi 5 half of #1051 (keys from a hardware generator alone), which
integ/pi5-all took in its merge of it (462c72b) and the soaked build
ran: the board's own random.c goes, the RNG200's registers are named for
../bcm/rng200.c, and the README says so. Master has #1051 but not this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195u6z8JjsAy9yrE5TqKxzx
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.

3 participants