Skip to content

feat(vm): let operators re-sign openshell-driver-vm with the hardened runtime and only the hypervisor entitlement #4772

Open

Description

@vineethsai7

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 find libkrunfw.5.dylib.

The only working combination today is the two exceptions above.

Impact / Why This Matters

  • disable-library-validation together with allow-dyld-environment-variables lets 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

  1. The VM runtime libraries can be signed together with the driver. The driver accepts a sibling runtime directory that holds libkrun and libkrunfw, signed by the same Team ID. It uses that directory instead of extracting the embedded copy. OPENSHELL_VM_RUNTIME_DIR exists already and could be the documented switch.
  2. libkrun finds libkrunfw without DYLD_* variables. Possible ways are an absolute or @loader_path/@rpath reference set at build time, or the firmware path passed explicitly if libkrun supports that.
  3. 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/runtime

Acceptance Criteria

  • With the recipe, a driver signed with --options runtime and only com.apple.security.hypervisor boots a sandbox.
  • No disable-library-validation and no allow-dyld-environment-variables entitlement 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.plist holds 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) and compress-vm-runtime.sh (L41-51) sign it ad hoc.
  • ffi.rs preload_runtime_support_libraries (L152-197) dlopens libkrunfw by absolute path.
  • runtime.rs configure_runtime_loader_env (L450-462) sets DYLD_FALLBACK_LIBRARY_PATH. main.rs (L725-761) re-execs with DYLD_LIBRARY_PATH.
  • OPENSHELL_VM_RUNTIME_DIR (runtime.rs L435-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 runtime and only the hypervisor entitlement. codesign reported TeamIdentifier=not set; security find-identity -v -p codesigning found 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions