Skip to content

soc: apple: sep: let a fresh install create its Touch ID keybag - #212

Merged
maralcbr merged 5 commits into
integration/aurorafrom
sep/xart-guard-first-setup
Oct 25, 2026
Merged

maralcbr merged 5 commits into
integration/aurorafrom
sep/xart-guard-first-setup

Conversation

@maralcbr

@maralcbr maralcbr commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes Touch ID setup on a fresh install of an M2 Max (and likely other warm-attach Macs), reported in #209.

Blessing a newly installed OS from macOS leaves the SEP-xART locker that every OS's enclave reads at attach in a pending state. The next enclave to save its state commits it. macOS's enclave does that at boot. Under Linux the first save is the first CREATE_KEYBAG, so the guard refused the commit: CREATE_KEYBAG got no reply, the enclave stopped answering until a restart, and Touch ID only worked after booting macOS once.

  • xart_guard: first-setup window. During the first CREATE_KEYBAG of an install whose owned list is loaded and empty, on a warm-attach Mac at level 1, the enclave may rewrite the first existing kind-4 (SEP-xART) locker it writes. Nothing identifies that locker as the pending one; the window allows any one pre-existing kind-4 rewrite. The locker is not adopted. Deletes, kind-3 (USER-xART) lockers, a second rewrite and level 2 stay refused, and cold-boot Macs (M1 family) get no window. Dj agreed to the exception, on condition that keyctl and fprintd keep working across reboots.
  • Once per install. Before the create is sent, the driver writes a marker entry (kind 0, lists no record) as the owned list's first entry and flushes it. No later create on the install gets the window: not another boot, not after a Touch ID reset (which keeps the list). If the marker can't be written, the create isn't sent that boot and the intent stays retryable.
  • No retry after a refused create. An earlier commit here marked a refused create retryable; it is reverted. It had no profile or level gate, so cold-boot Macs at the default level would have wedged the key store on every boot, and a refused write doesn't prove the enclave kept nothing. A refused create stays fail-closed (EEXIST) as before.
  • XART-SAFETY.md: the M2 Max measurement, the pending-locker evidence, the new rule, the marker and the remaining failure mode.

Evidence

M2 Max (J416c, T6021), system firmware 26.6.2, guard level 1, real preboot UUID throughout. Kernel 7.2.11.aurora5-1.1: the current omarchy-pkgs pin (99cb1a7) plus this branch's diff, built with the package's own PKGBUILD.

Fresh install with Omarchy Installer 2.3.8 (Remove, then Install, edge), no macOS boot before Touch ID setup.

Step Result
Pending locker at Linux's first boot 2715 B (1137 B before the install, 2321 B right after the installer's bless)
First CREATE_KEYBAG xART guard: allowed the enclave to commit an existing kind-4 locker during this install's first keybag creation; op 0x06 1153 B status 0; sks: identity keybag provisioned; locker now 1137 B; owned list empty
Enrolment (Omarchy Setup > Security > Fingerprint) complete, USER-xART root writes only
fprintd-verify match
keyctl trusted key new 32 / pipe / load sealed 113-byte enclave blob, unsealed to 32 bytes
Restart Touch ID: restored 1 enrolled identity, blob loads, match
macOS 1 template, Touch ID unlock (APEventTouchIDMatch), _keychainPasswordReset:0, _keychainMovedAside: 0
Back in Linux restored, blob loads, match

xart_guard_refusals=0 throughout.

Earlier the same day, unpatched aurora4: the refusal, the hang and the permanent EEXIST intent are reproduced in #209. The guard and store kprobe traces, gigalocker dumps at each step and macOS's AppleSEPXART log (which shows macOS reading the same four lockers under its own OS UUID) are available on request.

