Repository navigation
feat(vm): let operators re-sign openshell-driver-vm with the hardened runtime and only the hypervisor entitlement #4772
Description
User Story
I use OpenShell (0.1.3, checked against 0.1.5) with the MicroVM driver on macOS, deployed to managed Macs by an administrator. Enterprise macOS deployment needs every binary in the package signed with the organization's Developer ID, with the hardened runtime, and notarized.
When I re-signed openshell-driver-vm that way with only com.apple.security.hypervisor, the driver could not start a VM. It worked only after I added two exceptions that weaken the hardened runtime:
com.apple.security.cs.disable-library-validation;com.apple.security.cs.allow-dyld-environment-variables.
This affects every organization that repackages OpenShell for managed Macs.
Problem Statement
The driver extracts its embedded libkrun and libkrunfw runtime to a cache directory. Those libraries are ad-hoc signed at build time. The driver opens libkrunfw by path and tells libkrun where to find it through DYLD_FALLBACK_LIBRARY_PATH, and it re-execs itself with DYLD_LIBRARY_PATH.
Under the hardened runtime this fails in two ways:
- Library validation refuses to load the ad-hoc-signed libraries into a binary with a Team ID.
- dyld ignores the
DYLD_*variables, so libkrun cannot findlibkrunfw.5.dylib.
The only working combination today is the two exceptions above.
Impact / Why This Matters
disable-library-validationtogether withallow-dyld-environment-variableslets any process environment inject libraries into a binary that holds the hypervisor entitlement. Security reviews of managed-Mac packages reject or flag that combination.- The alternative is the release's own signature. That is not under the organization's Team ID, and some MDM policies require the organization's signature.
- There is no documented, supported way to repackage the VM driver.
Proposed Design
- The VM runtime libraries can be signed together with the driver. The driver accepts a sibling runtime directory that holds
libkrunandlibkrunfw, signed by the same Team ID. It uses that directory instead of extracting the embedded copy.OPENSHELL_VM_RUNTIME_DIRexists already and could be the documented switch. - libkrun finds libkrunfw without
DYLD_*variables. Possible ways are an absolute or@loader_path/@rpathreference set at build time, or the firmware path passed explicitly if libkrun supports that. - A documented repackaging recipe:
# notional
codesign --force --options runtime --timestamp -s "Developer ID Application: Example" runtime/libkrunfw.5.dylib runtime/libkrun.dylib
codesign --force --options runtime --timestamp --entitlements hypervisor-only.plist -s "Developer ID Application: Example" openshell-driver-vm
# gateway.toml or environment: OPENSHELL_VM_RUNTIME_DIR=/opt/example/openshell/runtimeAcceptance Criteria
- With the recipe, a driver signed with
--options runtimeand onlycom.apple.security.hypervisorboots a sandbox. - No
disable-library-validationand noallow-dyld-environment-variablesentitlement is needed. - The release driver's own behavior is unchanged when no runtime directory is configured.
- The macOS build lane checks that a hardened-runtime signature (ad-hoc or test identity) with only the hypervisor entitlement starts a VM.
Alternatives Considered
- Add the two exceptions. This works, but it weakens the hardened runtime for a binary that holds the hypervisor entitlement.
- Ship the release signature unchanged. This works on unmanaged Macs. It does not meet policies that require the organization's own signature.
- Extensibility points (middleware, interceptors, providers). These do not apply, because this is binary loading.
Agent Investigation
crates/openshell-driver-vm/entitlements.plistholds only the hypervisor entitlement..github/workflows/build-vm-driver.yml(L42, L113) uses it.embedded_runtime.rs(L12-14, L60-95) extracts the runtime.tasks/scripts/vm/build-libkrun-macos.sh(L216-234) andcompress-vm-runtime.sh(L41-51) sign it ad hoc.ffi.rspreload_runtime_support_libraries(L152-197) dlopens libkrunfw by absolute path.runtime.rsconfigure_runtime_loader_env(L450-462) setsDYLD_FALLBACK_LIBRARY_PATH.main.rs(L725-761) re-execs withDYLD_LIBRARY_PATH.OPENSHELL_VM_RUNTIME_DIR(runtime.rsL435-440) already selects an external runtime directory.
Checklist
- I've reviewed existing issues and the published docs
- This is a design proposal, not a "please build this" request
Environment
- Stock OpenShell 0.1.5 release binaries, checksum verified.
- macOS 15.8, Darwin kernel 24.6.0, Apple silicon, Apple Hypervisor.framework/libkrun; Docker Desktop 29.8.2; Podman not used.
- A separate copy of the VM driver was signed ad hoc with
--options runtimeand only the hypervisor entitlement.codesignreportedTeamIdentifier=not set;security find-identity -v -p codesigningfound zero Developer ID Application identities. This tests the hardened runtime loading path but does not confirm the Developer ID or notarization path.
Logs
Signature=adhoc
TeamIdentifier=not set
Runtime Version=14.4.0
hypervisor-only create exit=1
exception-entitlement create exit=0
The gateway's dlopen diagnostic for libkrunfw.5.dylib said the mapped file was invalid for the process because the process and file had different Team IDs. The exception test used both com.apple.security.cs.disable-library-validation and com.apple.security.cs.allow-dyld-environment-variables on the same isolated copy. The full redacted diagnostic is in the evidence folder.
Activity