Commit Graph
180 Commits
Author SHA1 Message Date
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
Michael Crosby 59f599eed5 allow filter of descriptors on push (#703)
Signed-off-by: michael_crosby <michael_crosby@apple.com>
2026-04-27 16:57:20 -04:00
Danny Canter 46c8fd3269 LinuxContainer/LinuxPod: Expose withVirtualMachineInstance (#701) 2026-04-27 12:17:12 -07:00
Dmitry Kovba 41ffd07f3e Add a default route to the first interface only (#697)
Adds a default route to the first interface only.
2026-04-23 11:05:25 -04:00
Dmitry Kovba bbea928c9e Add a public constructor to HTTP2ConnectBufferingHandler.swift (#695)
Adds a public constructor to `HTTP2ConnectBufferingHandler.swift`. This
is a follow-up to https://github.com/apple/containerization/pull/694.
2026-04-21 15:57:25 -07:00
Aditya Ramani 7874529578 Make HTTP2ConnectBufferingHandler public temporarily (#694)
Make the `HTTP2ConnectBufferingHandler` class public temporarily so that
consumers of the containerization package may reuse it for other grpc
clients.
2026-04-21 15:29:37 -07:00
Danny Canter 47518e0738 LinuxContainer: Give 1 vcpu of overhead for guest (#684) 2026-04-14 00:19:40 -07:00
Danny Canter 833b07f4f5 vminitd (client): Turn off idle timeout (#680)
Closes: #678

There's no reason to have an idle timeout per connection as users may
use this library in many different ways. The grpc lib defaults to a 30
min idle timeout which could be trivially reached if instead of waiting
on the init process, you were waiting on a bunch of execs. NIO under the
hood asserts on ebadfs (which is good, but bad for this scenario..), so
lets turn off the timeout altogether.
2026-04-13 00:15:37 -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 8451a8427d Single file mounts: Add/fix up some comments (#675) 2026-04-09 10:21:07 -07:00
Danny Canter ab89983c56 Mounts: Change single file mounts to a different approach (#665)
Related to https://github.com/apple/container/issues/1251

Change to sharing in the parent directory, and then bind mounting in the
file into the container. This has the unfortunate reality of being less
secure, but the current approach is burdended by a couple things,
namely:

1. You can't share in files that are on a different volume
2. There is a Virtualization bug that causes spurious errors when trying
to open the file.

I've added a doc to go over the approach we've taken, and some
workarounds if the approach is not satisfactory.
2026-04-08 22:01:13 -07:00
Raj 636715513c Add multi-reference push to ImageStore (#661) 2026-04-07 16:41:58 -07:00
Danny Canter a1038a9841 make default goal compile on Linux (#648)
To be able to test vminitd/vmexec/linux specific packages on ci it'd be
a heck of a lot easier if `make` just worked. This should be the last
bit needed. The default goal currently compiles just fine after the
linux specific `make deps` is ran. Next in line would be adding decent
unit tests/actually getting ci setup for the linux bits.
2026-04-06 11:13:16 -07:00
Danny Canter 367c136705 VirtualMachineInstance: Make default impls public (#651) 2026-04-06 10:34:32 -07:00
Danny Canter 1d60473274 LinuxPod: Remove macOS ifdef (#643)
It compiles fine on non-macOS
2026-04-03 12:31:42 -07:00
Danny Canter 3c4215702b LinuxContainer/LinuxPod: Sort mounts by depth (#601) 2026-04-03 10:28:47 -07:00
Anthony 35f97f225d Add progress handler for rootfs unpacking (#515)
I've added an optional progress handler for rootfs unpacking so that
consumers can show progress. The Ubuntu image takes about 8 seconds to
unpack on my machine, and I'm developing an app where it would be useful
to show progress in the UI.

Total size is determined in an optional first pass that scans archive
headers. Bytes written are then reported during unpacking. The optional
first pass adds 15 (Alpine) to 115 (Ubuntu) ms to unpacking duration on
my machine, depending on image size.
2026-04-02 17:33:55 -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 8615e3b021 Remove more incorrect os gates (#632)
A lot of logic we have works perfectly fine on other OS'.
2026-04-02 10:12:55 -07:00
Danny Canter 4c28821fef LinuxContainer: Move memory clamping to VZ code (#630)
The memory limit (clamp to system ram) is a VZ limitation so it's weird
that we had that logic directly in LinuxContainer. Someone could make a
VZVirtualMachineInstance that doesn't have this limitation but we
inherit this logic because it's done before passing off the memory
amount to the VMM.
2026-04-01 20:17:14 -07:00
Danny Canter baccf3f44b Hash: Make package visibility/remove ifdef (#631)
These build fine on Linux, and I don't honestly know why we had
hashMountSource as public API..
2026-04-01 19:45:53 -07:00
Danny Canter 220042089b Remove LinuxContainer.setupIO (#627)
Dead code
2026-04-01 13:57:43 -07:00
Danny Canter c5c1500eac Remove some unneeded Foundation imports (#613) 2026-03-30 17:00:58 -07:00
Maxime Grenu 1951816427 fix(dns): validate nameserver addresses are valid IP addresses (#534)
## What

Add a `DNS.validate()` method that verifies all nameserver entries are
valid IPv4 or IPv6 addresses. The method is called from
`Vminitd.configureDNS()` before applying the configuration.

## Why

Closes #467. Currently, any arbitrary string can be passed as a
nameserver in `DNSConfiguration`, which silently results in an invalid
`/etc/resolv.conf` inside the container. Hostname strings like
`dns.example.com` would be written to resolv.conf but would not work as
nameservers.

## How

- Added `DNS.validate() throws` method in `DNSConfiguration.swift` that
iterates over all nameservers and attempts to parse each as either an
`IPv4Address` or `IPv6Address` (using the existing parsers in
`ContainerizationExtras`)
- Added `import ContainerizationExtras` to `DNSConfiguration.swift` (the
`Containerization` target already depends on `ContainerizationExtras`)
- Called `config.validate()` at the start of `Vminitd.configureDNS()` so
validation happens before any GRPC call

## Testing

Added 6 new unit tests in `DNSTests.swift`:
- ✅ Valid IPv4 nameservers accepted
- ✅ Valid IPv6 nameservers accepted  
- ✅ Mixed IPv4/IPv6 nameservers accepted
- ✅ Empty nameserver list accepted
- ❌ Hostname rejected
- ❌ Invalid address rejected

## Checklist

- [x] Tests added
- [x] No breaking changes to existing API (validate() is a new method,
existing init is unchanged)
- [x] Follows existing patterns (uses ContainerizationExtras IP address
types, ContainerizationError for errors)

Signed-off-by: Maxime Grenu <maxime.grenu@gmail.com>
2026-03-25 02:40:07 -07:00
Danny Canter d8fcd1e9ca Network: Move to standalone type (#584)
The network protocol and VMNetNetwork implementation currently are
housed on ContainerManager even though they are generally useful types
even outside of this easy to use helper type. This change moves them to
not be nested types anymore, as well as exposes a new param on
VMNetNetworks constructor so we can pass the type of network.
2026-03-19 11:33:46 -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
Dmitry Kovba 8df7ce78d7 Enforce progress event value types (#579)
Enforces progress event value types.
2026-03-17 09:23:45 -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 622d102b8e Fix a potential filesystem corruption on virtio block devices (#576)
Enable the caching mode for virtio block devices to fix a potential
filesystem corruption. Also see
https://github.com/apple/container/pull/1041.
2026-03-12 20:17:30 -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 7064cbab40 vminitd: Bump Swift version to 6.3-snapshot (#570)
Closes #221

This contains (in the static linux sdk but the swift version and the sdk
must match) libarchive support and mimalloc! This also (unrelated to the
sdk bump it seems) raises the amount of retries we do when dialing
vminitd. It seems CI on rare occasions recently has timed out on some
tests. We could also explore just lowering the concurrency on the
integration suite.
2026-03-04 19:11:46 -08:00
Danny Canter 6f9ae02933 LinuxContainer/LinuxPod: Fix UDS proxy if target is symlink (#568)
Closes #256

If the target of the uds proxy goes through a symlink (/var/run) we had
the same bug we had with mounts previously where we'd follow this and if
the resolved path existed in the root of the VM we'd end up mounting
there. Fix this by plopping the sockets in a holding spot and then bind
mounting them in (which has the correct resolution logic).
2026-03-03 10:41:28 -08:00
Yibo Zhuang bacd99619f linux pod: exec process should inherit container's process config (#562)
This change fixes an issue in linux pod where the exec process
does not inherit the container process config which means any
environment variables, working directory, user, rlimits,
capabilities would be different for the exec process.

This change ensures that exec process would inherit
environment variables, working directory, user, rlimits,
and capabilities from the container process config but
resets arguments, terminal, and stdio as those should not
be inherited.

This change also adds an integration test to exercise this.
2026-02-26 21:22:52 -08:00
Danny Canter 205ccc7774 LinuxPod: Add hostname field on pod config (#561)
Just like we have for hosts and dns configurations, we can add a
hostname field to make it easier to setup if every container is going to
be using the same hostname.
2026-02-26 13:41:40 -08:00
Anthony b6b95ac897 Add per-container networking flag to ContainerManager.create() (#549)
This PR adds a `networking: Bool = true` parameter to
`ContainerManager.create()` so callers can opt out of network interface
creation on a per-container basis.

## Motivation

Currently, `ContainerManager.create()` unconditionally allocates a vmnet
network interface for every container (when the manager has a network
configured). Some use cases don't need network access and benefit from
having it disabled to reduce attack surface.

There's no way to achieve this today without either:
- Initializing the `ContainerManager` without a network (which disables
networking for *all* containers)
- Clearing `config.interfaces` in the configuration closure (which
wastes an IP allocation from the vmnet pool since `network.create(id)`
has already been called)

## Changes

- Add `networking: Bool = true` to all three `create()` overloads on
`ContainerManager`
- When `false`, `self.network?.create(id)` is skipped entirely. No
interface is allocated, and no DNS is configured.
- `releaseNetwork`/`delete` remain safe to call regardless, since
`Allocator.release` silently ignores unknown IDs.
- Add unit test `testNetworkingFalseSkipsInterfaceCreation` using the
existing `NilGatewayNetwork` fixture
- Add integration tests `testNetworkingDisabled` and
`testNetworkingEnabled` that create containers through a network-enabled
`ContainerManager` and verify the presence/absence of `eth0` via
`/sys/class/net/`
2026-02-22 17:08:49 -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
Danny Canter 061bc0a071 LinuxContainer: Add support for optional writable layer (#533)
This adds support to LinuxContainer to be able to provide an optional
writable layer. This is useful as today the rootfs size is determined by
the size of the image block itself which is set in stone at unpack time
of the image. This leaves a lot to be desired because a user might want
a larger or smaller rootfs size, but it's not configurable on a per
container basis because of this. To support this, we can pass an
additional writable block device that we can overlayfs with the image
contents in the guest. All writes will go to this writable layer, and
the rootfs size in the container is now whatever size this writable
layer is.

The block devices (via our ext4 package, but you could use whatever) are
cheap enough to generate on the fly that you can choose whatever size
you want easily.
2026-02-19 15:27:43 -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
Dmitry Kovba 36002eed5e Fix the socket relay error handling and log level (#535)
- Downgrades a warning to the debug level in `BidirectionalRelay`
because the shutdown syscall isn't supported for certain socket types
- Rethrows an error if we can't start a socket relay
2026-02-18 15:55:50 -08:00
Anthony 9bce347f50 Add releaseNetwork method to ContainerManager (#527)
I've extracted the network cleanup step from `delete` into a new public
`releaseNetwork` method. This mirrors the existing `release` on
`VmnetNetwork` and enables stop-and-restart workflows where the network
allocation needs to be freed without removing the container's rootfs.

## Changes

- Add `ContainerManager.release(_:)` — frees network resources for a
container after it has stopped
- Refactor `delete(_:)` to call `releaseNetwork(_:)` before removing
files, preserving existing behavior

## Motivation

Currently the only way to free a container's network allocation is
`delete`, which also removes its files. This makes it impossible to stop
a container (freeing the network so the ID can be re-allocated) and
later restart it with its filesystem intact. The new `releaseNetwork `
method fills this gap.
2026-02-12 12:11:29 -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
Manoj Mahapatra 98391937da Guard against if ipv4Gateway is nil, removed fore unwrap (#524)
- Guarded against ipv4Gateway if nil and throw
`ContainerizationError(.invalidState, ...)` instead of force unwraping
- Added a unit test
`ContainerManagerTests.testCreateThrowsWhenGatewayMissing`
2026-02-10 22:20:03 -08:00
Danny Canter 39aeac3f19 LinuxContainer/LinuxPod: Support duplicate virtiofs mounts (#522)
If we have the same source we should dedupe these. Previously
virt.framework would yell at us for a duplicate tag because we derive
the tag from hashing the mount source.
2026-02-09 11:06:53 -08:00
Dmitry Kovba 69bc038b30 Refactor a bidirectional relay and fix bugs (#516)
Changes:
- Refactors a bidirectional relay into a new class
- Makes the unique identifier for a socket configuration public

Bug fixes:
- Fixes a bug where partial writes didn't advance the pointer
- Fixes a buffer memory leak
- Fixes error messages
- Fixes log messages
- Fixes log levels
2026-02-05 16:50:45 -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
J LoganandAditya Ramani 1b50c817b6 Adds zstd decompression for layer content blobs. (#508)
- Closes apple/container#988.
- macOS libarchive is not built with zstd support, so the workaround in
ArchiveReader is to attempt to decompress every archive as zstd. If
decompression fails, we pass the original archive to libarchive. If it
succeeds, we pass the uncompressed archive.
- Adds blob media type recognition for zstd to EXT4Unpacker. Tested zstd
blob unpack using `image pull tonistiigi/hello-world:zstd-docker`.

Co-authored-by: Aditya Ramani <a_ramani@apple.com>
2026-02-02 13:10:22 -08:00
Danny Canter 92b02fc497 LinuxRLimit.Kind: Add string constructor (#504)
The OCI representation (just strings of the enum names) should be able
to be passed for convenience.
2026-01-30 17:09:36 -08:00
Danny Canter dd60ac3ab7 Add LinuxRLimit type (#499)
I was not a huge fan of how rlimits were specified using the OCI type as
it just takes in strings for the type which isn't super ergonomic. This
adds a new type for rlimits that we can convert to oci type like we
already do for capabilities.
2026-01-29 14:10:39 -08:00