Commit Graph
134 Commits
Author SHA1 Message Date
Michael Crosby 315341b625 add masked and readonly path support (#795)
Signed-off-by: michael_crosby <michael_crosby@apple.com>
2026-07-08 16:47:16 -04:00
Michael Crosby b438e97b93 Add cloud-hypervisor VMM backend for Linux hosts (#782)
apple/containerization currently runs containers in per-container VMs on
macOS hosts via Virtualization.framework. This adds a second VMM backend
so the same Swift orchestration layer (LinuxContainer / LinuxPod /
Vminitd gRPC contract) runs on Linux hosts via cloud-hypervisor + KVM.

**CloudHypervisor Swift package** (`Sources/CloudHypervisor/`) — a thin
client for cloud-hypervisor's REST-over-UDS API, layered on
AsyncHTTPClient. Endpoints cover VMM / VM lifecycle / hotplug (disk, fs,
net, vsock, remove-device). Cross-platform (compiles on macOS for unit
tests; consumed at runtime only by the Linux side of Containerization).

**CH backend in Containerization** — one cloud-hypervisor subprocess per
VM, gated behind `#if os(Linux)`. CHVirtualMachineManager /
CHVirtualMachineInstance mirror the VZ shape behind the existing
VirtualMachineManager / VirtualMachineInstance protocol. CHProcess and
VirtiofsdProcess manage the binaries; CHHotplugProvider handles
virtio-blk and virtio-fs runtime hotplug (with one virtiofsd per unique
source-hash tag, refcounted across containers).

**Linux host networking** — BridgeManager brings up a Linux bridge with
an IPv4 subnet and (opt-in via `--enable-nat`) iptables MASQUERADE +
scoped FORWARD rules. LinuxBridgedNetwork enslaves a fresh TAP per
container to the bridge. State is recorded under `/run/containerization`
so `cctl bridge delete` reverses exactly what create did. Bridge
teardown verifies the link kind via sysfs to refuse deleting non-bridge
interfaces.

**cctl run / bridge** — end-to-end Linux container run path (image pull,
ext4 rootfs assembly, VM boot, container exec) plus `cctl bridge
create|delete` for the host network plumbing.

**Build & dist** — `make linux-build` / `make linux-integration` build
and exercise the host side inside an apple/container `--virtualization`
dev container. `make dist-x86_64` produces a deployment tarball (cctl +
cloud-hypervisor + virtiofsd + initfs + kernel) cross-compiled from the
aarch64 dev container; pipeline documented in `docs/x86_64-build.md`.
Static-musl C deps and the Zig cross compiler are pinned by SHA256.

The host orchestrator runs as root. Per-VM runtime state lives under
`/run/containerization/ch/<UUID>` with mode 0700; UDS sockets inside are
bound with mode 0600. Vminitd's gRPC channel inherits that trust
boundary — socket-file perms are the auth.

Sandbox flags are upstream-secure by default. Two per-component opt-outs
exist for the apple/container dev-container case (where the host seccomp
profile SIGSYS-kills CH and virtiofsd):
- `CONTAINERIZATION_NO_CH_SECCOMP=1` — `cloud-hypervisor --seccomp
false`.
- `CONTAINERIZATION_NO_VIRTIOFSD_SANDBOX=1` — `virtiofsd --sandbox
none`. Each emits a one-shot `logger.warning` at process start. Legacy
alias `CONTAINERIZATION_RELAXED_SANDBOX=1` flips both. cctl spawns both
binaries with `setsid` and a minimal env allowlist (PATH / HOME /
RUST_LOG / RUST_BACKTRACE) so the parent's secrets don't leak to
children.

`make linux-integration` runs the cross-platform integration suite
against a real cloud-hypervisor VM inside the dev container. Linux runs
the cross-platform subset (`process true`/`false`/`echo hi`, virtiofs
round-trip, hotplug); the macOS suite is unchanged.

Signed-off-by: michael_crosby <michael_crosby@apple.com>
2026-07-02 11:20:22 -04:00
Saehej Kang 6b7b42ca3e [vminitd]: api for trim filesystem operations (#700)
Addition of `vminitd` API for trim filesystem operations

Closes #773

Depends on #685
2026-06-20 06:32:23 -07:00
Saehej Kang 5887dc55f3 [vminitd]: api for freeze/thaw filesystem operations (#685)
Addition of `vminitd` API for freeze/thaw filesystem operations

Closes #660
2026-06-19 14:45:17 -07:00
Aditya Ramani d55cc188ce Allow setting log level for vminitd (#772)
The `--log-level` option when running the agent sub-command for vminitd
was being silently ignored cause of the way the agent is being run. As a
workaround we need to read `/proc/self/cmdline` to get the right args
2026-06-16 18:04:31 -07:00
e1e31b7ae9 add IPv6 support (#752)
Extends the network plumbing to support per-interface IPv6 address
configuration.
The `Interface` protocol supports `ipv6Address` and `ipv6Gateway`.
The agent's networking RPCs carry per-family fields via new
`InterfaceAddress`, `LinkRoute`, and `DefaultRoute` types in
`ContainerizationExtras`.
`NetlinkSession` adds IPv6 methods for address and route operations.

---------

Co-authored-by: michael_crosby <michael_crosby@apple.com>
Co-authored-by: Michael Crosby <crosbymichael@gmail.com>
2026-06-03 12:07:20 -04:00
Danny Canter 6cb66583e2 Stats: Expose more memory stats (#758) 2026-06-01 11:52:53 -07:00
Danny Canter b1e779eb2a Cgroup2: Add ability to filter stats (#757) 2026-06-01 11:51:50 -07:00
mlsad3 fd820380a6 Fix head-of-line blocking and resource leak in BidirectionalRelay (#713)
- Closes #712.
- Replace synchronous `write()` calls in
  `BidirectionalRelay` with non-blocking I/O
  and `DispatchSourceWrite` backpressure
  handling. Under concurrent vsock proxy load,
  a single blocked write on the shared serial
  dispatch queue would freeze all relay
  connections permanently, including unrelated
  new connections.
- Set relay file descriptors to `O_NONBLOCK`
  and handle `EAGAIN` by suspending reads and
  installing a write source to drain pending data.
- Give each `BidirectionalRelay` its own serial queue
  instead of sharing one from `UnixSocketRelayManager`,
  eliminating cross-connection blocking.
- Resume suspended read sources before cancelling
  in `stop()` — GCD does not deliver cancel handlers
  on suspended dispatch sources, which caused file
  descriptor and memory leaks on teardown under
  backpressure.
- Guard-unwrap `buf.baseAddress` in
  `drainPendingWrite`.
2026-06-01 10:33:36 -07:00
Dmitry Kovba 9205a76630 Keep CVersion in the vminitd package (#747)
Moves `CVersion` back to the `vminitd` package. This is a follow-up for
apple/containerization#742.
2026-05-20 20:17:26 -07:00
Dmitry Kovba c8fe3bbef9 Move the VminitdCore library to the top-level package (#742)
External Swift Package Manager consumers can only see products declared
in the top-level `Package.swift`. The `VminitdCore` library was declared
inside the `vminitd` subpackage, so it was impossible to build a custom
`vminitd` against it via a URL dependency on `containerization`. This
change moves the `VminitdCore` to the top-level `Package.swift`.
2026-05-20 15:46:32 -07:00
Simone Panico db5b5b9840 Add path resolution for CopyIn using Stat (#727)
This pull request enhances the handling of file and directory copy
operations in Linux containers, particularly by improving destination
path resolution and error handling for the `copyIn` operation with the
`Stat RPC`

This PR is needed for
[container#1190](https://github.com/apple/container/pull/1190)
2026-05-19 10:25:43 -07:00
Danny Canter 8140499b4f TerminalIO: Fix ebadf on close (#719)
The stdout and stdin IOPairs in TerminalIO share the same Terminal fd.
Closing stdin first would close the Terminal, causing stdout to read -1
from fileDescriptor and fail to unregister from epoll. This left stale
handler closures (capturing the IOPair) in ProcessSupervisor.handlers
indefinitely.

Additionally, vsock sockets created in TerminalIO.start() with
closeOnDeinit disabled were never closed if the process exited before
attach() created IOPairs.
2026-05-04 10:35:41 -07:00
Michael CrosbyandDanny Canter b62edd2e2d make vminitd package for extensions (#708)
Signed-off-by: michael_crosby <michael_crosby@apple.com>
Co-authored-by: Danny Canter <danny_canter@apple.com>
2026-04-29 14:43:52 -04:00
Danny Canter 0e469481f5 LinuxContainer: Allow cpu/mem overhead to be configurable (#710)
If someone wanted to use a custom guest agent/guest image in general the
overhead we chose is kind of a nuisance.. This allows the values to be
configurable, and raises the default to 128, and vminitds cgroup
monitoring to 80.
2026-04-29 10:33:44 -04:00
jwhur b770cd2a02 Add stat RPC (#614)
Add `Stat` RPC to vminitd.

`Stat` RPC is used to stat file system objects in the VM. It accepts the
path to the object (resolved against VM root) and returns the stat
result.
2026-04-27 14:44:33 -07:00
jwhur de58d1dd09 Set memory.low for vminitd to avoid kernel reclaiming its memory (#682)
Sets `memory.low` for `vminitd` cgroup to make kernel avoid reclaiming
its memory under high memory pressure. Even if the container process
runs in memory cgroup, consuming lots of page cache can lead to
reclaiming `vminitd`'s page cache memory , which hangs the `vminitd`.
Setting `memory.low` makes kernel avoid reclaiming `vminitd`'s page so
that we can guarantee the proper `vminitd` operation under high memory
pressure.
2026-04-13 18:42:28 -07:00
J LoganandDanny Canter 9d870451e8 Upgrade vminitd API to use grpc-swift-2. (#578) (#669)
- Closes #51. Again.
- No real notable API changes. The largest change code-wise is in
Vminitd. The connection loop is set up immediately in the new API by
calling runConnections() on the client, and this blocks until either the
task it's running on is cancelled or beginGracefulShutdown is called.
Because of this, either we'd have to modify our API to have
VirtualMachineAgent implementations call some run() method, or we just
put runConnections in an internal task on Vminitd. This change uses the
latter approach as it's simpler.
- Updated dependencies to pick up latest protobuf and grpc-swift-2
fixes.
- ClientBootstrap.withConnectedSocket(fd).wait() registers the vsock fd
with epoll/kqueue immediately. vminitd sends its HTTP/2 SETTINGS frame
right away upon accepting the connection, so those bytes can arrive on
the fd — and be read by NIO — before the gRPC pipeline is installed.
With a bare pipeline, NIO has nowhere to send the bytes and discards
them.
- Buffer until ClientConnectionHandler is in the pipeline so it can
process the SETTINGS frame and fire .ready, then schedule delivery of
the buffered data with assumeIsolatedUnsafeUnchecked().execute.
- To help produce more accurate merged logs, defines a
`StderrLogHandler` in the vminitd Application.swift that writes
timestamps to the boot log with millisecond precision and format
identical to that of the log files created using the `--log-root` arg on
`container`.
- Updates hawkeye to latest version (v6.5.1).
- In vminitd, use the Server event loop group for the gRPC server.

Co-authored-by: Danny Canter <danny_canter@apple.com>
2026-04-12 22:11:03 -07:00
Danny Canter ceee3a67ba vminitd: Lower nio event loop group threads to 1 (#677) 2026-04-10 10:47:22 -07:00
Danny Canter c2552ca399 Epoll: Rework epoll type (#619) 2026-04-08 21:59:41 -07:00
Danny Canter 997d5a4b08 Actions: Add Linux build step (#654)
Related to https://github.com/apple/containerization/issues/606

To make sure the project (and many linux specific libraries) builds on
linux lets add a linux step to build for both musl and glibc. Eventually
this will run unit tests as well. This change needs a bit more libc
agnostic-ifying work to make sure things work for both libcs.
2026-04-07 15:13:12 -07:00
Danny Canter 1a91899b63 Cgroup2: Map OCI spec unlimited sentinel values to "max" (#620) 2026-04-06 21:53:37 -07:00
Danny Canter 83943ed715 vminitd: Make everything libc agnostic (#655)
Remove the last (as far as I can see..) of the musl specific imports we
had.
2026-04-06 18:34:48 -07:00
Dmitry Kovba 11bbbbb852 Support a default route without a gateway (#628)
Adds the support for a default route without a gateway.

```
/ # ip route show default
default dev eth0 scope link 
```
2026-04-02 14:27:56 -07:00
Danny Canter 4040ce20c2 vminitd: Get rid of unused CgroupManager (#621) 2026-04-02 10:13:07 -07:00
Danny Canter 2bce72d57e vminitd: Log git info (#609)
Logs the git sha, tag (if we're on one), and build time.
2026-03-30 13:46:35 -07:00
Dmitry Kovba 72432f148c Add the vminitd version to the logs (#604)
Adds the vminitd version to the logs.

Switching to a local version of vminitd is non-trivial:

```
-                .define("CZ_VERSION", to: "\"\(scVersion)\""),
+                .define("CZ_VERSION", to: "\"latest\""),
```

Having an additional confirmation of the used version in the logs is
vital.
2026-03-30 10:15:00 -07:00
Yibo Zhuang a59ed89421 vmexec: create working directory if it doesn't exist (#591)
This seems like standard OCI runtime behavior, which is to create the
working directory if it doesn't exist.
2026-03-19 22:24:25 -07:00
Michael Crosby 84b71f10ae Revert "Upgrade vminitd API to use grpc-swift-2. (#578)" (#588)
This reverts commit 7ffe6d2ed5.
2026-03-17 13:46:28 -07:00
Danny Canter a35b168888 LinuxContainer/LinuxPod: Add support for NoNewPrivileges (#581)
Basically just a direct mapping to the prctl/OCI spec field.
2026-03-14 11:23:22 -07:00
J LoganandDanny Canter 7ffe6d2ed5 Upgrade vminitd API to use grpc-swift-2. (#578)
- No real notable API changes. The largest change code-wise is in
Vminitd. The connection loop is set up immediately in the new API by
calling runConnections() on the client, and this blocks until either the
task it's running on is cancelled or beginGracefulShutdown is called.
Because of this, either we'd have to modify our API to have
VirtualMachineAgent implementations call some run() method, or we just
put runConnections in an internal task on Vminitd. This change uses the
latter approach as it's simpler.
- Updated dependencies to pick up latest protobuf and grpc-swift-2
fixes.
- ClientBootstrap.withConnectedSocket(fd).wait() registers the vsock fd
with epoll/kqueue immediately. vminitd sends its HTTP/2 SETTINGS frame
right away upon accepting the connection, so those bytes can arrive on
the fd — and be read by NIO — before the gRPC pipeline is installed.
With a bare pipeline, NIO has nowhere to send the bytes and discards
them.
- Buffer until ClientConnectionHandler is in the pipeline so it can
process the SETTINGS frame and fire .ready, then schedule delivery of
the buffered data with assumeIsolatedUnsafeUnchecked().execute.
- To help produce more accurate merged logs, defines a
`StderrLogHandler` in the vminitd Application.swift that writes
timestamps to the boot log with millisecond precision and format
identical to that of the log files created using the `--log-root` arg on
`container`.
- Updates hawkeye to latest version (v6.5.1).

---------

Co-authored-by: Danny Canter <danny_canter@apple.com>
2026-03-13 12:26:09 -07:00
Dmitry Kovba 28f1c5a9b5 Apply sysctls from the OCI spec (#580)
Applies sysctls from the OCI spec.
2026-03-12 20:46:16 -07:00
Danny Canter 1be13d1d76 LinuxContainer: Support copying directories (#571)
Now that the static linux SDK we use has libarchive linked against it,
we can finally live our dream (/s) of supporting copying directories
in/out a little easier. This was.. kind of annoying. I think the very
simple route of writing archive to guest/host -> streaming over grpc is
simplest, but on the guest end we have a couple problems:

1. The VMs rootfs is read only today always, which is a good thing to me
and I don't want to change if we don't have to.
2. Writing the archive to the containers rootfs temporarily could work,
but it's a bit weird, and the user can make the containers rootfs
readonly which would screw that plan.
3. We could write it to /run or /tmp, but they're tmpfs and dealing with
the headache of the user possibly tarring an enormous dir is one I don't
want to care about.

So, that leaves us with the (truthfully better to me) approach of trying
to write the tar data directly to the host and skipping grpc which kinda
forces us to have a temp spot. Because of that, I made it such that we
pass a port number from host<->guest, and transfer the actual data
(either the single file or tarred dir contents) over the vsock port
instead. The stream is kinda clunky, but it just serves as a means to
exchange metadata and a "we're done" signifier.
2026-03-06 15:30:00 -08:00
Danny Canter 284db2ffea Capabilities: Make case insensitive (#558) 2026-02-25 05:43:04 -08:00
jwhur a16dee6468 Preserve error from ManagedProcess (#555)
This PR changes `ManagedProcess` to throw its own error together with
`vexec` error.

apple/container#1250 reports intermittent failure of CI tests, where the
system logs report failing `agent.startProcess` due to the `"read ack
pipe"` from `vmexec`.

This `"read ack pipe"` is thrown when writing end of `ackPipe` is closed
([ExecCommand.swift#L88](https://github.com/apple/containerization/blob/main/vminitd/Sources/vmexec/ExecCommand.swift#L88))
as EOF is returned from reading `ackPipe`.

It again means `ManagedProcess` throws an error after forking the
`vmexec` process
([ManagedProcess.swift#L165](https://github.com/apple/containerization/blob/main/vminitd/Sources/vminitd/ManagedProcess.swift#L165)).

However, current `ManagedProcess` doesn't throw its error if `errorPipe`
has data, which, i.e., `"read ack pipe"`, is actually not the root cause
in this case
([ManagedProcess.swift#L244](https://github.com/apple/containerization/blob/main/vminitd/Sources/vminitd/ManagedProcess.swift#L244)).
2026-02-24 00:39:27 -08:00
William Tan 0f7e3a5a33 vmexec: Pass through process env for ExecCommand (#550)
This mirrors the logic already in place for RunCommand and will allow
the PATH environment variable to get picked up properly.
2026-02-22 17:09:05 -08:00
jwhur 185bc1ecd7 vminitd: read errorPipe instead of syncPipe (#547)
ManagedProcess should read errorPipe until EOF to get any error message
from vmexec.
2026-02-21 05:38:46 -08:00
Danny Canter 32cf8c4d32 vminitd: Implement minimal init process to reap zombies (#537)
There are some workloads that benefit from having a "true" init process
that reaps zombies. This change implements a minimal init as part of
vminitd and exposes an API to be able to use this init process in our
containers. signals will be forwarded, any child procs will be reaped
and the exit code of the actual workload will be propagated. The
LinuxContainer/LinuxPod API is a very simple bool to ask to use this as
our init process, and the init simply spawns whatever command you want
as a child underneath this.

```
➜  ./bin/cctl run --kernel bin/kernel.arm64 --init
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /.cz-init -- /bin/sh
    2 root      0:00 /bin/sh
    3 root      0:00 ps aux
```
2026-02-20 16:22:36 -08:00
Yibo Zhuang 6cb52e2465 vminitd: add anonymous memory and inactive file stats (#538)
These two stats are import to calculate the following
- wss bytes (memory usage - inactive files)
- rss bytes (anonymous memory)
- available bytes (limit - wss bytes)

Just exposing these two in `SandboxContext.proto` as we already collect
them in `readMemoryStats()` in `Cgroup2Manager`
2026-02-18 20:28:55 -08:00
Danny Canter cb3493b507 vminitd: Add ability to set log level (#531)
This adds a small flag named --log-level to be able to set the log level
of vminitd and the pause command. I imagine this won't be the last time
we'll have to add flags to vminitd so I went ahead and converted vminitd
to be a Argument Parser based binary as well.
2026-02-14 13:33:21 -08:00
Dmitry Kovba 7c7ed05e10 Add a public method to wait for the relay to complete (#529)
- Adds a public method to wait for the relay to complete when both
directions close
- Improves error handling
- Moves `UnixSocketRelayManager` into a separate file
- Renames `SocketRelay` to `UnixSocketRelay`
- Adds logs at the info level after converting other logs to the debug
level previously
2026-02-11 23:44:22 -08:00
Dmitry Kovba 3f9dcf60e6 Improvements to the process and network management commands (#381)
Improves the process and network management commands.
2026-02-09 13:19:54 -08:00
Dmitry Kovba a8b830550a Do not remove a socket file created by another service (#520)
- Fixes a bug where a socket file created by another service could be
removed
- Fixes log levels
- Improves access level
2026-02-09 13:19:33 -08:00
Anthony df5f0f336a Fix usage of "clean up" as verb (#507)
"clean up" is a verb, and "cleanup" is a noun. There are several
examples of the incorrect usage of "cleanup" as a verb in this
repository, including one in the public API (`cleanupOrphanedBlobs`).
For this public method, I've added a deprecation notice to the name with
the incorrect usage.
2026-02-04 09:14:25 -08:00
Danny Canter b2f8351668 vmexec: Add missing rlimits (#506)
We were missing:

RLIMIT_LOCKS, RLIMIT_MSGQUEUE, RLIMIT_NICE, RLIMIT_RTPRIO,
RLIMIT_RTTIME, and RLIMIT_SIGPENDING
2026-02-02 13:53:15 -08:00
Danny Canter d37f90048b vminitd: Set nofile rlimit to max (#498)
No reason to default to 65k
2026-01-28 16:45:25 -08:00
J Logan 7d4bd80fc8 Move setTime debug message to trace level. (#493)
- Closes #492.
2026-01-26 10:25:18 -08:00
Dmitry Kovba 1d9140cc8a Add a route when a gateway is outside a subnet (#488)
When we set a gateway outside a subnet in Linux, this fails with:
```
ip-route-add-default: netlink response indicates error, rc = -101 
```

To resolve the error, we should first add a route to the gateway outside
the subnet, which this PR does.
2026-01-22 18:57:46 -08:00
Danny Canter 26f3dcc796 LinuxProcess: Start stdin relay after process start (#478)
Fixes #477

Because we start piping stdin before process launch we can fill up the
guest pipe buffer before the process even starts. We'd need some
backpressure mechanism to handle this and slow consumers (register the
other end with epoll and buffer some data etc.), but we should probably
just start piping after the process is up and running. This change does
exactly that, as well as stops holding the process mutex while draining
stdin in the guest for `CloseStdin()`.

This fixes issues where we try and write > pipe_buf bytes through stdin.
Today this hangs.
2026-01-16 14:14:08 -08:00
Danny Canter 0e91de6124 vmexec: Use FoundationEssentials (#475)
Start the journey to try and remove the 30MiB ICU blob in this binary...
2026-01-16 10:11:45 -08:00