Not tested

  • The once-per-install marker: the hardware runs above predate it (they show the list staying empty). The new code has been built, not booted.
  • The KUnit tests: they compile with CONFIG_KUNIT=y and CONFIG_APPLE_SEP_KUNIT_TEST=y, but haven't been run (CONFIG_KUNIT is off in the package config).
  • Other boards: M2 Pro, M3, and the base M2 (J413, where keybag creation made no xART writes, so the window never opens).

Merge Danger

Door: two-way

The rule only relaxes during one CREATE_KEYBAG per install, on an install whose owned list was empty, and it never adopts the locker. Reverting restores the old refusal; a marker left in the list is ignored by older kernels as one torn entry.

Blast Radius: the first Touch ID setup on warm-attach Macs (M2, M2 Pro/Max, M3) at the default guard level.

…SEP-xART locker

Blessing a newly installed OS from macOS leaves a SEP-xART locker (kind 4)
in a pending state. Every OS's enclave reads that locker at attach, and the
next enclave to save its state commits it. macOS's enclave does that at
boot. Under Linux the first save is the first CREATE_KEYBAG, so on an
install whose first boot is Linux the guard refused the commit. The create
then got no reply, the enclave stopped answering until a restart, and Touch
ID could only be set up after booting macOS once.

While the first CREATE_KEYBAG of an install whose list is loaded and empty
runs on a warm-attach Mac at level 1, let the enclave rewrite one existing
kind-4 locker. The locker is not listed as Linux's, so later rewrites are
refused as before. Deletes, kind-3 lockers and a second rewrite are still
refused, and cold-boot Macs get no window: their create rewrites a pre-Linux
record for a different reason.

Tested on an M2 Max (J416c, system firmware 26.6.2), reinstalled with the
Omarchy Mac installer and with no macOS boot before Touch ID setup. The
guard allowed the one commit (2715 to 1137 bytes, as macOS's enclave makes
it), the keybag was provisioned and the list stayed empty. Enrolment,
match, trusted-key seal and load, restore and match after a restart, macOS
Touch ID unlock and keychain, then restore, trusted-key load and match back
in Linux all passed, with no refusal.

Signed-off-by: Marcelo Alcantara <maralc@gmail.com>
A CREATE_KEYBAG that times out keeps its intent record, so every later
create fails with EEXIST in case a keybag exists unnamed in the enclave.
When the guard refused one of the enclave's xART writes during the create,
the enclave could not save the state the create needed, so it kept no
keybag, and the enclave typically stops answering until a restart. The
intent then blocks Touch ID setup for good, and the owner's only way out is
removing /var/lib/aurora-sep-keybag.bin by hand.

Mark such a create retryable, so the next boot tries again.

Signed-off-by: Marcelo Alcantara <maralc@gmail.com>
@greptile-apps

greptile-apps Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new actionable issues were found.

Summary

Lets a fresh install create its first Touch ID keybag on warm-attach Macs at guard level 1.

  • Fresh installs can create a Touch ID keybag without booting macOS first.

The earlier torn-list finding is fixed: open_first_setup() checks the actual file size. Its supplied thread is unnumbered, so it has no numbered previous-finding entry. No new actionable issues were found. Kernel builds and KUnit tests were not run.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[First keybag create] --> B{Warm attach, level 1,
  loaded empty list?}
  B -->|No| C[Keep normal guard rules]
  B -->|Yes| D[Write and flush consumed marker]
  D -->|Fails| E[Stop before sending; mark create retryable]
  D -->|Succeeds| F[Allow one existing kind-4 rewrite]
  F --> G[Close window when exchange returns]
  G --> H[Keep marker across boots and Touch ID resets]
Loading

Reviews (3) · Last reviewed commit: "soc: apple: sep: Open the first-setup wi..." · Reviewed by Greptile

Comment thread drivers/soc/apple/xart_guard.rs Resolved
…ntry

load() counts whole entries, so a list holding only a torn first entry
left the append offset at 0 and opened the first-setup window. A torn
entry is still an earlier setup: open the window only when the list file
is empty. Also update the aurora-sep package's checksum for the
XART-SAFETY.md change.

