Repository navigation
soc: apple: sep: open the boot policy window for Touch ID's designate - #1340
Conversation
There was a problem hiding this comment.
The code change looks right: activate_touchid() now runs DESIGNATE_KEYBAG for the recovered keybag inside xart_guard::policy_window(), before sks_machine_refkey(), and the window is still one per boot. The new test_policy_window.py is wired into sep-source.yml and passes.
One thing to change before merge: the text refers to the issue as a bare #1190, which on this repository resolves to another project. Please replace it with #1190 (or drop it, since the Link: trailers already carry the URL) in:
- the body of commit 5c0e33e (
This is what #1190 reports on a J616s) - the body of commit 4858214 (
This happened on a J616s (#1190)) tools/aurora-sep/XART-SAFETY.md(enrolment of a Stage 1 that day (#1190))- the docstring of
tools/aurora-sep/tests/test_policy_window.py(when Touch ID comes up first (#1190))
This is a reword only, so the code does not change.
The boot policy window covers the first unlock of the identity keybag. When Touch ID brings the keybag up before any trusted key is unsealed, its first use under a new policy is the DESIGNATE_KEYBAG in activate_touchid() instead, and the enclave asks for its one rewrite there. On a MacBook Air M3 (J613) that offers Touch ID at the login screen, the first boot of integration/aurora 11eccbe after a change from a raw m1n1 Stage 1 to a Mach-O one logged, after LOAD_KEYBAG answered: xART guard: refused to rewrite kind-4 record <id>, which this Linux install did not create sks: DESIGNATE_KEYBAG got no reply after 2037 ms sks: DESIGNATE_KEYBAG did not complete; enrolment will refuse hwrng: read produced nothing (ETIMEDOUT) This is what #1190 reports on a J616s. aurora-sep-policy-change with no arguments armed the refused record, and the next boot rewrote it and restored the enrolment. A planned change does not need the lost boot. Say how to avoid it: arm --expect before the change, on whatever kernel is running, then make the first boot afterwards a kernel with the allowance code. A kernel without that code does not read the allowance; with the guard on it refuses the rewrite and leaves the allowance for a later boot. On a second Stage 1 change on the same J613, armed this way from a kernel without the allowance code, Touch ID survived the first boot with no refusal. Also say that the tool finds nothing to allow on a kernel whose refusal line has no session id, and that the keybag's first use can be the designate. Link: #1190 Signed-off-by: Satya Benson <satya@benson.earth>
After a boot policy change the enclave rewrites one existing kind-4 session record the first time Linux's identity keybag is used under the new policy. Commit e89d4a2 ("soc: apple: sep: let a boot policy change update its xART record") lets that rewrite through in a window around the first unlock, CHANGE_LOCK_STATE in refkey.rs. When Touch ID comes up before any trusted key is unsealed, the keybag's first use is the DESIGNATE_KEYBAG in activate_touchid() instead, which runs outside the window. The guard refuses the rewrite, the designate is never answered, and Touch ID stays off on every boot until aurora-sep-policy-change is run. This happened on a J616s (#1190) and on a MacBook Air M3 (J613), each after a Recovery enrolment of a new Stage 1. On both, the refusal comes after LOAD_KEYBAG has answered and before DESIGNATE_KEYBAG times out: xART guard: refused to rewrite kind-4 record <id>, which this Linux install did not create sks: DESIGNATE_KEYBAG got no reply after 2037 ms sks: DESIGNATE_KEYBAG did not complete; enrolment will refuse Both use the variant-5 key store, where activate_touchid() is the only sender of DESIGNATE_KEYBAG. Run that designate in policy_window() too. The window itself is unchanged: one per boot, opened by whichever comes first of that designate and the first unlock of an identity keybag that already existed, and kept shut by a keybag or ref-key created earlier in the boot. activate_touchid() designates before it can create the machine ref-key. Inside the window the guard still lets through one rewrite of one kind-4 record that existed at probe, never a delete or a shared root, only once its previous value is saved, and without adding it to Linux's list. Under an unchanged policy that designate rewrites no existing record. The guard is on by default on both Macs, and a refused write there leaves the designate unanswered, yet every Touch ID boot without a policy change brings the enrolment up. A host test checks that activate_touchid() designates a keybag it recovered, inside the window, before the machine ref-key, and that the only other designate runs in a ref-key path that holds the window or has closed it. Run it in the SEP source checks. Fixes: e89d4a2 ("soc: apple: sep: let a boot policy change update its xART record") Link: #1190 Signed-off-by: Satya Benson <satya@benson.earth>
4858214 to
0f3fda0
Compare
|
Replaced all four bare issue references with #1190, including both commit messages. This is text-only; the policy-window test still passes (4/4). |
|
GPT-6.1 Sol on @satchlj's behalf 2026-11-10 J613 boot/no-finger re-test with #1340 head 0f3fda0. RTC set correct time before userspace; fprintd and aurora73-touchid-gate reported success. Persistent Claim/VerifyStart/VerifyStop/Release succeeded, sensor registration completed and all traced SPI messages completed at full length with #1491 included. The new-default reboot repeated the service/gate and sensor-start checks. No finger match or enrollment was attempted; protected fingerprint/SEP state directories were not read. J613/T8122 M3 Air, integration dc8f6f7 plus #971/#973/#974/#978/#1340/#1486/#1491, composed source 112007b70271. Hardware-tested release 7.3.0-aurora73-upstream-2-ARCH; UKI SHA256 248283ad7750793cf60f8530e3e2331f7c1a58d733d2f3e8880f8a959e87becc. Composition evidence, not an isolated PR kernel. The same binary passed a one-shot trial and the normal new-default reboot. Installed package revision 30.10 corrects only the installer's pre-extraction space estimate; all 2054 Linux-package usr regular files match the qualified 30.9 package. Stage1/Stage2 unchanged, four boot hooks masked. |
DjDeveloperr
left a comment
There was a problem hiding this comment.
Codex (GPT-6.1 Sol), reviewing on @DjDeveloperr’s behalf.
No blocking findings. DESIGNATE_KEYBAG for the recovered identity bag now runs inside the existing one-per-boot policy window before machine-refkey creation can close it. Guard::check and its rewrite/delete/shared-root protections are unchanged. The maintainer-requested issue references are now full URLs. Exact-head host/source/Rust/KUnit checks pass; the reported 193/193 SEP KUnit result is attributed evidence. An attended policy-change boot remains needed before claiming hardware proof of this specific policy-change case; unchanged-policy sensor startup alone does not prove it.
|
Since this merged into
@satchlj @RyanTheTide, which one is intended?
All other linux PRs are held until Assisted by Claude Code |
|
Claude Fable 5.2 on @satchlj's behalf @DjDeveloperr thanks for tracking that down. Option 1 from our side: the test was written without knowledge of 519d09b, and the bare To unblock @RyanTheTide if you would rather have the initrd designate inside a window (option 2), that is your design to change; the test can be tightened again afterwards. |
test_no_other_path_designates_outside_a_window fails on integration/aurora since #1340 merged, which fails the source check of every pull request. The test was written on a branch without 519d09b ("support a trusted-key-only initrd attach"). That commit builds the ref-key unlock as a closure in refkey_unseal_cached and runs it inside crate::xart_guard::policy_window on the real root, but bare in the trusted-key-only initrd (keystore_only), on purpose: "Do not consume the real root's one policy window in the initrd". With the window shut the guard lets no existing session record be rewritten, so that path cannot make the rewrite the test protects against. Accept exactly that shape: the one deferred call in refkey_unseal_cached, whose closure is used twice, bare under keystore_only and in the window otherwise. Any other caller still has to open or close the window before the call. No runtime change. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Signed-off-by: Satya Benson <satya@benson.earth>
Closes #1190.
After a boot policy change the enclave rewrites one existing kind-4 session
record the first time Linux's identity keybag is used under the new policy.
e89d4a2 lets that rewrite through during the first unlock
(
CHANGE_LOCK_STATEinrefkey.rs). When Touch ID comes up before any trustedkey is unsealed, the keybag's first use is the
DESIGNATE_KEYBAGinactivate_touchid()instead, and that runs outside the window. The guardrefuses the rewrite, the designate is never answered, and Touch ID stays off on
every boot until
aurora-sep-policy-changeis run.Seen on
J616s (T6040), in apple_sep: Touch ID is lost after a boot policy change when DESIGNATE_KEYBAG comes before the trusted-key unlock #1190: after every Recovery enrolment of a Stage 1 on
2026-11-07, raw and Mach-O alike.
J613 (MacBook Air M3, T8122), Omarchy (Arch): after a change from raw
m1n1 to the Aura 1.0.0b5 Mach-O Stage 1 on 2026-11-07, on a 7.3 kernel built on
integration/aurora 11eccbe (which has e89d4a2):
On both, the refusal comes after LOAD_KEYBAG has answered and before
DESIGNATE_KEYBAG times out. Both use the variant-5 key store (T8122 takes
T8112's, T6040 takes T8140's), where
activate_touchid()is the only sender ofDESIGNATE_KEYBAG.
sks_prepare_identity_refkey()designates too, but only onthe 13.5 key store, and always inside a ref-key path's window.
On the J613,
aurora-sep-policy-changewith no arguments armed the refusedrecord. The next boot logged "allowed one rewrite of kind-4 record for a
boot policy change; its previous value is in
/var/lib/aurora-sep-xart-policy-previous.bin", restored the Catacomb, and
"Touch ID: restored 1 enrolled identity/identities; enrolment survived reboot".
The change
sbio.rs:activate_touchid()runs itssks_designate_user_keybag()incrate::xart_guard::policy_window(). That is the whole code change.xart_guard.rs: doc comments only. The window is described as the firstunlock or designate of an identity keybag that already existed.
tools/aurora-sep/tests/test_policy_window.py, also added to the SEP sourcechecks:
activate_touchid()designates a keybag it recovered, inside thewindow, before the machine ref-key (whose creation closes the window), and
the only other designate is in a ref-key path that holds the window or has
closed it. It fails on the current tree.
XART-SAFETY.mdand the tool's help: the designate case, the J613 report,and "Changing Stage 1 on purpose" (the first commit, which stands without the
fix).
The window's terms don't change. There is one window per boot, opened by
whichever comes first of this designate and the first unlock, and kept shut by
a keybag or ref-key created earlier in the boot. Inside it the guard still lets
through one rewrite of one kind-4 record that existed at probe, never a delete
or a shared root, only once the previous value is durable, and without listing
the record as Linux's.
Guard::check()is untouched.Under an unchanged policy this designate rewrites no existing record. The guard
is on by default on both Macs, and a refused write there leaves the designate
unanswered, yet every Touch ID boot without a policy change brings the enrolment
up.
Limit
The window stays one per boot, as you designed it. If some Mac designates
first but the enclave only asks at a later unlock, this change would close the
window before that unlock, where today's kernel would have let the rewrite
through. Neither Mac does that: on both, the first use got the request (your
J616s at the loader's unlock on 10-28, the #1190 J616s and the J613 at the
designate). The one-time allowance still covers such a case. Giving the
designate its own latch would cover it too, at the cost of two short windows
per boot. I kept to one.
Planned changes
The first commit documents what worked on the J613's second Stage 1 change
(2026-11-08, Aura 1.0.0b5-hsusb1): run
aurora-sep-policy-change --expectbefore the 1TR enrolment, on whatever kernel is installed, then make the first
boot afterwards a kernel with the allowance code. Touch ID survived that first
boot with no refusal. A kernel without the allowance code doesn't read the
file. With the guard on, it refuses and leaves the allowance for the next boot.
Its refusal line also names no session id, so the no-argument form can't arm
from there.
Tested
test_policy_windowandtest_policy_change: all pass.test_policy_windowfails on the current tree.drivers/soc/apple/apple-sep.o, CI recipe (defconfig + asahi.config +KUNIT+APPLE_SEP_KUNIT_TEST, LLVM 18, Rust 1.85.0, W=1): builds. Its one warning (SCRD_UNLOCK_POLICY_LENunused, in
scrd.rs) is already on the base.kunit.py run --arch=arm64 --kunitconfig=drivers/soc/apple/sep.kunitconfig 'apple_sep*'on QEMU: 193 of 193 pass (rustc 1.85.0, clang 18, QEMU 8.2).from rustfmt elsewhere, base and head alike.
another Stage 1 enrolment; I can run one on the J613 if you want hardware
proof first.
🤖 Generated with Claude Code