runc and the OCI hooks it spawns are separate processes, so the trace
context can not reach them over ttrpc. Inject it into their environment
instead, riding on the request context via go-runc's WithExtraEnv, which
does not race with concurrent requests the way setting it on the shim
process would.
The otelttrpc interceptor extracts that context, so chain it first
explicitly instead of leaving it to plugin initialization order. Also
flush the spans the tracing plugin buffered before the shim exits.
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
Log fields which contain an error currently fall through to JSON
marshaling, which may produce an unhelpful value such as "{}" instead
of the error message.
Handle error values explicitly and use fmt.Sprint when formatting error
and fmt.Stringer values. Besides preserving their textual
representation, fmt handles typed-nil implementations without
propagating a panic from their Error or String method.
Also simplify the final fmt.Sprintf("%v", v) fallback to fmt.Sprint(v).
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Some rootfs may use symlinks for /etc/passwd and /etc/group. For example,
NixOS uses absolute symlinks to files in /nix/store. os.Root is not used
because it rejects absolute symlinks.
The previous code only handled a symlink on the final path. Add a helper to
resolve symlinks in every path component with fs.ReadLinkFS. Absolute symlinks
are resolved from the rootfs, and the final path is still opened with fs.FS.
When tracing a path through symbolic links, the maximum number of links that
can be followed is [40][1].
[1]: <https://man7.org/linux/man-pages/man7/path_resolution.7.html>
Signed-off-by: Wei Fu <fuweid89@gmail.com>
A pre-2.3 containerd daemon can start a newly installed shim through the
deprecated CLI, environment, and stdin API.
The shim currently accepts that request but returns a protobuf bootstrap
result, which the old daemon cannot parse.
It treats the protobuf bytes as a socket address and fails later with a
cryptic error:
```
failed to create TTRPC connection: unsupported protocol: \b\x03\x12Yunix
```
This patch makes the shim reject the deprecated startup request before
starting and tell the user that the containerd daemon may need to be
restarted.
The 2.2 daemon includes the shim's stderr in its start error, so this
message reaches the user directly.
This explicitly removes input-side support for the deprecated startup
API, but it does not break a working standard containerd pairing.
Pre-2.3 daemons already cannot consume the response from the new shim.
After a package upgrade, a restarted daemon uses the new bootstrap API.
Custom callers that send the deprecated request format while supporting
the new protobuf response will now also be rejected.
Signed-off-by: Paweł Gronowski <git@grono.dev>
The shim package could not be used by Windows shims due to missing implementation. This commit adds the Windows implementation for the shim package.
Signed-off-by: Harsh Rawat <harshrawat@microsoft.com>
Remove support for restoring checkpoint data during CreateContainer,
which was previously deprecated in v2.3.
Assisted-by: Antigravity
Signed-off-by: Samuel Karp <samuelkarp@google.com>
ParseSourceDateEpoch used strconv.ParseInt, which accepts a leading sign, so a
negative SOURCE_DATE_EPOCH was silently accepted and produced a pre-1970
timestamp with a nil error. That contradicts the function's own doc ("returns
an error if ... not well-formatted") and the reproducible-builds spec, where
SOURCE_DATE_EPOCH is a non-negative number of seconds since the Unix epoch.
Reject negative values and add a regression test.
Signed-off-by: Nikolaus Schuetz <nikolauspschuetz@gmail.com>
Build the image for TestIssue13030 locally using pkg/archive,
instead of pulling the prebuilt ghcr.io/containerd/whiteout-test image.
The image is built by appending layers generated with archive.WriteDiff
on top of the busybox base image, served with the new
testutil.ServeImage helper on a localhost HTTP registry, and pulled
through the regular client.Pull path with WithPullUnpack. This removes
the need to publish the multi-arch whiteout-test image, so the
Dockerfile and Makefile added in PR 13704 are removed along with the
image list entry.
Assisted-by: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
The package was moved to a separate module; update the links to
make it easier to discover the current version of upstream.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
`populateDefaultUnixSpec` uses `filepath.Join` to generate the default
`CgroupsPath`. On Windows, this produces invalid paths as path elems are
joined with backslash. Switch to `path.Join` instead.
Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
awaitPipeReady retried only when DialPipe returned os.IsNotExist or
context.DeadlineExceeded, but winio.DialPipe converts the per-attempt
deadline into winio.ErrTimeout before returning. A pipe in state 1
(ListenPipe called, Accept not yet called) causes DialPipe to block for
the full per-attempt timeout and return winio.ErrTimeout, which the old
check treated as a fatal error instead of retrying.
Also guard windows.ERROR_PIPE_BUSY explicitly to match the error checks
in containerd/nerdbox#218.
Adds a regression test that forces the state-1 to state-2 transition
race by delaying Accept past the 1-second per-attempt timeout.
Signed-off-by: Esteban Ginez <esteban.ginez@docker.com>
Image config labels are copied onto the container by both the CRI
plugin (BuildLabels) and the client's WithImageConfigLabels option
used by `ctr run`. Labels in the containerd.io/* namespace are
interpreted by containerd itself and labels in the io.cri-containerd*
namespace are interpreted by the CRI plugin. An image config is not a
trusted source for labels in either namespace.
Skip labels in both reserved namespaces when copying labels from an
image config to a container, and warn about each label skipped: an
image that tries to set them may be attempting to alter containerd
behavior. Oversized image labels are already skipped this way by
the CRI plugin.
Labels set explicitly by clients, for example via `ctr run --label`
or in the CRI request, are unaffected.
Verified with the CRI plugin and with `ctr run` against an image
whose config carries labels like these: the labels are no longer
present on the created container and a warning is logged for each.
Assisted-by: Claude Code
Signed-off-by: Ben Cressey <ben@cressey.org>
Signed-off-by: Samuel Karp <samuelkarp@google.com>
`strconv.NumError` implements `Unwrap` (see https://go.dev/cl/194563),
so there's no need to manually assert the type and unwrap.
Updates 9439355c2b
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
openUserFile now stats the opened file, refuses anything that is not a
regular file, and wraps the returned fs.File so reads are capped at
maxUserFileBytes (10 MiB). All callers of openUserFile read either
etc/passwd or etc/group; both are regular files on real systems, well
under the cap.
The cap and the regular-file check together bound parser memory use
when reading user-database files of unexpected shape or size.
Adds tests for the cap and for the non-regular file rejection. The cap
test covers three boundary points: a small pad (trailing entry parsed),
a pad placing the entry's last byte exactly on the cap (still parsed),
and a pad past the cap (read returns an "exceeds" error).
Assisted-by: Antigravity
Signed-off-by: Chris Henzie <chrishenzie@gmail.com>
Commit f9c80be1b removed varcheck linter, but some nolint:varcheck
annotations are still there, resulting in golangci-lint warning:
> WARN [runner/nolint_filter] Found unknown linters in //nolint directives: varcheck
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
InitRootFS was added in #1477 for potential future use but has no
callers either inside or outside this repository. Remove it along
with the associated Mounter interface, initializerFunc type,
createInitLayer helper, and the platform-specific init files that
only existed to support it.
Fixes#13238
Signed-off-by: Sanil2108 <sanilkhurana7@gmail.com>
Allow the socket directory to be directly configured by the shim manager
with reasonable defaults when not set. The default for root users will
still be the same directory under the default state directory. For
non-root users a temp directory will be used as default if the state
directory is not owned by the user.
Signed-off-by: Derek McGowan <derek@mcg.dev>
Send the socket directory from containerd to the shim. The shim still
decides where the socket goes but can use the environment variable
passed from containerd to ensure the socket is placed in the configured
directory with proper permission.
This is needed for some rootless cases which do not have permission to
the default state directory as currently set. The directory being
hardcoded by the shim means it is currently not possible to change the
location the shim will listen at.
Signed-off-by: Derek McGowan <derek@mcg.dev>
Avoid using logrus concepts in the API, use slog style log levels with
integer values and 0 meaning the default "info" level.
Signed-off-by: Derek McGowan <derek@mcg.dev>
- Use time.NewTimer + Stop() instead of time.After to avoid timer leaks
- Treat context.DeadlineExceeded as retryable (pipe busy, not just missing)
- Wrap last dial error instead of os.ErrNotExist for better diagnostics
- Update makeConnection godoc to reflect current BootstrapResult type
Signed-off-by: Esteban Ginez <esteban.ginez@docker.com>
The shim "start" helper returns the named pipe address before the
daemon process has created the pipe via winio.ListenPipe(). On busy
Windows systems, containerd may try to connect before the pipe exists.
Add awaitPipeReady() — the start helper now polls the pipe address
(up to 5s, 10ms intervals) before writing the bootstrap result to
stdout. This follows hcsshim's readiness pattern where the shim
verifies its endpoint is ready before signaling the parent.
As a safety net, also parameterize makeConnection() with a dialer so
binary.Start() uses AnonDialer (retry) for new shims while loadShim()
keeps AnonReconnectDialer (fail-fast) for reconnects per #3659.
On Unix, awaitPipeReady() is a no-op: domain sockets appear atomically.
Signed-off-by: Esteban Ginez <esteban.ginez@docker.com>