Signed-off-by: Marcelo Alcantara <maralc@gmail.com>
…efused"

This reverts commit 6848e89.

The retry had no profile or level gate. On cold-boot Macs at the default
guard level (T8103, T6000), where the create's rewrite of a pre-Linux
record is refused, every boot would mark the create retryable, try again,
be refused and wedge the key store, instead of failing fast with EEXIST
after the first boot. A refused write also does not prove the enclave kept
no keybag: an allowed root write comes before it. Keep the intent
fail-closed.

Signed-off-by: Marcelo Alcantara <maralc@gmail.com>
The first-setup window opened whenever the owned list was empty, and a
successful first create leaves it empty: the committed locker is not
adopted. Resetting Touch ID removes the keybag but keeps the list, so the
next create on the same install got the window again, and the enclave could
rewrite a SEP-xART locker that was no longer pending.

Record the window as consumed before it opens: write a marker as the list's
first entry and flush it before the create is sent. The marker is kind 0,
which no record has, so it lists nothing as Linux's; older kernels read it
as one torn entry and append after it. If it cannot be made durable, the
create is not sent and the intent is dropped as retryable. The window now
also requires level 1 when it opens, so level 2 consumes nothing.

Document that the window allows the first pre-existing kind-4 rewrite,
with nothing identifying it as the pending locker, and the marker.

Signed-off-by: Marcelo Alcantara <maralc@gmail.com>
@maralcbr
maralcbr merged commit 7876c8e into integration/aurora Oct 25, 2026
14 checks passed
@joshuaswarren

Copy link
Copy Markdown

Hand build replaced by the shipped Edge package: linux-aurora 7.2.11.aurora6-1 (CI run 40185970994, head 7876c8e, success; Edge bumped aurora5-1 -> aurora6-1 minutes after the run). Installed through the shipped packages and their hooks (no hand packaging), one-shot boot of the linux-aurora entry, stock default (the 12.6 preempt entry) untouched.

Tested on the 14-inch M2 Max:

step result
boots yes — candidate boot 9615ad25 (7.2.11-6-1-ARCH), return boot 0ee38b62 (7.1.12-2-12.6-sep-ARCH default)
smoke equal to stock; boot/wifi/input/display/audio/ANE/battery all pass
omarchy-m-test 0.1.13 https://omarchy-m-testing.org/reports/kGAMNvUN5bjGHtV1aZtimzu5 (stock reference: https://omarchy-m-testing.org/reports/RVXdswZ8LJoUJKF7vRh2KAHf)
boot-chain integrity boot.bin restored to the pre-test hash 73729530..., 12.6 default UKI hash unchanged, all limine pins MATCH, no one-shot left

CI on this PR: 12 pass, 2 skipped.

Regressions: none found. omarchy-m-test check list matches the stock run except: boot.kernel-package now PASS (the running kernel is the installed package, which is the point of this run), input.auto-keyboard-light PASS (already passing on the earlier tip build; stock 12.6 fails it — improvement, not regression), hardware.drivers counts the apple,mesa-fingerprint node unclaimed (same delta as the earlier tip build, no functional impact seen, and this machine has no fingerprint reader), and sep.attach reads SKIP because the tool's passive SEP reader expects diagnostics ABI 1 while the 7.2.11 kernel exposes ABI 2 — the driver itself is fully alive on the candidate (apple_sep loaded, profile T6020/J414s, xART extent scanned clean, 12 SEP endpoints discovered, hwrng registered, trusted-keys registered; audio.microphone-signal passes). One new dmesg line class on the candidate, no functional impact: tas2764 i2c probe "Failed to parse devicetree" on three of the five amp i2c addresses, while speaker amps still unlock, the DSP sink is present, speaker protection stays active and the tone plays.

