Commit Graph
247 Commits
Author SHA1 Message Date
Raj 636eef0eff Add catalog listing to RegistryClient (#564)
Adds a `catalog(prefix:)` method to `RegistryClient` that implements
`GET /v2/_catalog` with pagination and prefix-based filtering.
2026-02-27 17:17:57 -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
Raj 38d3f2b3d7 Fall back to the referrers tag schema when the referrers API is not available (#560)
Fall back to the referrers tag schema when the referrers API is not
available
2026-02-25 18:11:23 -08:00
Danny Canter 2bf2cedede Mount: Ensure symlinks stay scoped to rootfs (#559)
Today we don't resolve symlinks relative to the rootfs of the container
as ContainerizationOS.Mount did not handle this. This means trying to
mount something at /var/run (which typically is a symlink to /run in
most cases) would resolve to /run in the root of the VM. This change
adds some logic to handle this.

```
➜  ./bin/cctl run --kernel bin/kernel.arm64 --mount /Users/dcantah/foo:/var/run/foo bash
root@sandbox-vm:/# ls var/run/foo/
howdy
```
2026-02-25 14:29:34 -08:00
Danny Canter 284db2ffea Capabilities: Make case insensitive (#558) 2026-02-25 05:43:04 -08:00
Danny Canter 485bb6ec2c Integration: Fix network disable test (#557) 2026-02-25 05:42:23 -08:00
J Logan a092fc4bd2 Remove libzstd imports from ContainerizationArchive. (#554)
- Closes #532.
- Relocate all zstd calls down into CArchive, and export a function
zstd_decompress_fd(src_fd, dst_fd) that ContainerizationArchive can use.
This eliminates problems that can occur when treating Swift warnings as
errors in Xcode projects that use ContainerizationArchive.
2026-02-24 00:42:30 -08:00
Raj e6a5acdff2 Add OCI 1.1 subject, artifactType, and referrers API (#546)
This PR adds OCI Image Spec v1.1 artifact support. It extends Manifest,
Index, and Descriptor with the `subject` and `artifactType` fields, adds
a `referrers()` method to RegistryClient implementing the OCI
Distribution Spec v1.1 referrers API. Also, I've added some unit unit
tests for backward compatibility and roundtrip encpding of all new
fields
2026-02-23 12:09:16 -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
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
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
Maxime Grenu 86171acece ContainerizationOCI: raise Reference name limit to 255 to match OCI spec (#541)
## What

Raise the constant from 127 to 255 in `Reference.swift` and update the
derived `referenceTotalLengthMax` accordingly.

## Why

Closes #453.

The [OCI distribution
spec](https://github.com/opencontainers/distribution-spec/blob/main/spec.md)
states that the **name** component of an image reference (registry host
+ repository path) may be at most 255 bytes. The previous hard-coded
limit of 127 characters incorrectly rejected valid references that used
long registry hostnames or deep path hierarchies.

The old `referenceTotalLengthMax = 255` was also inconsistent: with a
127-char name cap, a 255-char total reference would only allow a very
short tag. The new value is derived explicitly as `nameTotalLengthMax
(255) + separator (1) + tagLengthMax (128) = 384`.

## How

- `nameTotalLengthMax`: 127 → 255
- `tagLengthMax`: new constant (128) documenting the maximum tag length
already enforced by the tag regex (`{0,127}` + leading char = 128
chars).
- `referenceTotalLengthMax`: computed from the two constants above (384)
rather than hard-coded to 255.

## Testing

Added three new cases in `ReferenceTests.swift`:
- ✅ Name of 128 characters (registry + path) — previously rejected, now
accepted
- ✅ Name of exactly 255 characters — at the OCI spec maximum, accepted
- ❌ Name of 256 characters — one over the limit, rejected
2026-02-20 11:37:42 -08:00
Dmitry Kovba 7dea6dfa66 Downgrade a relay error to a warning (#545)
- This PR downgrades a relay error that might be
  logged when a connection is closed to a warning.
- Related PR in apple/container#1238.
2026-02-19 19:43:37 -08:00
Yibo Zhuang 185b04af74 fix: explicit cast SHUT_WR and SHUT_RDWR to Int32 (#544)
This is needed in order to make sure containerization compiles
successfully in linux
2026-02-19 15:31:54 -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
J Logan c45e36e740 Adds cause chain to ContainerizationError.errorDescription. (#539)
- Fixes #540.
2026-02-18 19:21:36 -08:00
J Logan 48db741f45 Adds log observability for AsyncLock acquire and hold. (#536)
- For providing insight into slow XPC helper launch issues in CI.
2026-02-18 16:40:46 -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
Anthony 71a0b4577f Add LocalizedError conformance to ContainerizationError (#528)
Without `LocalizedError` conformance, calling `localizedDescription` on
a `ContainerizationError` falls back to the default representation
(e.g., "ContainerizationError.ContainerizationError error 1.") instead
of returning the actual error message. This makes it difficult to show
meaningful errors in a UI, where `localizedDescription` is the standard
way to get a user-facing string.
2026-02-11 15:42:08 -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
Saehej Kang 3f4eee7d2a [keychain]: add list function + update variable/parameter names (#502)
- Add a `list` function that is needed for the `container registry list`
command
- Updates to `KeychainHelper` and `KeychainQuery` variable/parameter
names
- Updates to test cases
2026-02-04 18:15:30 -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 Logan c3fe889a2f Fix for decompressing zstd with localpath URL. (#512)
- InputSource(url:) rejects URLs with nil scheme, which was what was
passed when running the `container system kernel set` integration test
with a local kernel archive path.
2026-02-02 20:32:07 -08:00
J Logan 258ad89d51 Disable pod single file mount test. (#511) 2026-02-02 16:23:57 -08:00
J Logan 3f36cba3bf Align kernel build version with Kata used in container. (#510)
- Also temporarily disable single file integration tests until they're
reliable.
2026-02-02 15:34:58 -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
Danny Canter a8758a6ab3 LinuxPod: Add back top-level dns/hosts (#501)
Upon further thought, we should probably support this at the pod level
and allow per container overrides. I've changed my mind on how tedious
it is to specify it on a per-container basis.
2026-01-28 14:23:19 -08:00
Stuart LangandClaude Opus 4.5 c8ddc8a826 Make EXT4.Inode properties public (#500)
## Summary

The `EXT4.Inode` struct is public but its properties were internal,
preventing external consumers from reading inode metadata. This change
makes the properties public to enable use cases like reading file
metadata (mode, uid, gid, timestamps) from ext4 filesystems.

Motivating use case: https://github.com/socktainer/socktainer/pull/169

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 13:53:20 -08:00
Aditya Ramani 3a0b79d7fb Check for wildcard when determining if proxy should be bypassed (#497)
The `shouldBypassProxy` method from `ProxyUtils.swift` did not account
for `NO_PROXY` entries of the form `*.host.com`
This PR adds an additional check to determine if the proxy should be
bypassed for a given host.
2026-01-28 09:55:45 -08:00
Danny Canter db113ffec9 LinuxPod: Support per container dns/hosts (#496)
This shouldn't have been pod level, and we had no way to set hosts today
either. This just exposes hosts and the dns configs per container now.
2026-01-27 10:11:32 -05:00
jwhur fd62f311b4 Shutdown VM gracefully from created state (#495)
This PR enables gracefully shutting down VM even when the
`LinuxContainer` is in `created` state.
2026-01-26 15:56:24 -08:00
1a017417bc LinuxContainer/LinuxPod: Single file support (#487)
Fixes #79

This adds support for single file (virtiofs based) mounts to the two
main container types. This is transparent, and doesn't need to be setup
by a user, so there is no visible API change. Virtiofs does not support
single file mounts today, and it would be less than ideal from a
security standpoint to just expose the parent directory of the file to
the vm and then bind mount in the file, so we chose the following:

1. Create a temp directory the container types will manage.
2. Hardlink in the file we want.
3. Share that tempdir into the vm.
4. Finally bind mount in the file into the container.

The main goal I wanted for this is to leave the logic out of the
`VirtualMachineInstance`. I really want this to just be a little dance
the container types do, and leave the vm out of it. Because of that,
most of the logic is shoved in a new `FileMountContext` type that does
the dirty tricks of rewriting what the user asked for to be a bind mount
from a temporary holding spot we'll use in the guest for these temp
directories.

One of the downsides to this is today the tempdirs are solely on the
main volume, so cross volume will need to copy the file to the tempdir,
so writes won't get written back.

Co-authored-by: Dean Coulstock <d_coulstock@apple.com>
Co-authored-by: Jaewon Hur <hurjaewon@snu.ac.kr>
2026-01-22 20:57:58 -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 db277344b4 Mount: Support single file bind mount (#486)
Add in a small bit to create an empty file if we're asking for a single
file bind mount. This also resolves a bug with us using the wrong target
path in one of the mount variants.
2026-01-22 13:49:00 -08:00
J Logan 8da5f2306d Move Bindable to ContainerizationExtras, fix binding bugs. (#481)
- Bindable is generally useful, so it makes sense to move it out of the
netlink library. Removed Equatable conformance from Bindable as this
isn't generally necessary (it's only used for unit tests in netlink).
- Fix some offset checks in a couple data binding functions and improve
the unit tests.
2026-01-21 15:34:10 -08:00
Danny Canter c4f1263594 cctl: Make networking macOS 26 only (#437)
There's no sane way to do networking in this tool on < 26, you have to
guess the bridge subnet.
2026-01-21 15:29:45 -08:00
J Logan dadfdcefae Adds opt-in precommit hook to check formatting. (#483) 2026-01-21 11:34:16 -08:00
Danny Canter 863380c5e1 Interface: Support custom mtu (#484)
We started the legwork awhile ago, but never exposed it to be
configurable by the container types.
2026-01-20 17:32:28 -08:00
Danny Canter 552d4ce759 Integration: Add simple test filtering (#479)
Just does simple string contains logic
2026-01-17 20:15:54 -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
J Logan 3e93416b9a Merge commit from fork
* Admit only valid OCI layout files when loading image.

- Adds `AdmissionMapper` protocol for validating archive
  member paths and normalizing them to relative paths
  under the extraction root directory.
- Renames `Reader.swift` to `ArchiveReader.swift` to
  match type name.
- Rework `TempDir` to address `NSString.utf8String`
  deprecation warning in Swift 6.2.3.
- Rework `ArchiveReader.extractContent()` to use an
  `AdmissionMapper` to validate and remap archive
   members before extracting.
- Adds `IdentityAdmissionWrapper` for naive extraction.
- Adds `NoSymlinkAdmissionWrapper` that only extracts
  regular files and directories under the extraction root.
- Adds `OCIImageAdmissionWrapper` that only extracts
  valid OCI image layout paths.
- Use `OCIImageAdmissionWrapper` for `cctl image load`
  and print rejected paths.

* PR feedback.

* Adds public init() for TrustedAdmissionMapper.

* Replace AdmissionMapper with more secure extraction.

- Adds FileDescriptor.mkdirSecure() to prevent
  root escapes on member pathnames, and to prevent
  symlink traversal.
- Adds FileDescriptor.unlinkRecursive() to
  facilitate overwrites when there are multiple
  archive entries with the same member path.
- Adds FileDescriptor.validateSymlinkTargetInRoot()
  to validate that extracted symlink targets do
  not escape the root.
- Rewrite ArchiveReader.extractContents() to use
  secure path functions.

* Remove unneeded symlink check, rename files.

* Simplify the lexical normalizer workaround.

* Reject member paths containing parent traversal components.

* Remove unused lexical normalization workaround.

* Fix leaking fds, extract absolute members as relative.
2026-01-15 12:52:02 -06:00