Caker

Virtualization platform for macOS

View project on GitHub

Sandbox

Caker ships two builds: a direct-download build with no App Sandbox, and an App Store build that runs inside the macOS App Sandbox (com.apple.security.app-sandbox). The sandboxed build can only read and write a fixed set of locations, and Caker enforces additional restrictions of its own on top of that for two VM-facing features: Unix domain sockets and Virtio-FS shared directories. This page documents both.

Checking whether you’re sandboxed

cakectl sandbox                 # sandboxed: true / false
caked sandbox --format json     # {"sandboxed": true}

Bundle.isApplicationSandboxed is the single source of truth used throughout the codebase; it’s derived once (and cached) from the running binary’s code signature, by checking for the com.apple.security.app-sandbox entitlement.

Unix domain socket paths

Unix domain sockets are bound through a sockaddr_un struct, whose sun_path field macOS limits to 104 bytes including the NUL terminator. Caker uses a 103-byte budget (URL.maxSocketPathLength) for the full unix://<path> target.

VM directories can nest fairly deep (~/Library/.../vms/<name>/...), so a fully-qualified per-VM socket path (agent socket, console socket, network control socket, VM-run service socket) can easily exceed that budget once you factor in a long VM or network name. When it does, URL.socketPath(name:) falls back to a much shorter path:

  • Sandboxed build: the short path is rebuilt directly under the sandbox container’s home directory, as <original last path component>.<name> — no home-relative subdirectories, since only the container itself is guaranteed writable.
  • Non-sandboxed build: the short path falls back to NSTemporaryDirectory() instead.

This same budget is why VM names and network names have a length ceiling: URL.maxVirtualMachineNameLength and URL.maxNetworkNameLength are both computed as maxSocketPathLength minus your home directory path length minus the fixed suffixes Caker appends (vms/cakedvm or net) — the deeper your home/container path, the shorter a VM or network name is allowed to be.

Separately, user-defined sockets attached to a VM (cakectl config vm --socket <url>) are subject to a stricter check: when the running process is sandboxed and not the embedded Caker.app VM runner (Bundle.fileAccessRestricted), any socket whose bind path resolves outside your sandbox container’s home directory is dropped — silently, with only a warning logged (.fileAccessRestricted is enabled, skipping socket: ...) — rather than failing the VM start. The App Sandbox simply cannot create a Unix socket file at an arbitrary path on disk.

Shared directories and additional disks

Directory sharing (-v/--mount <source>[:<destination>][,ro][,name=][,uid=][,gid=], backed by VZSharedDirectory/Virtio-FS) and additional disk attachments (extra disk images beyond the boot disk) go through the same gate: Utilities.isValidSharePoint.

Outside the sandbox, or when running inside Caker.app’s own GUI process, any path is allowed — the app can already read it, or the user picked it through a file panel that grants a security-scoped bookmark. In the sandboxed CLI/daemon (fileAccessRestricted == true), only these are accepted:

  • ~/Documents, ~/Download, ~/Public — macOS’s own sandbox-exception folders, always readable/writable by any sandboxed app
  • Any path under the app’s own sandbox container home directory

Anything else — an external volume, a path under a project directory, or a home-relative folder not in that list — is silently dropped from the VM configuration (again just a warning log), not rejected with an error. The VM still starts; it simply comes up without that mount or disk.

Note that this allow-list is narrower than the read-only/read-write home-relative exceptions declared in the app’s entitlements (~/.ssh/, ~/.tart/, ~/.docker/, UTM/VirtualBuddy support directories, etc.) — those exist to let Caker import VMs/keys from other tools, they don’t extend what you can pass to --mount or attach as an extra disk.

In the Caker.app GUI, the mount picker defaults to browsing ~/Public when sandboxed (instead of your full home directory) as a hint toward a folder that’s guaranteed to work.

See also

  • Command Summary — full --mount, --socket, --disk flag reference
  • Troubleshooting — ASIF disk resize and other sandbox-only failures
  • FAQ — sandboxed vs. direct-download build feature differences