Skip to content

kryptik-recover verifies a slot against the signed command line before it commits it - #231

Merged
DevomB merged 4 commits into
mainfrom
recover-verify
Oct 7, 2026
Merged

DevomB merged 4 commits into
mainfrom
recover-verify

Conversation

@DevomB

@DevomB DevomB commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

kryptik-recover --restore-slot checked the slot it wrote only against the medium's root.json, which is not signed. Someone who can write to a medium could alter its root image and rewrite root.json's sha256 and total_bytes to match. The slot then read back as matching, was committed, and the tool said done: boot ... without the medium. dm-verity still stops that disk at its first bad block, so integrity holds, but the tool reports success for a disk that may not boot. The installer already ran veritysetup verify against the root hash in the medium's signed command line; recovery never did. Both tools also copied the medium's slot kernel with nothing tying it to that root.

What changed:

  • build/service-scripts/medium-root.sh (new, installed in /usr/libexec/kryptik/ with the other scripts) holds the installer's checks of root.json, and both tools source it. Every field gets a form check before it is used, so a root_hash that is not a hash is refused without being printed. The record must name the root hash and data blocks in the medium's signed command line. kernel_names_root requires a slot kernel to embed that hash, as kryptik-update requires of a payload's kernels. root_verifies runs veritysetup verify with the signed table.
  • kryptik-recover --restore-slot checks the record and the slot kernel before it writes, keeps the read-back, and runs veritysetup verify before the ESP names the slot again. When verification fails it refuses with the reason; nothing is committed and the ESP names no kernel for that slot, so --commit-slot takes nothing either.
  • kryptik-install checks both medium kernels before its first write (the ISO's ESP image is loop-mounted read-only for that). It also lists veritysetup and grep in its up-front tool check, which it did not, though it already ran veritysetup.
  • The design doc's installer section and the user guide's recovery section say what is checked. A kernel's signature remains the firmware's to check, at boot: the image has no sbverify, and the medium's certificate sits on its unsigned ESP.

How the run proves it: integrity-test.sh step 4 first boots a copy of the medium altered as described. It changes one byte in a free block from the middle of the root's ext4 (found with debugfs ffb on a read-only loop device; nothing reads it at boot, but verity covers it) and rewrites root.json's sha256 to match. The step expects KRYPTIK_RECOVER: rc=1 with the verify refusal, and no kernel for slot a on the disk's ESP. The code before this change reports success on that medium. The step's restore from the unaltered medium then runs as before, which also exercises the kernel check on the real slot kernel. tools/tests/installer.sh gains cases for the record and kernel checks (47/0 locally; with the root_hash form check or the kernel check removed, the matching case fails).

Merged with main at a8ed377 (84f9fd3): #217's inline form checks of root.json in kryptik-recover give way to medium_root, which makes them and ties the record to the signed command line; medium_root takes #217's rule that a record must name a version; the installer's tool list is main's with grep.

Distro run 37573380829 at a8ed377: every part green, the verdict included. integrity-test 40/0: "a medium whose root is not the one its signed kernel names is refused, though its root.json was rewritten to match", "the refused restore left the ESP naming no kernel for slot a, so --commit-slot a takes nothing", and the restore from the unaltered medium succeeded. Since then one comment line: 1b83297 adds a shellcheck directive in tools/tests/installer.sh (SC2034 on V_HASH, read only by the sourced kernel_names_root). CI green at 1b83297. Merges into main 1f28250 without conflict.

DevomB added 4 commits October 6, 2026 21:22
…e it commits it: --restore-slot took the medium's unsigned root.json at its word, so a medium whose root was altered and whose root.json was rewritten to match was written, read back as matching, and committed as a disk that boots

The installer's checks of root.json move into build/service-scripts/medium-root.sh, which kryptik-install and kryptik-recover both source: every field has its form before it is used (a root_hash that is not a hash is refused without being printed), the record must name the root hash and size in the medium's signed command line, each slot kernel copied from the medium must carry that hash, and veritysetup verify runs on what was written before anything names it. The installer now checks both medium kernels before its first write (the ISO's ESP image is mounted for that) and lists veritysetup and grep among the tools it checks up front.

integrity-test.sh step 4 first boots a copy of the medium with one byte changed in a free block of its root and root.json's sha256 rewritten to match, and expects the restore refused and the ESP naming no kernel for slot a; tools/tests/installer.sh covers the record and kernel checks.
… source: medium-root.sh is sourced by kryptik-install and kryptik-recover, which installer-run runs, and the rule knew only helpers that service scripts source
…json in kryptik-recover give way to medium_root, which makes the same checks and ties the record to the signed command line, and medium_root takes #217's rule that a record must name a version; the installer's tool list is main's with grep
…rced kernel_names_root: CI's shellcheck took it for unused, which the fixture step's earlier failure had hidden
@DevomB
DevomB marked this pull request as ready for review October 7, 2026 08:27
@DevomB
DevomB merged commit 40b3f3a into main Oct 7, 2026
11 checks passed
@DevomB
DevomB deleted the recover-verify branch October 7, 2026 15:36
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