feat(helper): bundle the interposer in the .app#64
Merged
Conversation
The helper now carries the interposer in Contents/Resources and resolves it from its own bundle, so an installed SimEnclave arms the simulator out of the box. Before, the helper only found the dylib by walking up to a dev-tree build-sim/, so the /Applications build never armed and apps ran uninjected (SecKeyCreateRandomKey hit the bare simulator: -34018). Re-scope the fence to the boundary that matters. The interposer is a simulator-slice binary (dyld on a device refuses it), a consuming app injects it debug-scheme-only, and the variable stays in the allowlist; those are the real guarantees, and none needs the dylib absent from the helper. fence-check.sh gains --helper (the bundled payload must be simulator-slice and the helper must not inject into itself); --bundle still rejects an interposer in a consuming app. fence-selftest covers both. Docs updated to match.
This was referenced Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An installed SimEnclave couldn't inject. The helper found the interposer only by walking up from its own path to a dev-tree
build-sim/, which doesn't exist next to/Applications, soarm()silently no-oped, the simulator was never armed, and apps ran uninjected. A permanent-keySecKeyCreateRandomKeythen hit the bare simulator and failed-34018.The fix
The helper bundles the interposer in
Contents/Resourcesand resolves it from its own bundle (dev-tree fallback kept). The.appis self-contained, so the installer just drops it in/Applicationsand arming works out of the box.Re-scoping the fence (the part worth reviewing)
The old fence forbade the interposer inside any
.app, including the helper's own. That rule conflated the helper (the tool that injects) with a consuming app (the thing that must never ship it). It is not what keeps the interposer out of production. Three things do, none of which needs the dylib absent from the helper:DYLD_INSERT_LIBRARIESonly in a debug scheme; a release build references nothing. iOS library validation blocks the injection on a device anyway.So the fence now guards that boundary honestly:
fence-check.sh --helper <app>asserts the bundled interposer is present and is simulator-slice (viavtool), and that the helper does not inject into itself.fence-check.sh --bundle <app>still rejects an interposer or the variable in a consuming app.fence-selftest.shcovers both (no-interposer fails, non-sim-slice fails, real sim-slice passes; consuming-app cases unchanged).The guarantee gets stronger and more honest: instead of "the dylib is hidden," it's "the only binary the tool ships can run nowhere but the Simulator."
Verified
Built the
.app: interposer bundled,vtoolplatformIOSSIMULATOR,--helperpasses,--bundlecorrectly fails on it, static fence passes, codesign--deep --strictok, helper compiles. Installed it, launched the helper, and it armed the booted sim pointing at its own bundled dylib; the relaunched example app injected and the helper loggedserved LIST_KEYS app=dev.simenclave.SecureEnclaveExample, so the-34018path is gone.Custody gate: PASS (dev tool, the developer's own Mac SEP, no user keys or funds).