Not tested: this machine has no fingerprint reader (fprintd: "No devices available"), so the Touch ID keybag path in this PR is covered only down to the SEP/xart first-setup guard code compiled in and the SEP attach staying healthy; the actual keybag create path needs a machine with the reader. M3 paths in the other merged PRs are not exercised on this machine.

@joshuaswarren

Copy link
Copy Markdown

Read 6848e89 ("Retry a keybag create whose xART write was refused") against what happened on a 14-inch M2 Max. Short answer: our result is not the case it fixes, and I did not run that commit.

What the commit does, as I read it: when CREATE_KEYBAG fails and guard_refusals() went up during the exchange, it marks the create retryable (keybag::mark_refused) so the next boot tries again instead of treating the slot as a keybag that may exist.

What happened here (aurora6 7.2.11.aurora6-1, which contains #212):

  • First attempt: fprintd started at 86 s into a boot where /etc/modprobe.d/aurora-sep.conf (from an earlier aurora-sep --read-only) set xart_writes=0 provision_keybag=0. The driver logged Touch ID: no persisted identity keybag exists and Touch ID activation failed: ENOENT; refusing retries this boot because a partial keybag load is not safely repeatable. No create was attempted and the guard refused nothing (xart_guard_refusals stayed 0), so the new retry path would not have run.
  • Next boot: with omarchy-mac's xart_writes=1 provision_keybag=1 added to the same apple_sep options, the kernel rejected the duplicated parameters ('1' invalid for parameter 'xart_writes'), the module did not load, and the load unit still reported success. That is a packaging/config problem, written up in Edge omarchy 4.5.0rc1-1 lacks the enable-fingerprint operation (#16360), so Mac Touch ID setup cannot work omarchy-pkgs#1614.
  • After deleting the read-only file and restarting the load unit: xART guard: allowed the enclave to commit an existing kind-4 locker during this install's first keybag creation, sks: identity keybag provisioned, keybag file created, xart_guard_refusals 0. Enrollment then completed (enrol: opt-in completed user catacomb state Some(7), identity count 1) and fprintd-list shows the print. xART at load before enrollment: 170 slots, 12 live records, max revision 56563, 0 malformed.

So: the first-keybag create on an M2 Max worked with #212 once writes were enabled; the one refusal-style message we saw came from provisioning being switched off by the read-only file, not from a refused enclave write. A refused create is the path 6848e89 covers, and we did not hit it.

Not measured yet: a real match after enrollment, survival across a reboot, xART counts after enrollment, and macOS on that Mac. I will add them here when done.

@joshuaswarren

Copy link
Copy Markdown

Result on the 14-inch M2 Max, aurora6 7.2.11.aurora6-1 (contains #212), added to my comment above:

  • Enrolled through the Omarchy menu (Setup > Security > Fingerprint): fprintd-list shows right-index-finger on the Apple secure enclave sensor; driver log enrol: opt-in completed user catacomb state Some(7), identity count 1.
  • Survived a reboot: next boot Touch ID: restored 1 enrolled identity/identities; enrolment survived reboot, fprintd-list still shows the print, xart_guard_refusals 0.
  • Unlocked the lock screen with the finger once (Joshua, by hand).
  • xART before and after, from the driver's load line:
slots live records max revision malformed writes
before enrollment 170 12 56563 0 ENABLED
after enrollment + one reboot 170 12 56573 0 ENABLED

The max revision moved by 10 (the anti-replay counter going forward during enrollment). The guard reported 10 session records exist, 0 created by Linux; the other 10 are protected both times. I can see counts only, not record contents.

  • Not checked: macOS on that Mac (Touch ID unlock there was not re-tested), polkit/pkexec with the finger, a second finger, removal (disable-fingerprint).

Two things outside the kernel that blocked the first tries are written up in omacom/omarchy-pkgs#1614 (menu row hidden by a stale guard after the package switch; duplicate apple_sep module options from an old read-only file).

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.

2 participants