From abb6a439dd94b0f8ad3844d14cfc0d54436fc943 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Tue, 10 Sep 2024 09:40:55 +0200 Subject: [PATCH 01/47] Use nanosecond timestamp for evented pleg pod status Fixes https://github.com/cri-o/cri-o/issues/8580 Signed-off-by: Sascha Grunert --- server/sandbox_status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/sandbox_status.go b/server/sandbox_status.go index a5a5665dfc2..484e9abac21 100644 --- a/server/sandbox_status.go +++ b/server/sandbox_status.go @@ -41,7 +41,7 @@ func (s *Server) PodSandboxStatus(ctx context.Context, req *types.PodSandboxStat var containerStatuses []*types.ContainerStatus var timestamp int64 if s.config.EnablePodEvents { - timestamp = time.Now().Unix() + timestamp = time.Now().UnixNano() containerStatuses, err = s.getContainerStatusesFromSandboxID(ctx, req.PodSandboxId) if err != nil { return nil, status.Errorf(codes.Unknown, "could not get container statuses of the sandbox Id %q: %v", req.PodSandboxId, err) From 4b55a1107892814836dd2b1aced65356cfbc27a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Sun, 8 Sep 2024 00:31:30 +0900 Subject: [PATCH 02/47] Pin govulncheck to specific version to match Go version requirements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Wilczyński --- .github/workflows/test.yml | 4 ++-- dependencies.yaml | 6 ++++++ hack/govulncheck.sh | 29 +++++++++++++++++------------ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e68df20bdb9..b16cfb0b98f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -341,7 +341,7 @@ jobs: - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ env.GO_VERSION }} - - name: Run Govulncheck + - name: Run govulncheck run: make verify-govulncheck - - name: Run Gosec + - name: Run gosec run: make verify-gosec diff --git a/dependencies.yaml b/dependencies.yaml index 0e7581a21c5..ab87a703470 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -109,6 +109,12 @@ dependencies: - path: Makefile match: GO_MOD_OUTDATED_VERSION + - name: govulncheck + version: v1.1.3 + refPaths: + - path: hack/govulncheck.sh + match: GOVULNCHECK_VERSION + - name: gosec version: 2.19.0 refPaths: diff --git a/hack/govulncheck.sh b/hack/govulncheck.sh index 8554909789c..7dab2836ee9 100755 --- a/hack/govulncheck.sh +++ b/hack/govulncheck.sh @@ -1,34 +1,39 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail -# Install dependencies +# The govulncheck version should match supported Go version. +GOVULNCHECK_VERSION="v1.1.3" + +# Install build time dependencies. sudo apt-get update sudo apt-get install -y pkg-config libgpgme-dev libbtrfs-dev libseccomp-dev btrfs-progs -# Set environment variables +# Set environment variables. +export GOGC=off export GO111MODULE=on -export GOSUMDB=sum.golang.org -export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig -GOPATH_BIN=$(go env GOPATH)/bin -export PATH="$PATH:$GOPATH_BIN" +export GOSUMDB="sum.golang.org" +export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig" +GOPATH_BIN="$(go env GOPATH)"/bin +export PATH="${PATH}:${GOPATH_BIN}" -go install golang.org/x/vuln/cmd/govulncheck@latest +# Install govulncheck. +go install golang.org/x/vuln/cmd/govulncheck@${GOVULNCHECK_VERSION} -# Generate report +# Generate the report. report=$(mktemp) trap 'rm "$report"' EXIT "$GOPATH_BIN"/govulncheck -json -tags=test,exclude_graphdriver_devicemapper ./... >"$report" -# Parse vulnerabilities from report +# Parse vulnerabilities from the report. modvulns=$(jq -Sr '.vulnerability.modules[]? | select(.path != "stdlib") | [.path, "affected package(s): \(.packages[].path)", "found version: \(.found_version)", "fixed version: \(.fixed_version)"]' <"$report") libvulns=$(jq -Sr '.vulnerability.modules[]? | select(.path == "stdlib") | [.path, "affected package(s): \(.packages[].path)", "found version: \(.found_version)", "fixed version: \(.fixed_version)"]' <"$report") -# Print vulnerabilities +# Print vulnerabilities information, if any. echo "$modvulns" echo "$libvulns" -# Exit with non-zero status if there are any vulnerabilities in module dependencies +# Exit with non-zero status if there were any vulnerabilities detected in module dependencies. if [[ -n "$modvulns" ]]; then exit 1 fi From 2d27da0f3b96e5dc1d493456fdc102015136d35d Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Fri, 13 Sep 2024 15:15:30 -0400 Subject: [PATCH 03/47] image: serialize RegistryImageReferences when checking signatures So we can check a signature of an image that has both a tag and a digest Signed-off-by: Peter Hunt --- internal/storage/image.go | 18 ++------- .../storage/references/registry_reference.go | 20 +++++++++- test/policy.bats | 37 +++++++++++++++++++ 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/internal/storage/image.go b/internal/storage/image.go index 34201a500b7..3d41f320ce8 100644 --- a/internal/storage/image.go +++ b/internal/storage/image.go @@ -966,21 +966,9 @@ func (svc *imageService) CandidatesForPotentiallyShortImageName(systemContext *t images := make([]RegistryImageReference, len(resolved.PullCandidates)) for i := range resolved.PullCandidates { - // Strip the tag from ambiguous image references that have a - // digest as well (e.g. `image:tag@sha256:123...`). Such - // image references are supported by docker but, due to their - // ambiguity, explicitly not by containers/image. - ref := resolved.PullCandidates[i].Value - _, isTagged := ref.(reference.NamedTagged) - canonical, isDigested := ref.(reference.Canonical) - if isTagged && isDigested { - canonical, err = reference.WithDigest(reference.TrimNamed(ref), canonical.Digest()) - if err != nil { - return nil, err - } - ref = canonical - } - images[i] = references.RegistryImageReferenceFromRaw(ref) + // This function will strip the tag if both tag and digest are specified, as it's supported + // by Docker (and thus CRI-O by example) but not c/image. + images[i] = references.RegistryImageReferenceFromRaw(resolved.PullCandidates[i].Value) } return images, nil diff --git a/internal/storage/references/registry_reference.go b/internal/storage/references/registry_reference.go index e8f7de06393..59464ad6a48 100644 --- a/internal/storage/references/registry_reference.go +++ b/internal/storage/references/registry_reference.go @@ -12,7 +12,7 @@ import ( // // More specifically: // - The name always specifies a registry; it is not an alias nor a short name input to a search -// - The name contains a tag or digest; it does not specify just a repo. +// - The name contains a tag xor digest; it does not specify just a repo. // // This is intended to be a value type; if a value exists, it contains a valid reference. type RegistryImageReference struct { @@ -24,8 +24,22 @@ type RegistryImageReference struct { // RegistryImageReferenceFromRaw is an internal constructor of a RegistryImageReference. // // This should only be called from internal/storage. -// It’s the caller’s responsibility to provide a valid value (!IsNameOnly, and registry-qualified). +// It will modify the reference if both digest and tag are specified, stripping the tag and leaving the digest. +// It will also verifies the image is not only a name. If it is only a name, the function errors. func RegistryImageReferenceFromRaw(rawNamed reference.Named) RegistryImageReference { + _, isTagged := rawNamed.(reference.NamedTagged) + canonical, isDigested := rawNamed.(reference.Canonical) + // Strip the tag from ambiguous image references that have a + // digest as well (e.g. `image:tag@sha256:123...`). Such + // image references are supported by docker but, due to their + // ambiguity, explicitly not by containers/image. + if isTagged && isDigested { + canonical, err := reference.WithDigest(reference.TrimNamed(rawNamed), canonical.Digest()) + if err != nil { + panic("internal error, reference.WithDigest was not passed a digest, which should not be possible") + } + rawNamed = canonical + } // Ideally this would be better encapsulated, e.g. in internal/storage/internal, but // that would require using a type defined with the internal package with a public alias, // and as of 2023-10 mockgen creates code that refers to the internal target of the alias, @@ -40,6 +54,8 @@ func RegistryImageReferenceFromRaw(rawNamed reference.Named) RegistryImageRefere // // It is only intended for communication with OUT-OF-PROCESS APIs, // like registry references provided by CRI by Kubelet. +// It will modify the reference if both digest and tag are specified, stripping the tag and leaving the digest. +// It will also verifies the image is not only a name. If it is only a name, the `latest` tag will be added. func ParseRegistryImageReferenceFromOutOfProcessData(input string) (RegistryImageReference, error) { // Alternatively, should we provide two parsers, one with docker.io/library and :latest defaulting, // and one only accepting fully-specified reference.Named.String() values? diff --git a/test/policy.bats b/test/policy.bats index 2e31b267821..935f40f9b16 100644 --- a/test/policy.bats +++ b/test/policy.bats @@ -204,3 +204,40 @@ SANDBOX_CONFIG="$TESTDATA/sandbox_config.json" [[ "$output" == *"SignatureValidationFailed"* ]] } + +@test "allow signed image with restrictive policy on container creation7 if already pulled (by tag and ID)" { + start_crio + crictl pull "$SIGNED_IMAGE" + # Insert "latest" tag into the repoDigests field, and use that as the reference + # CRI-O should filter out the :latest bit, so it's a valid reference for c/image + REPO_TAG_DIGEST=$(crictl inspecti "$SIGNED_IMAGE" | jq -r .status.repoDigests[0] | sed "s|@|:latest@|g") + stop_crio_no_clean + + SIGNATURE_POLICY="$RESTRICTIVE_POLICY" start_crio + POD_ID=$(crictl runp "$TESTDATA/sandbox_config.json") + CTR_CONFIG="$TESTDIR/config.json" + jq '.image.image = "'"$REPO_TAG_DIGEST"'" | .image.user_specified_image = "'"$REPO_TAG_DIGEST"'"' "$TESTDATA/container_config.json" > "$CTR_CONFIG" + + # Testing for container start failed not because of the signature, but of + # the missing command executable + run ! crictl create "$POD_ID" "$CTR_CONFIG" "$TESTDATA/sandbox_config.json" + [[ "$output" == *"unable to start container process"* || "$output" == *"No such file or directory"* ]] +} + +@test "deny unsigned image with restrictive policy on container creation7 if already pulled (by tag and ID)" { + start_crio + crictl pull "$UNSIGNED_IMAGE" + # Insert "latest" tag into the repoDigests field, and use that as the reference + # CRI-O should filter out the :latest bit, so it's a valid reference for c/image + REPO_TAG_DIGEST=$(crictl inspecti "$UNSIGNED_IMAGE" | jq -r .status.repoDigests[0] | sed "s|@|:latest@|g") + stop_crio_no_clean + + SIGNATURE_POLICY="$RESTRICTIVE_POLICY" start_crio + POD_ID=$(crictl runp "$TESTDATA/sandbox_config.json") + CTR_CONFIG="$TESTDIR/config.json" + jq '.image.image = "'"$REPO_TAG_DIGEST"'" | .image.user_specified_image = "'"$REPO_TAG_DIGEST"'"' "$TESTDATA/container_config.json" > "$CTR_CONFIG" + + run ! crictl create "$POD_ID" "$CTR_CONFIG" "$TESTDATA/sandbox_config.json" + + [[ "$output" == *"SignatureValidationFailed"* ]] +} From 7d4f035b5521867c5f4d768aabebdf448e9e451a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Rop=C3=A9?= Date: Fri, 5 Jul 2024 16:33:32 +0200 Subject: [PATCH 04/47] tests: improve wait_for_log to allow multiple calls for the same message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wait_for_log looks at crio logs and waits for the given message to appear. If the message is already in the logs, it gets out immediately. To allow waiting for another occurence of the same message, we're making it output the timestamp of the first occurence that it finds. The caller can keep that information and provide it as a second parameter to wait_for_log, in which case wait_for_log will start waiting for the message after the given timestamp. Signed-off-by: Julien Ropé --- test/helpers.bash | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/test/helpers.bash b/test/helpers.bash index 557b2bf5e70..41876c051f5 100644 --- a/test/helpers.bash +++ b/test/helpers.bash @@ -486,7 +486,28 @@ function reload_crio() { kill -HUP "$CRIO_PID" } +# wait_for_log [line to skip] +# +# Wait for a given log message in crio log file. +# +# If a second parameter is given, the log will be truncated from start to the +# first occurrence of the second parameter. This allow to catch messages after +# the given string. +# +# The function registers the timestamp of the first occurrence it finds to an +# environment variable "LAST_TIMESTAMP". +# This variable can then be used as the second parameter to the function, making +# sure that we can find repetitions of the same log messages over time. +# +# $1 : log message to wait for +# $2 : previous string that needs to be skipped +# function wait_for_log() { + export LAST_TIMESTAMP + local LOGFILE="$CRIO_LOG" + if [ "$2" != "" ]; then + LOGFILE=$(mktemp "$TESTDIR"/wait_for_log_XXXXXX) + fi CNT=0 while true; do if [[ $CNT -gt 50 ]]; then @@ -494,7 +515,18 @@ function wait_for_log() { exit 1 fi - if grep -iq "$1" "$CRIO_LOG"; then + if [ "$2" != "" ]; then + # create a temp log file containing only the logs after the given string + sed -e "1,/$2/d" <"$CRIO_LOG" >"$LOGFILE" + fi + status=0 # initialize the variable to make shellcheck happy + run grep -i -m 1 "$1" "$LOGFILE" + if [ "$status" -eq 0 ]; then + # register only the time part of the timestamp + # this should be a string with no space in it, and that is unique in the log + # NOTE: log time format = 2006-01-02T15:04:05.999999999Z + TIMESTAMP_REGEXP="[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}.[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}.[[:digit:]]*." + LAST_TIMESTAMP=$(echo "$output" | grep -oE "time=\"$TIMESTAMP_REGEXP" | cut -d" " -f2) break fi From a673a7ca44ea1a74bbfaaaeeafb3524ecb687086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Rop=C3=A9?= Date: Fri, 5 Jul 2024 16:55:51 +0200 Subject: [PATCH 05/47] test: fix empty pinned_images test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the test is doing multiple reloads, it was hard to use wait_for_log to synchronize on the end of the reload process. With the modification on wait_for_log to allow waiting for multiple occurences of a log message, we can simplify this test, and make sure it's actually in sync. Keeping only one "wait_for_log" calls should be enough then - no need for multiple synchronization points, and the config validation is done by the calls to "crictl images". Fixes: #8324 Signed-off-by: Julien Ropé --- contrib/test/ci/integration.yml | 1 - contrib/test/ci/vars.yml | 2 -- test/reload_config.bats | 6 +----- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/contrib/test/ci/integration.yml b/contrib/test/ci/integration.yml index 5a834028f55..ffba890204c 100644 --- a/contrib/test/ci/integration.yml +++ b/contrib/test/ci/integration.yml @@ -53,7 +53,6 @@ state: present loop: "{{ ['cgroups.bats'] | product(kata_skip_cgroups_tests) \ + ['command.bats'] | product(kata_skip_command_tests) \ - + ['reload_config.bats'] | product(kata_skip_reload_config) \ + ['crio-check.bats'] | product(kata_skip_crio_check_tests) \ + ['crio-wipe.bats'] | product(kata_skip_crio_wipe_tests) \ + ['ctr.bats'] | product(kata_skip_ctr_tests) \ diff --git a/contrib/test/ci/vars.yml b/contrib/test/ci/vars.yml index c3dbce56a2c..d6a2b21bc34 100644 --- a/contrib/test/ci/vars.yml +++ b/contrib/test/ci/vars.yml @@ -99,8 +99,6 @@ kata_skip_cgroups_tests: kata_skip_command_tests: - 'test "crio commands"' - 'test "log max boundary testing"' -kata_skip_reload_config: - - 'test "reload config should remove pinned images when an empty list is provided"' kata_skip_crio_check_tests: - 'test "storage directory check should wipe everything on repair errors"' kata_skip_crio_wipe_tests: diff --git a/test/reload_config.bats b/test/reload_config.bats index d6dd99f6aed..6461ca35a4d 100644 --- a/test/reload_config.bats +++ b/test/reload_config.bats @@ -276,9 +276,7 @@ EOF # Add a pinned image to the configuration printf '[crio.image]\npinned_images = ["%s", ""]\n' $EXAMPLE_IMAGE > "$CRIO_CONFIG_DIR"/01-overwrite reload_crio - wait_for_log 'Set config pinned_images to \\"quay.io/crio/fedora-crio-ci:latest\\"' wait_for_log "Configuration reload completed" - wait_for_log 'pinned_images = \[\\"quay.io/crio/fedora-crio-ci:latest\\"\]' # Verify that the image is pinned output=$(crictl images -o json | jq ".images[] | select(.repoTags[] == \"$EXAMPLE_IMAGE\") |.pinned") @@ -287,9 +285,7 @@ EOF # Remove the pinned image from the configuration printf '[crio.image]\npinned_images = []\n' > "$CRIO_CONFIG_DIR"/01-overwrite reload_crio - wait_for_log 'Set config pinned_images to \\"\[\]\\"' - wait_for_log "Configuration reload completed" - wait_for_log 'pinned_images = \[\]' + wait_for_log "Configuration reload completed" "$LAST_TIMESTAMP" # Verify that the image is no longer pinned output=$(crictl images -o json | jq ".images[] | select(.repoTags[] == \"$EXAMPLE_IMAGE\") |.pinned") From b6226b8a3d2890ba778b40385af90235e88e506c Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 26 Sep 2024 21:08:15 +0200 Subject: [PATCH 06/47] config: pass down PullOptions from the storage configuration maintain the PullOptions as read from the storage.conf file, so that we don't lose options like `convert_images` that are necessary to convert existing images to a format usable with composefs. Do not bother to expose this configuration in the crio drop-in configuration as the PullOptions API is still experimental in containers/storage. Signed-off-by: Giuseppe Scrivano --- pkg/config/config.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/config/config.go b/pkg/config/config.go index 6eddff51f64..b0504b77a8e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -159,6 +159,9 @@ type RootConfig struct { // StorageOption is a list of storage driver specific options. StorageOptions []string `toml:"storage_option"` + // PullOptions is a map of pull options that are passed to the storage driver. + pullOptions map[string]string + // LogDir is the default log directory where all logs will go unless kubelet // tells us to put them somewhere else. LogDir string `toml:"log_dir"` @@ -192,6 +195,7 @@ func (c *RootConfig) GetStore() (storage.Store, error) { ImageStore: c.ImageStore, GraphDriverName: c.Storage, GraphDriverOptions: c.StorageOptions, + PullOptions: c.pullOptions, }) } @@ -879,6 +883,7 @@ func DefaultConfig() (*Config, error) { ImageStore: storeOpts.ImageStore, Storage: storeOpts.GraphDriverName, StorageOptions: storeOpts.GraphDriverOptions, + pullOptions: storeOpts.PullOptions, LogDir: "/var/log/crio/pods", VersionFile: CrioVersionPathTmp, CleanShutdownFile: CrioCleanShutdownFile, @@ -1075,6 +1080,7 @@ func (c *RootConfig) Validate(onExecution bool) error { c.Root = store.GraphRoot() c.Storage = store.GraphDriverName() c.StorageOptions = store.GraphOptions() + c.pullOptions = store.PullOptions() } return nil From e9deb6cde38e136c60fe4e1428351adb72be38c9 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Tue, 1 Oct 2024 00:26:05 +0000 Subject: [PATCH 07/47] version: bump to 1.31.1 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index f7ec5a8733a..917ed1f113d 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.0" +const Version = "1.31.1" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From cae8a3ab588bb9678b360ed30525888c41bffe4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Wed, 2 Oct 2024 01:40:20 +0900 Subject: [PATCH 08/47] Cherry-pick changes from containers/common/pull#2185 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Wilczyński --- go.mod | 2 +- go.sum | 4 ++-- .../containers/common/pkg/subscriptions/subscriptions.go | 6 +++++- vendor/github.com/go-task/slim-sprig/v3/.gitattributes | 1 + vendor/modules.txt | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 vendor/github.com/go-task/slim-sprig/v3/.gitattributes diff --git a/go.mod b/go.mod index 14e8ef5f8b4..4caf8ff919e 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/containerd/typeurl v1.0.3-0.20220422153119-7f6e6d160d67 github.com/containernetworking/cni v1.2.3 github.com/containernetworking/plugins v1.5.1 - github.com/containers/common v0.60.2 + github.com/containers/common v0.60.3-0.20241001153533-18930ed8933b github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon-rs v0.6.5 github.com/containers/image/v5 v5.32.2 diff --git a/go.sum b/go.sum index ea3ccf09b2a..7f47fe27e7c 100644 --- a/go.sum +++ b/go.sum @@ -726,8 +726,8 @@ github.com/containernetworking/cni v1.2.3 h1:hhOcjNVUQTnzdRJ6alC5XF+wd9mfGIUaj8F github.com/containernetworking/cni v1.2.3/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M= github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+E5J/EcKOE4gQ= github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM= -github.com/containers/common v0.60.2 h1:utcwp2YkO8c0mNlwRxsxfOiqfj157FRrBjxgjR6f+7o= -github.com/containers/common v0.60.2/go.mod h1:I0upBi1qJX3QmzGbUOBN1LVP6RvkKhd3qQpZbQT+Q54= +github.com/containers/common v0.60.3-0.20241001153533-18930ed8933b h1:S6ziP2hPX0XombD5UNp6isvKqN8xcBjCavNvEDGRMsw= +github.com/containers/common v0.60.3-0.20241001153533-18930ed8933b/go.mod h1:I0upBi1qJX3QmzGbUOBN1LVP6RvkKhd3qQpZbQT+Q54= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/conmon-rs v0.6.5 h1:mxdEBF/pjBmryj1ABrTDUqxDyxoZrpo8A1/9+JNvtZU= diff --git a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go index ded66365bb4..a6538ffb908 100644 --- a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go +++ b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go @@ -11,6 +11,7 @@ import ( "github.com/containers/common/pkg/umask" "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" + securejoin "github.com/cyphar/filepath-securejoin" rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" "github.com/sirupsen/logrus" @@ -346,7 +347,10 @@ func addFIPSModeSubscription(mounts *[]rspec.Mount, containerRunDir, mountPoint, srcBackendDir := "/usr/share/crypto-policies/back-ends/FIPS" destDir := "/etc/crypto-policies/back-ends" - srcOnHost := filepath.Join(mountPoint, srcBackendDir) + srcOnHost, err := securejoin.SecureJoin(mountPoint, srcBackendDir) + if err != nil { + return fmt.Errorf("resolve %s in the container: %w", srcBackendDir, err) + } if err := fileutils.Exists(srcOnHost); err != nil { if errors.Is(err, os.ErrNotExist) { return nil diff --git a/vendor/github.com/go-task/slim-sprig/v3/.gitattributes b/vendor/github.com/go-task/slim-sprig/v3/.gitattributes new file mode 100644 index 00000000000..176a458f94e --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/v3/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/vendor/modules.txt b/vendor/modules.txt index af56a836d67..07866215e81 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -243,7 +243,7 @@ github.com/containernetworking/cni/pkg/version # github.com/containernetworking/plugins v1.5.1 ## explicit; go 1.20 github.com/containernetworking/plugins/pkg/ns -# github.com/containers/common v0.60.2 +# github.com/containers/common v0.60.3-0.20241001153533-18930ed8933b ## explicit; go 1.21.0 github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/apparmor/internal/supported From e0fe0960939d76509e94d22558df70c2634a5ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Tue, 15 Oct 2024 14:37:01 +0900 Subject: [PATCH 09/47] Cherry-pick changes from containers/storage/pull#2134 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Wilczyński --- go.mod | 2 +- go.sum | 4 +- .../github.com/containers/storage/userns.go | 87 +++++++++++++------ .../containers/storage/userns_unsupported.go | 14 +++ vendor/modules.txt | 2 +- 5 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 vendor/github.com/containers/storage/userns_unsupported.go diff --git a/go.mod b/go.mod index 4caf8ff919e..dd3a284e2ba 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/containers/image/v5 v5.32.2 github.com/containers/kubensmnt v1.2.0 github.com/containers/ocicrypt v1.2.0 - github.com/containers/storage v1.55.0 + github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18 github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 github.com/cpuguy83/go-md2man v1.0.10 github.com/creack/pty v1.1.23 diff --git a/go.sum b/go.sum index 7f47fe27e7c..da7970301f1 100644 --- a/go.sum +++ b/go.sum @@ -740,8 +740,8 @@ github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYgle github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= -github.com/containers/storage v1.55.0 h1:wTWZ3YpcQf1F+dSP4KxG9iqDfpQY1otaUXjPpffuhgg= -github.com/containers/storage v1.55.0/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= +github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18 h1:YRxFFfDzvXL7WY8OiCKYDbiWQcUPkA7f5mbcfwATHIE= +github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 h1:OoRAFlvDGCUqDLampLQjk0yeeSGdF9zzst/3G9IkBbc= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09/go.mod h1:m2r/smMKsKwgMSAoFKHaa68ImdCSNuKE1MxvQ64xuCQ= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= diff --git a/vendor/github.com/containers/storage/userns.go b/vendor/github.com/containers/storage/userns.go index 57120731be5..09919394c02 100644 --- a/vendor/github.com/containers/storage/userns.go +++ b/vendor/github.com/containers/storage/userns.go @@ -1,18 +1,21 @@ +//go:build linux + package storage import ( "fmt" "os" "os/user" - "path/filepath" "strconv" drivers "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/unshare" "github.com/containers/storage/types" + securejoin "github.com/cyphar/filepath-securejoin" libcontainerUser "github.com/moby/sys/user" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" ) // getAdditionalSubIDs looks up the additional IDs configured for @@ -85,40 +88,59 @@ const nobodyUser = 65534 // parseMountedFiles returns the maximum UID and GID found in the /etc/passwd and // /etc/group files. func parseMountedFiles(containerMount, passwdFile, groupFile string) uint32 { + var ( + passwd *os.File + group *os.File + size int + err error + ) if passwdFile == "" { - passwdFile = filepath.Join(containerMount, "etc/passwd") - } - if groupFile == "" { - groupFile = filepath.Join(groupFile, "etc/group") + passwd, err = secureOpen(containerMount, "/etc/passwd") + } else { + // User-specified override from a volume. Will not be in + // container root. + passwd, err = os.Open(passwdFile) } - - size := 0 - - users, err := libcontainerUser.ParsePasswdFile(passwdFile) if err == nil { - for _, u := range users { - // Skip the "nobody" user otherwise we end up with 65536 - // ids with most images - if u.Name == "nobody" { - continue - } - if u.Uid > size && u.Uid != nobodyUser { - size = u.Uid - } - if u.Gid > size && u.Gid != nobodyUser { - size = u.Gid + defer passwd.Close() + + users, err := libcontainerUser.ParsePasswd(passwd) + if err == nil { + for _, u := range users { + // Skip the "nobody" user otherwise we end up with 65536 + // ids with most images + if u.Name == "nobody" || u.Name == "nogroup" { + continue + } + if u.Uid > size && u.Uid != nobodyUser { + size = u.Uid + 1 + } + if u.Gid > size && u.Gid != nobodyUser { + size = u.Gid + 1 + } } } } - groups, err := libcontainerUser.ParseGroupFile(groupFile) + if groupFile == "" { + group, err = secureOpen(containerMount, "/etc/group") + } else { + // User-specified override from a volume. Will not be in + // container root. + group, err = os.Open(groupFile) + } if err == nil { - for _, g := range groups { - if g.Name == "nobody" { - continue - } - if g.Gid > size && g.Gid != nobodyUser { - size = g.Gid + defer group.Close() + + groups, err := libcontainerUser.ParseGroup(group) + if err == nil { + for _, g := range groups { + if g.Name == "nobody" || g.Name == "nogroup" { + continue + } + if g.Gid > size && g.Gid != nobodyUser { + size = g.Gid + 1 + } } } } @@ -309,3 +331,14 @@ func getAutoUserNSIDMappings( gidMap := append(availableGIDs.zip(requestedContainerGIDs), additionalGIDMappings...) return uidMap, gidMap, nil } + +// Securely open (read-only) a file in a container mount. +func secureOpen(containerMount, file string) (*os.File, error) { + tmpFile, err := securejoin.OpenInRoot(containerMount, file) + if err != nil { + return nil, err + } + defer tmpFile.Close() + + return securejoin.Reopen(tmpFile, unix.O_RDONLY) +} diff --git a/vendor/github.com/containers/storage/userns_unsupported.go b/vendor/github.com/containers/storage/userns_unsupported.go new file mode 100644 index 00000000000..e37c18fe438 --- /dev/null +++ b/vendor/github.com/containers/storage/userns_unsupported.go @@ -0,0 +1,14 @@ +//go:build !linux + +package storage + +import ( + "errors" + + "github.com/containers/storage/pkg/idtools" + "github.com/containers/storage/types" +) + +func (s *store) getAutoUserNS(_ *types.AutoUserNsOptions, _ *Image, _ rwLayerStore, _ []roLayerStore) ([]idtools.IDMap, []idtools.IDMap, error) { + return nil, nil, errors.New("user namespaces are not supported on this platform") +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 07866215e81..8ed2dcf93af 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -357,7 +357,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/storage v1.55.0 +# github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18 ## explicit; go 1.21 github.com/containers/storage github.com/containers/storage/drivers From f334f80c331fc382f2a41ed3d30d5c91423c601a Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Fri, 27 Sep 2024 14:59:57 -0400 Subject: [PATCH 10/47] config: fix validation of allowed annotations If an annotation was allowed twice by a workload or runtime it should be allowed in the resulting list. Also fix a comment and add a test Signed-off-by: Peter Hunt --- pkg/config/config.go | 12 ++++---- server/utils.go | 5 ++-- test/ctr.bats | 66 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index b0504b77a8e..75821dbba02 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1743,19 +1743,21 @@ func (r *RuntimeHandler) RuntimeSupportsMountFlag(flag string) bool { } func validateAllowedAndGenerateDisallowedAnnotations(allowed []string) (disallowed []string, _ error) { - disallowedMap := make(map[string]struct{}) + disallowedMap := make(map[string]bool) for _, ann := range annotations.AllAllowedAnnotations { - disallowedMap[ann] = struct{}{} + disallowedMap[ann] = false } for _, ann := range allowed { if _, ok := disallowedMap[ann]; !ok { return nil, fmt.Errorf("invalid allowed_annotation: %s", ann) } - delete(disallowedMap, ann) + disallowedMap[ann] = true } disallowed = make([]string, 0, len(disallowedMap)) - for ann := range disallowedMap { - disallowed = append(disallowed, ann) + for ann, allowed := range disallowedMap { + if !allowed { + disallowed = append(disallowed, ann) + } } return disallowed, nil } diff --git a/server/utils.go b/server/utils.go index 5e6b1507534..fa6fb09c725 100644 --- a/server/utils.go +++ b/server/utils.go @@ -211,9 +211,8 @@ func (s *Server) getResourceOrWait(ctx context.Context, name, resourceType strin // for which disallowed annotations will be filtered. They may be the same. // After this function, toFilter will no longer container disallowed annotations. func (s *Server) FilterDisallowedAnnotations(toFind, toFilter map[string]string, runtimeHandler string) error { - // Only one of these Filter* will actually do any filtering, as the runtime DisallowedAnnotations - // were scrubbed at the config validation step if there were workload AllowedAnnotations configured. - // When runtime level allowed annotations are deprecated, this will be dropped. + // Combine the two lists to create one. Both will ultimately end up filtering, and FilterDisallowedAnnotations + // will handle duplicates, if any. // TODO: eventually, this should be in the container package, but it's going through a lot of churn // and SpecAddAnnotations is already passed too many arguments allowed, err := s.Runtime().AllowedAnnotations(runtimeHandler) diff --git a/test/ctr.bats b/test/ctr.bats index 545abf031a5..7f341ccd3e7 100644 --- a/test/ctr.bats +++ b/test/ctr.bats @@ -1326,6 +1326,72 @@ function create_test_rro_mounts() { [ ! -f "$linked_log_path" ] } +@test "ctr log linking both runtime and workload" { + if [[ $RUNTIME_TYPE == vm ]]; then + skip "not applicable to vm runtime type" + fi + setup_crio + create_runtime_with_allowed_annotation logs io.kubernetes.cri-o.LinkLogs + create_workload_with_allowed_annotation io.kubernetes.cri-o.LinkLogs + start_crio_no_setup + + # Create directories created by the kubelet needed for log linking to work + pod_uid=$(head -c 32 /proc/sys/kernel/random/uuid) + pod_name=$(jq -r '.metadata.name' "$TESTDATA/sandbox_config.json") + pod_namespace=$(jq -r '.metadata.namespace' "$TESTDATA/sandbox_config.json") + pod_log_dir="/var/log/pods/${pod_namespace}_${pod_name}_${pod_uid}" + mkdir -p "$pod_log_dir" + pod_empty_dir_volume_path="/var/lib/kubelet/pods/$pod_uid/volumes/kubernetes.io~empty-dir/logging-volume" + mkdir -p "$pod_empty_dir_volume_path" + ctr_path="/mnt/logging-volume" + + ctr_name=$(jq -r '.metadata.name' "$TESTDATA/container_config.json") + ctr_attempt=$(jq -r '.metadata.attempt' "$TESTDATA/container_config.json") + + # Add annotation for log linking in the pod + jq --arg pod_log_dir "$pod_log_dir" --arg pod_uid "$pod_uid" '.annotations["io.kubernetes.cri-o.LinkLogs"] = "logging-volume" + | .log_directory = $pod_log_dir | .metadata.uid = $pod_uid' \ + "$TESTDATA/sandbox_config.json" > "$TESTDIR/sandbox_config.json" + pod_id=$(crictl runp "$TESTDIR"/sandbox_config.json) + + # Touch the log file + mkdir -p "$pod_log_dir/$ctr_name" + touch "$pod_log_dir/$ctr_name/$ctr_attempt.log" + + # Create a new container + jq --arg host_path "$pod_empty_dir_volume_path" --arg ctr_path "$ctr_path" --arg log_path "$ctr_name/$ctr_attempt.log" \ + ' .command = ["sh", "-c", "echo Hello log linking && sleep 1000"] + | .log_path = $log_path + | .mounts = [ { + host_path: $host_path, + container_path: $ctr_path + } ]' \ + "$TESTDATA"/container_config.json > "$TESTDIR/container_config.json" + ctr_id=$(crictl create "$pod_id" "$TESTDIR/container_config.json" "$TESTDIR/sandbox_config.json") + + # Check that the log is linked + ctr_log_path="$pod_log_dir/$ctr_name/$ctr_attempt.log" + [ -f "$ctr_log_path" ] + mounted_log_path="$pod_empty_dir_volume_path/$ctr_name/$ctr_attempt.log" + [ -f "$mounted_log_path" ] + linked_log_path="$pod_empty_dir_volume_path/$ctr_id.log" + [ -f "$linked_log_path" ] + + crictl start "$ctr_id" + + # Check expected file contents + grep -E "Hello log linking" "$mounted_log_path" + grep -E "Hello log linking" "$ctr_log_path" + grep -E "Hello log linking" "$linked_log_path" + + crictl exec --sync "$ctr_id" grep -E "Hello log linking" "$ctr_path"/"$ctr_id.log" + + # Check linked logs were cleaned up + crictl rmp -fa + [ ! -f "$mounted_log_path" ] + [ ! -f "$linked_log_path" ] +} + @test "ctr stop loop kill retry attempts" { FAKE_RUNTIME_BINARY_PATH="$TESTDIR"/fake FAKE_RUNTIME_ATTEMPTS_LOG="$TESTDIR"/fake.log From 677d91db34a9e6699927a1f36b39210ad9053192 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Fri, 1 Nov 2024 00:26:14 +0000 Subject: [PATCH 11/47] version: bump to 1.31.2 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 917ed1f113d..7c57fcf6bbb 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.1" +const Version = "1.31.2" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From c918a52d1ec601b814e3ffab3f21a0cf6676fd38 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Thu, 24 Oct 2024 10:56:52 +0200 Subject: [PATCH 12/47] nix: don't build gpgme with `--enable-fixed-path` Don't use the fixed path to allow searching in system local paths. Signed-off-by: Sascha Grunert --- nix/overlay.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nix/overlay.nix b/nix/overlay.nix index a1d2d6a9987..7f70150c7ba 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -3,7 +3,11 @@ let in self: super: { - gpgme = (static super.gpgme); + gpgme = (static super.gpgme).overrideAttrs (x: { + # Drop the --enable-fixed-path: + # https://github.com/nixos/nixpkgs/blob/9a79bc99/pkgs/development/libraries/gpgme/default.nix#L94 + configureFlags = self.lib.lists.remove "--enable-fixed-path=${self.gnupg}/bin" x.configureFlags; + }); libassuan = (static super.libassuan); libgpgerror = (static super.libgpgerror); libseccomp = (static super.libseccomp); From c65eb63b1ad069aefbf2ba5b80698246dfda1bbd Mon Sep 17 00:00:00 2001 From: Martin Sivak Date: Tue, 12 Nov 2024 13:35:31 +0100 Subject: [PATCH 13/47] RuntimeHandler inheritance This allows defining a RuntimeHandler with custom annotations or other fields while inheriting the runtime type from the default runtime. This behavior is useful for layered projects that are not in control of the runtime selection but need to tweak the specific behavior while inheriting the node global runtime. Signed-off-by: Martin Sivak --- docs/crio.conf.5.md | 3 +++ pkg/config/config.go | 4 ++++ pkg/config/config_test.go | 14 ++++++++++++++ pkg/config/reload.go | 10 ++++++++++ pkg/config/reload_test.go | 24 ++++++++++++++++++++++++ pkg/config/template.go | 5 +++++ 6 files changed, 60 insertions(+) diff --git a/docs/crio.conf.5.md b/docs/crio.conf.5.md index 068e5be6e92..b758404c427 100644 --- a/docs/crio.conf.5.md +++ b/docs/crio.conf.5.md @@ -345,6 +345,9 @@ Root directory used to store runtime data **runtime_type**="oci" Type of the runtime used for this runtime handler. "oci", "vm" +**inherit_default_runtime**=false +Override the runtime path, runtime config path, runtime root and runtime type from the default runtime on load. + **runtime_config_path**="" Path to the runtime configuration file, should only be used with VM runtime types diff --git a/pkg/config/config.go b/pkg/config/config.go index 75821dbba02..c84d0c347c1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -264,6 +264,10 @@ type RuntimeHandler struct { // Output of the "features" subcommand. // This is populated dynamically and not read from config. features runtimeHandlerFeatures + + // Inheritance request + // Fill in the Runtime information (paths and type) from the default runtime + InheritDefaultRuntime bool `toml:"inherit_default_runtime,omitempty"` } // Multiple runtime Handlers in a map. diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 03e58c0214c..66d93e192be 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -1458,6 +1458,20 @@ var _ = t.Describe("Config", func() { // Then Expect(err).ToNot(HaveOccurred()) }) + + It("should succeed with empty runtime type and runtime_config_path when inheriting from default", func() { + // Given + sut.Runtimes["inherited"] = &config.RuntimeHandler{ + RuntimeConfigPath: invalidPath, RuntimeType: "invalid", InheritDefaultRuntime: true, + } + err := sut.ReloadRuntimes(sut) + Expect(err).ToNot(HaveOccurred()) + + // When + err = sut.Validate(false) + // Then + Expect(err).ToNot(HaveOccurred()) + }) }) t.Describe("RuntimeHandlerFeatures", func() { diff --git a/pkg/config/reload.go b/pkg/config/reload.go index 0fef2bf987e..004cd629bd1 100644 --- a/pkg/config/reload.go +++ b/pkg/config/reload.go @@ -285,6 +285,16 @@ func (c *Config) ReloadRuntimes(newConfig *Config) error { return nil } + // Update the default runtime paths in all runtimes that are asking for inheritance + for _, runtime := range c.Runtimes { + if runtime.InheritDefaultRuntime { + runtime.RuntimePath = c.Runtimes[c.DefaultRuntime].RuntimePath + runtime.RuntimeType = c.Runtimes[c.DefaultRuntime].RuntimeType + runtime.RuntimeConfigPath = c.Runtimes[c.DefaultRuntime].RuntimeConfigPath + runtime.RuntimeRoot = c.Runtimes[c.DefaultRuntime].RuntimeRoot + } + } + if err := c.ValidateRuntimes(); err != nil { return fmt.Errorf("unabled to reload runtimes: %w", err) } diff --git a/pkg/config/reload_test.go b/pkg/config/reload_test.go index 8c1a77c72ae..5c07ecfc4bb 100644 --- a/pkg/config/reload_test.go +++ b/pkg/config/reload_test.go @@ -427,6 +427,30 @@ var _ = t.Describe("Config", func() { Expect(sut.Runtimes).To(HaveKeyWithValue("existing", newRuntime)) Expect(sut.Runtimes["existing"].PrivilegedWithoutHostDevices).To(BeTrue()) }) + + It("should inherit runtime config", func() { + // Given + newRuntime := &config.RuntimeHandler{ + RuntimePath: invalidPath, + InheritDefaultRuntime: true, + } + defaultRuntime := &config.RuntimeHandler{ + RuntimePath: existingRuntimePath, + } + newConfig := &config.Config{} + newConfig.DefaultRuntime = "default" + newConfig.Runtimes = make(config.Runtimes) + newConfig.Runtimes["default"] = defaultRuntime + newConfig.Runtimes["new"] = newRuntime + + // When + err := sut.ReloadRuntimes(newConfig) + + // Then + Expect(err).ToNot(HaveOccurred()) + Expect(sut.Runtimes).To(HaveKeyWithValue("new", newRuntime)) + Expect(sut.Runtimes["new"].RuntimePath).To(Equal(existingRuntimePath)) + }) }) t.Describe("ReloadPinnedImages", func() { diff --git a/pkg/config/template.go b/pkg/config/template.go index a45fba09cb9..099b918b20e 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -1231,6 +1231,7 @@ const templateStringCrioRuntimeRuntimesRuntimeHandler = `# The "crio.runtime.run # runtime_path = "/path/to/the/executable" # runtime_type = "oci" # runtime_root = "/path/to/the/root" +# inherit_default_runtime = false # monitor_path = "/path/to/container/monitor" # monitor_cgroup = "/cgroup/path" # monitor_exec_cgroup = "/cgroup/path" @@ -1251,6 +1252,9 @@ const templateStringCrioRuntimeRuntimesRuntimeHandler = `# The "crio.runtime.run # state. # - runtime_config_path (optional, string): the path for the runtime configuration # file. This can only be used with when using the VM runtime_type. +# - inherit_default_runtime (optional, bool): when true the runtime_path, +# runtime_type, runtime_root and runtime_config_path will be replaced by +# the values from the default runtime on load time. # - privileged_without_host_devices (optional, bool): an option for restricting # host devices from being passed to privileged containers. # - allowed_annotations (optional, array of strings): an option for specifying @@ -1321,6 +1325,7 @@ const templateStringCrioRuntimeRuntimesRuntimeHandler = `# The "crio.runtime.run {{ $.Comment }}runtime_path = "{{ $runtime_handler.RuntimePath }}" {{ $.Comment }}runtime_type = "{{ $runtime_handler.RuntimeType }}" {{ $.Comment }}runtime_root = "{{ $runtime_handler.RuntimeRoot }}" +{{ $.Comment }}inherit_default_runtime = {{ $runtime_handler.InheritDefaultRuntime }} {{ $.Comment }}runtime_config_path = "{{ $runtime_handler.RuntimeConfigPath }}" {{ $.Comment }}container_min_memory = "{{ $runtime_handler.ContainerMinMemory }}" {{ $.Comment }}monitor_path = "{{ $runtime_handler.MonitorPath }}" From d3f39eaa9368f88d1c5795d7e887f20b54268671 Mon Sep 17 00:00:00 2001 From: Martin Sivak Date: Tue, 19 Nov 2024 16:30:38 +0100 Subject: [PATCH 14/47] RuntimeHandler inheritance bug-fix The original PR missed few important bits - the reload code path was not the only one that loads configs - an empty RuntimePath has a special meaning and inheriting it does not inherit the parent runtime - golang does a copy during interation, not a reference and the updated values were forgotten - the unit test ignores some of the checks during CI when not on a bare metal This patch fixes all of these and adds better logging and also tests that actually catch the above mistakes. Signed-off-by: Martin Sivak --- pkg/config/config.go | 24 ++++++++++++++++++++++++ pkg/config/config_test.go | 33 +++++++++++++++++++++++++++++---- pkg/config/reload.go | 10 ---------- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index c84d0c347c1..262c42dd872 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1298,6 +1298,30 @@ func defaultRuntimeHandler() *RuntimeHandler { func (c *RuntimeConfig) ValidateRuntimes() error { var failedValidation []string + // Update the default runtime paths in all runtimes that are asking for inheritance + for name := range c.Runtimes { + if !c.Runtimes[name].InheritDefaultRuntime { + continue + } + + logrus.Infof("Inheriting runtime configuration %q from %q", name, c.DefaultRuntime) + + c.Runtimes[name].RuntimePath = c.Runtimes[c.DefaultRuntime].RuntimePath + // An empty RuntimePath causes cri-o to look for a binary named `name`, + // but we inherit from the default - look for binary called c.DefaultRuntime + // The validator will check the binary is valid below. + if c.Runtimes[name].RuntimePath == "" { + executable, err := exec.LookPath(c.DefaultRuntime) + if err == nil { + c.Runtimes[name].RuntimePath = executable + } + } + + c.Runtimes[name].RuntimeType = c.Runtimes[c.DefaultRuntime].RuntimeType + c.Runtimes[name].RuntimeConfigPath = c.Runtimes[c.DefaultRuntime].RuntimeConfigPath + c.Runtimes[name].RuntimeRoot = c.Runtimes[c.DefaultRuntime].RuntimeRoot + } + // Validate if runtime_path does exist for each runtime for name, handler := range c.Runtimes { if err := handler.Validate(name); err != nil { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 66d93e192be..53406344d9f 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -1274,6 +1274,28 @@ var _ = t.Describe("Config", func() { Expect(sut.Runtimes).To(HaveKey(config.DefaultRuntime)) }) + It("should succeed with additional runtime with inheritance", func() { + // Given + f := t.MustTempFile("config") + Expect(os.WriteFile(f, + []byte(` + [crio.runtime.runtimes.crun] + [crio.runtime.runtimes.foo] + inherit_default_runtime = true + `), 0), + ).To(Succeed()) + + // When + err := sut.UpdateFromFile(context.Background(), f) + + // Then + Expect(err).ToNot(HaveOccurred()) + Expect(sut.Runtimes).To(HaveLen(2)) + Expect(sut.Runtimes).To(HaveKey("foo")) + Expect(sut.Runtimes).To(HaveKey(config.DefaultRuntime)) + Expect(sut.Runtimes["foo"].InheritDefaultRuntime).To(BeTrue()) + }) + It("should fail when file does not exist", func() { // Given // When @@ -1464,13 +1486,16 @@ var _ = t.Describe("Config", func() { sut.Runtimes["inherited"] = &config.RuntimeHandler{ RuntimeConfigPath: invalidPath, RuntimeType: "invalid", InheritDefaultRuntime: true, } - err := sut.ReloadRuntimes(sut) - Expect(err).ToNot(HaveOccurred()) - // When - err = sut.Validate(false) + err := sut.ValidateRuntimes() + // Then Expect(err).ToNot(HaveOccurred()) + Expect(sut.Runtimes).To(HaveKey(sut.DefaultRuntime)) + Expect(sut.Runtimes).To(HaveKey("inherited")) + + // When + Expect(sut.Runtimes["inherited"].RuntimePath).To(Equal(sut.Runtimes[sut.DefaultRuntime].RuntimePath)) }) }) diff --git a/pkg/config/reload.go b/pkg/config/reload.go index 004cd629bd1..0fef2bf987e 100644 --- a/pkg/config/reload.go +++ b/pkg/config/reload.go @@ -285,16 +285,6 @@ func (c *Config) ReloadRuntimes(newConfig *Config) error { return nil } - // Update the default runtime paths in all runtimes that are asking for inheritance - for _, runtime := range c.Runtimes { - if runtime.InheritDefaultRuntime { - runtime.RuntimePath = c.Runtimes[c.DefaultRuntime].RuntimePath - runtime.RuntimeType = c.Runtimes[c.DefaultRuntime].RuntimeType - runtime.RuntimeConfigPath = c.Runtimes[c.DefaultRuntime].RuntimeConfigPath - runtime.RuntimeRoot = c.Runtimes[c.DefaultRuntime].RuntimeRoot - } - } - if err := c.ValidateRuntimes(); err != nil { return fmt.Errorf("unabled to reload runtimes: %w", err) } From 165504928b36ad85314a0c4923882a56b6eb2207 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Mon, 18 Nov 2024 12:52:25 +0100 Subject: [PATCH 15/47] Add `--pull-progress-timeout` / `pull_progress_timeout` option Add the option to be able to fine-tune the pull progress timeout or even disable it. Fixes #8764 and #8760 Follow-up on: https://github.com/cri-o/cri-o/pull/7887 Signed-off-by: Sascha Grunert --- completions/bash/crio | 1 + completions/fish/crio.fish | 1 + completions/zsh/_crio | 1 + docs/crio.8.md | 3 +++ docs/crio.conf.5.md | 3 +++ internal/criocli/criocli.go | 9 +++++++++ pkg/config/config.go | 16 +++++++++++----- pkg/config/template.go | 12 ++++++++++++ server/image_pull.go | 15 ++++++--------- test/image.bats | 13 +++++++++++++ 10 files changed, 60 insertions(+), 14 deletions(-) diff --git a/completions/bash/crio b/completions/bash/crio index 9c9b09112bc..1711ac3d219 100755 --- a/completions/bash/crio +++ b/completions/bash/crio @@ -106,6 +106,7 @@ h --profile-cpu --profile-mem --profile-port +--pull-progress-timeout --rdt-config-file --read-only --registries-conf diff --git a/completions/fish/crio.fish b/completions/fish/crio.fish index 09a4f887f76..da108573ce5 100644 --- a/completions/fish/crio.fish +++ b/completions/fish/crio.fish @@ -141,6 +141,7 @@ complete -c crio -n '__fish_crio_no_subcommand' -f -l profile -d 'Enable pprof r complete -c crio -n '__fish_crio_no_subcommand' -f -l profile-cpu -r -d 'Write a pprof CPU profile to the provided path.' complete -c crio -n '__fish_crio_no_subcommand' -f -l profile-mem -r -d 'Write a pprof memory profile to the provided path.' complete -c crio -n '__fish_crio_no_subcommand' -f -l profile-port -r -d 'Port for the pprof profiler.' +complete -c crio -n '__fish_crio_no_subcommand' -f -l pull-progress-timeout -r -d 'The timeout for an image pull to make progress until the pull operation gets canceled. This value will be also used for calculating the pull progress interval to --pull-progress-timeout / 10. Can be set to 0 to disable the timeout as well as the progress output.' complete -c crio -n '__fish_crio_no_subcommand' -f -l rdt-config-file -r -d 'Path to the RDT configuration file for configuring the resctrl pseudo-filesystem.' complete -c crio -n '__fish_crio_no_subcommand' -f -l read-only -d 'Setup all unprivileged containers to run as read-only. Automatically mounts the containers\' tmpfs on \'/run\', \'/tmp\' and \'/var/tmp\'.' complete -c crio -n '__fish_crio_no_subcommand' -l root -s r -r -d 'The CRI-O root directory.' diff --git a/completions/zsh/_crio b/completions/zsh/_crio index 81600dbe351..ec0a37b2553 100644 --- a/completions/zsh/_crio +++ b/completions/zsh/_crio @@ -131,6 +131,7 @@ it later with **--config**. Global options will modify the output.' '--profile-cpu' '--profile-mem' '--profile-port' + '--pull-progress-timeout' '--rdt-config-file' '--read-only' '--registries-conf' diff --git a/docs/crio.8.md b/docs/crio.8.md index 938c321fb6a..7c2bf007ec5 100644 --- a/docs/crio.8.md +++ b/docs/crio.8.md @@ -103,6 +103,7 @@ crio [--profile-mem]=[value] [--profile-port]=[value] [--profile] +[--pull-progress-timeout]=[value] [--rdt-config-file]=[value] [--read-only] [--root|-r]=[value] @@ -382,6 +383,8 @@ crio [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] **--profile-port**="": Port for the pprof profiler. (default: 6060) +**--pull-progress-timeout**="": The timeout for an image pull to make progress until the pull operation gets canceled. This value will be also used for calculating the pull progress interval to --pull-progress-timeout / 10. Can be set to 0 to disable the timeout as well as the progress output. (default: 10s) + **--rdt-config-file**="": Path to the RDT configuration file for configuring the resctrl pseudo-filesystem. **--read-only**: Setup all unprivileged containers to run as read-only. Automatically mounts the containers' tmpfs on '/run', '/tmp' and '/var/tmp'. diff --git a/docs/crio.conf.5.md b/docs/crio.conf.5.md index b758404c427..877bfb56db4 100644 --- a/docs/crio.conf.5.md +++ b/docs/crio.conf.5.md @@ -491,6 +491,9 @@ Path to the temporary directory to use for storing big files, used to store imag **auto_reload_registries**=false If true, CRI-O will automatically reload the mirror registry when there is an update to the 'registries.conf.d' directory. Default value is set to 'false'. +**pull_progress_timeout**="10s" +The timeout for an image pull to make progress until the pull operation gets canceled. This value will be also used for calculating the pull progress interval to pull_progress_timeout / 10. Can be set to 0 to disable the timeout as well as the progress output. + ## CRIO.NETWORK TABLE The `crio.network` table containers settings pertaining to the management of CNI plugins. diff --git a/internal/criocli/criocli.go b/internal/criocli/criocli.go index 13010c3d92e..408d158d833 100644 --- a/internal/criocli/criocli.go +++ b/internal/criocli/criocli.go @@ -407,6 +407,9 @@ func mergeConfig(config *libconfig.Config, ctx *cli.Context) error { if ctx.IsSet("auto-reload-registries") { config.AutoReloadRegistries = ctx.Bool("auto-reload-registries") } + if ctx.IsSet("pull-progress-timeout") { + config.PullProgressTimeout = ctx.Duration("pull-progress-timeout") + } if ctx.IsSet("separate-pull-cgroup") { config.SeparatePullCgroup = ctx.String("separate-pull-cgroup") } @@ -934,6 +937,12 @@ func getCrioFlags(defConf *libconfig.Config) []cli.Flag { EnvVars: []string{"AUTO_RELOAD_REGISTRIES"}, Value: defConf.AutoReloadRegistries, }, + &cli.DurationFlag{ + Name: "pull-progress-timeout", + Usage: "The timeout for an image pull to make progress until the pull operation gets canceled. This value will be also used for calculating the pull progress interval to --pull-progress-timeout / 10. Can be set to 0 to disable the timeout as well as the progress output.", + EnvVars: []string{"CONTAINER_PULL_PROGRESS_TIMEOUT"}, + Value: defConf.PullProgressTimeout, + }, &cli.BoolFlag{ Name: "read-only", Usage: "Setup all unprivileged containers to run as read-only. Automatically mounts the containers' tmpfs on '/run', '/tmp' and '/var/tmp'.", diff --git a/pkg/config/config.go b/pkg/config/config.go index 262c42dd872..dd094830ae6 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -566,6 +566,11 @@ type ImageConfig struct { // reload the mirror registry when there is an update to the // 'registries.conf.d' directory. AutoReloadRegistries bool `toml:"auto_reload_registries"` + // PullProgressTimeout is the timeout for an image pull to make progress + // until the pull operation gets canceled. This value will be also used for + // calculating the pull progress interval to pullProgressTimeout / 10. + // Can be set to 0 to disable the timeout as well as the progress output. + PullProgressTimeout time.Duration `toml:"pull_progress_timeout"` } // NetworkConfig represents the "crio.network" TOML config table. @@ -942,11 +947,12 @@ func DefaultConfig() (*Config, error) { EnableCriuSupport: true, }, ImageConfig: ImageConfig{ - DefaultTransport: "docker://", - PauseImage: DefaultPauseImage, - PauseCommand: "/pause", - ImageVolumes: ImageVolumesMkdir, - SignaturePolicyDir: "/etc/crio/policies", + DefaultTransport: "docker://", + PauseImage: DefaultPauseImage, + PauseCommand: "/pause", + ImageVolumes: ImageVolumesMkdir, + SignaturePolicyDir: "/etc/crio/policies", + PullProgressTimeout: 10 * time.Second, }, NetworkConfig: NetworkConfig{ NetworkDir: cniConfigDir, diff --git a/pkg/config/template.go b/pkg/config/template.go index 099b918b20e..ba98aad60d6 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -540,6 +540,11 @@ func initCrioTemplateConfig(c *Config) ([]*templateConfigValue, error) { group: crioImageConfig, isDefaultValue: simpleEqual(dc.AutoReloadRegistries, c.AutoReloadRegistries), }, + { + templateString: templateStringCrioImagePullProgressTimeout, + group: crioImageConfig, + isDefaultValue: simpleEqual(dc.PullProgressTimeout, c.PullProgressTimeout), + }, { templateString: templateStringCrioNetworkCniDefaultNetwork, group: crioNetworkConfig, @@ -1499,6 +1504,13 @@ const templateStringCrioImageAutoReloadRegistries = `# If true, CRI-O will autom ` +const templateStringCrioImagePullProgressTimeout = `# The timeout for an image pull to make progress until the pull operation +# gets canceled. This value will be also used for calculating the pull progress interval to pull_progress_timeout / 10. +# Can be set to 0 to disable the timeout as well as the progress output. +{{ $.Comment }}pull_progress_timeout = "{{ .PullProgressTimeout }}" + +` + const templateStringCrioNetwork = `# The crio.network table containers settings pertaining to the management of # CNI plugins. [crio.network] diff --git a/server/image_pull.go b/server/image_pull.go index d6f36e11432..0f65de89718 100644 --- a/server/image_pull.go +++ b/server/image_pull.go @@ -223,13 +223,13 @@ func (s *Server) pullImageCandidate(ctx context.Context, sourceCtx *imageTypes.S // Cancel the pull if no progress is made pullCtx, cancel := context.WithCancel(ctx) - go consumeImagePullProgress(ctx, cancel, progress, remoteCandidateName) + go consumeImagePullProgress(ctx, cancel, s.Config().PullProgressTimeout, progress, remoteCandidateName) _, repoDigest, err := s.StorageImageServer().PullImage(pullCtx, remoteCandidateName, &storage.ImageCopyOptions{ SourceCtx: sourceCtx, DestinationCtx: s.config.SystemContext, OciDecryptConfig: decryptConfig, - ProgressInterval: time.Second, + ProgressInterval: s.Config().PullProgressTimeout / 10, Progress: progress, CgroupPull: storage.CgroupPullConfiguration{ UseNewCgroup: s.config.SeparatePullCgroup != "", @@ -253,19 +253,16 @@ func (s *Server) pullImageCandidate(ctx context.Context, sourceCtx *imageTypes.S // It also checks if progress is being made within a constant timeout. // If the timeout is reached because no progress updates have been made, then // the cancel function will be called. -func consumeImagePullProgress(ctx context.Context, cancel context.CancelFunc, progress <-chan imageTypes.ProgressProperties, remoteCandidateName storage.RegistryImageReference) { - // The progress interval is 1s, but we give it a bit more time just in case - // that the connection revives. - const timeout = 10 * time.Second - timer := time.AfterFunc(timeout, func() { - log.Warnf(ctx, "Timed out on waiting up to %s for image pull progress updates", timeout) +func consumeImagePullProgress(ctx context.Context, cancel context.CancelFunc, pullProgressTimeout time.Duration, progress <-chan imageTypes.ProgressProperties, remoteCandidateName storage.RegistryImageReference) { + timer := time.AfterFunc(pullProgressTimeout, func() { + log.Warnf(ctx, "Timed out on waiting up to %s for image pull progress updates", pullProgressTimeout) cancel() }) timer.Stop() // don't start the timer immediately defer timer.Stop() // ensure that the timer is stopped when we exit the progress loop for p := range progress { - timer.Reset(timeout) + timer.Reset(pullProgressTimeout) if p.Event == imageTypes.ProgressEventSkipped { // Skipped digests metrics diff --git a/test/image.bats b/test/image.bats index e508c5bb06f..10ead5e7df5 100644 --- a/test/image.bats +++ b/test/image.bats @@ -382,3 +382,16 @@ EOF expected_output=$(date -d "@$datestr" +"%a %b %e %H:%M:%S %Z %Y") [[ "$output" == *"$expected_output"* ]] } + +@test "pull progress timeout should trigger when being set too low" { + CONTAINER_PULL_PROGRESS_TIMEOUT=1ms start_crio + + run ! crictl pull "$IMAGE_LIST_TAG" + [[ "$output" == *"context canceled"* ]] +} + +@test "pull progress timeout should not timeout when set to 0" { + CONTAINER_PULL_PROGRESS_TIMEOUT=0 start_crio + + crictl pull "$IMAGE_LIST_TAG" +} From 6aa6cbcb400bf1348dbd6a30f8f857c772007537 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 30 Sep 2024 14:37:13 +0000 Subject: [PATCH 16/47] Only restore container if all bind mounts are defined To avoid the situation where a container that is restored via a registry mounts unexpected host paths into the container, this changes the restore behaviour of CRI-O. Previously all bind mounted paths in the original container which were defined for example like this: volumeMounts: - mountPath: /data name: data-volume volumes: - name: data-volume hostPath: path: /srv/container/data Were automatically mounted in the restored container without and definition necessary. This lead to the situation that the user does not know which path will be mounted if starting a restored container. Now CRI-O will refuse to restore a container if not all bind mounts are defined via the CRI CreateContainer RPC in the CreateContainerRequest message. CRI-O will now return an error that will look something likes this: Error: the container to restore (7f...be) expects following bind mounts defined (/data,/data2) Now the user has to explicitly add those bind mounts in the same way as it was done during initial container creation. Signed-off-by: Adrian Reber --- server/container_restore.go | 132 ++++++++++++++---------------------- test/checkpoint.bats | 8 ++- 2 files changed, 57 insertions(+), 83 deletions(-) diff --git a/server/container_restore.go b/server/container_restore.go index 0b59cde95db..38325ed5709 100644 --- a/server/container_restore.go +++ b/server/container_restore.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "strings" metadata "github.com/checkpoint-restore/checkpointctl/lib" "github.com/containers/storage/pkg/archive" @@ -63,6 +64,10 @@ func (s *Server) CRImportCheckpoint( return "", errors.New(`attribute "image" missing from container definition`) } + if createConfig.Metadata == nil && createConfig.Metadata.Name == "" { + return "", errors.New(`attribute "metadata" missing from container definition`) + } + inputImage := createConfig.Image.Image createMounts := createConfig.Mounts createAnnotations := createConfig.Annotations @@ -152,69 +157,25 @@ func (s *Server) CRImportCheckpoint( ctrID = "" } - ctrMetadata := types.ContainerMetadata{} originalAnnotations := make(map[string]string) - originalLabels := make(map[string]string) - - if dumpSpec.Annotations[annotations.ContainerManager] == "libpod" { - // This is an import from Podman - ctrMetadata.Name = config.Name - ctrMetadata.Attempt = 0 - } else { - if err := json.Unmarshal([]byte(dumpSpec.Annotations[annotations.Metadata]), &ctrMetadata); err != nil { - return "", fmt.Errorf("failed to read %q: %w", annotations.Metadata, err) - } - if createConfig.Metadata != nil && createConfig.Metadata.Name != "" { - ctrMetadata.Name = createConfig.Metadata.Name - } - if err := json.Unmarshal([]byte(dumpSpec.Annotations[annotations.Annotations]), &originalAnnotations); err != nil { - return "", fmt.Errorf("failed to read %q: %w", annotations.Annotations, err) - } - - if err := json.Unmarshal([]byte(dumpSpec.Annotations[annotations.Labels]), &originalLabels); err != nil { - return "", fmt.Errorf("failed to read %q: %w", annotations.Labels, err) - } - if sandboxUID != "" { - if _, ok := originalLabels[kubetypes.KubernetesPodUIDLabel]; ok { - originalLabels[kubetypes.KubernetesPodUIDLabel] = sandboxUID - } - if _, ok := originalAnnotations[kubetypes.KubernetesPodUIDLabel]; ok { - originalAnnotations[kubetypes.KubernetesPodUIDLabel] = sandboxUID - } - } - - if createLabels != nil { - fixupLabels := []string{ - // Update the container name. It has already been update in metadata.Name. - // It also needs to be updated in the container labels. - kubetypes.KubernetesContainerNameLabel, - // Update pod name in the labels. - kubetypes.KubernetesPodNameLabel, - // Also update namespace. - kubetypes.KubernetesPodNamespaceLabel, - } - for _, annotation := range fixupLabels { - _, ok1 := createLabels[annotation] - _, ok2 := originalLabels[annotation] + if err := json.Unmarshal([]byte(dumpSpec.Annotations[annotations.Annotations]), &originalAnnotations); err != nil { + return "", fmt.Errorf("failed to read %q: %w", annotations.Annotations, err) + } - // If the value is not set in the original container or - // if it is not set in the new container, just skip - // the step of updating metadata. - if ok1 && ok2 { - originalLabels[annotation] = createLabels[annotation] - } - } + if sandboxUID != "" { + if _, ok := originalAnnotations[kubetypes.KubernetesPodUIDLabel]; ok { + originalAnnotations[kubetypes.KubernetesPodUIDLabel] = sandboxUID } + } - if createAnnotations != nil { - // The hash also needs to be update or Kubernetes thinks the container needs to be restarted - _, ok1 := createAnnotations["io.kubernetes.container.hash"] - _, ok2 := originalAnnotations["io.kubernetes.container.hash"] + if createAnnotations != nil { + // The hash also needs to be update or Kubernetes thinks the container needs to be restarted + _, ok1 := createAnnotations["io.kubernetes.container.hash"] + _, ok2 := originalAnnotations["io.kubernetes.container.hash"] - if ok1 && ok2 { - originalAnnotations["io.kubernetes.container.hash"] = createAnnotations["io.kubernetes.container.hash"] - } + if ok1 && ok2 { + originalAnnotations["io.kubernetes.container.hash"] = createAnnotations["io.kubernetes.container.hash"] } } @@ -271,8 +232,8 @@ func (s *Server) CRImportCheckpoint( } containerConfig := &types.ContainerConfig{ Metadata: &types.ContainerMetadata{ - Name: ctrMetadata.Name, - Attempt: ctrMetadata.Attempt, + Name: createConfig.Metadata.Name, + Attempt: createConfig.Metadata.Attempt, }, Image: &types.ImageSpec{ Image: rootFSImage, @@ -282,7 +243,9 @@ func (s *Server) CRImportCheckpoint( SecurityContext: &types.LinuxContainerSecurityContext{}, }, Annotations: originalAnnotations, - Labels: originalLabels, + // The labels are nod changed or adapted. They are just taken from the CRI + // request without any modification (in contrast to the annotations). + Labels: createLabels, } if createConfig.Linux != nil { @@ -319,6 +282,13 @@ func (s *Server) CRImportCheckpoint( "/run/.containerenv": true, } + // It is necessary to ensure that all bind mounts in the checkpoint archive are defined + // in the create container requested coming in via the CRI. If this check would not + // be here it would be possible to create a checkpoint archive that mounts some random + // file/directory on the host with the user knowing as it will happen without specifying + // it in the container definition. + missingMount := []string{} + for _, m := range dumpSpec.Mounts { // Following mounts are ignored as they might point to the // wrong location and if ignored the mounts will correctly @@ -328,40 +298,38 @@ func (s *Server) CRImportCheckpoint( } mount := &types.Mount{ ContainerPath: m.Destination, - HostPath: m.Source, } + bindMountFound := false for _, createMount := range createMounts { if createMount.ContainerPath == m.Destination { mount.HostPath = createMount.HostPath + mount.Readonly = createMount.Readonly + mount.RecursiveReadOnly = createMount.RecursiveReadOnly + mount.Propagation = createMount.Propagation + mount.RecursiveReadOnly = createMount.RecursiveReadOnly + bindMountFound = true } } - - for _, opt := range m.Options { - switch opt { - case "ro": - mount.Readonly = true - case "rro": - mount.RecursiveReadOnly = true - case "rprivate": - mount.Propagation = types.MountPropagation_PROPAGATION_PRIVATE - case "rshared": - mount.Propagation = types.MountPropagation_PROPAGATION_BIDIRECTIONAL - case "rslaved": - mount.Propagation = types.MountPropagation_PROPAGATION_HOST_TO_CONTAINER - } - } - - // Recursive Read-only (RRO) support requires the mount to be - // read-only and the mount propagation set to private. - if mount.RecursiveReadOnly { - mount.Readonly = true - mount.Propagation = types.MountPropagation_PROPAGATION_PRIVATE + if !bindMountFound { + missingMount = append(missingMount, m.Destination) + // If one mount is missing we can skip over any further code as we have + // to abort the restore process anyway. Not using break to get all missing + // mountpoints in one error message. + continue } log.Debugf(ctx, "Adding mounts %#v", mount) containerConfig.Mounts = append(containerConfig.Mounts, mount) } + if len(missingMount) > 0 { + return "", fmt.Errorf( + "restoring %q expects following bind mounts defined (%s)", + inputImage, + strings.Join(missingMount, ","), + ) + } + sandboxConfig := &types.PodSandboxConfig{ Metadata: &types.PodSandboxMetadata{ Name: sb.Metadata().Name, diff --git a/test/checkpoint.bats b/test/checkpoint.bats index 8382c136a9f..bb5caaacb86 100644 --- a/test/checkpoint.bats +++ b/test/checkpoint.bats @@ -36,9 +36,15 @@ function teardown() { pod_id=$(crictl runp "$TESTDATA"/sandbox_config.json) # Replace original container with checkpoint image RESTORE_JSON=$(mktemp) + RESTORE2_JSON=$(mktemp) jq ".image.image=\"$TESTDIR/cp.tar\"" "$TESTDATA"/container_sleep.json > "$RESTORE_JSON" - ctr_id=$(crictl create "$pod_id" "$RESTORE_JSON" "$TESTDATA"/sandbox_config.json) + # This should fail because the bind mounts are not part of the create request + run crictl create "$pod_id" "$RESTORE_JSON" "$TESTDATA"/sandbox_config.json + [ "$status" -eq 1 ] + jq ". +{mounts:[{\"container_path\":\"/etc/issue\",\"host_path\":\"$BIND_MOUNT_FILE\"},{\"container_path\":\"/data\",\"host_path\":\"$BIND_MOUNT_DIR\"}]}" "$RESTORE_JSON" > "$RESTORE2_JSON" + ctr_id=$(crictl create "$pod_id" "$RESTORE2_JSON" "$TESTDATA"/sandbox_config.json) rm -f "$RESTORE_JSON" + rm -f "$RESTORE2_JSON" rm -f "$TESTDATA"/checkpoint.json crictl start "$ctr_id" restored=$(crictl inspect --output go-template --template "{{(index .info.restored)}}" "$ctr_id") From ee2d73252884f963b14dbe865e4a15fd09469731 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Wed, 27 Nov 2024 10:29:44 +0100 Subject: [PATCH 17/47] Fix container restore lint report Signed-off-by: Sascha Grunert --- server/container_restore.go | 18 +++++---- server/container_restore_test.go | 67 +++++++------------------------- 2 files changed, 25 insertions(+), 60 deletions(-) diff --git a/server/container_restore.go b/server/container_restore.go index 38325ed5709..f9603514ba9 100644 --- a/server/container_restore.go +++ b/server/container_restore.go @@ -64,7 +64,7 @@ func (s *Server) CRImportCheckpoint( return "", errors.New(`attribute "image" missing from container definition`) } - if createConfig.Metadata == nil && createConfig.Metadata.Name == "" { + if createConfig.Metadata == nil || createConfig.Metadata.Name == "" { return "", errors.New(`attribute "metadata" missing from container definition`) } @@ -302,14 +302,16 @@ func (s *Server) CRImportCheckpoint( bindMountFound := false for _, createMount := range createMounts { - if createMount.ContainerPath == m.Destination { - mount.HostPath = createMount.HostPath - mount.Readonly = createMount.Readonly - mount.RecursiveReadOnly = createMount.RecursiveReadOnly - mount.Propagation = createMount.Propagation - mount.RecursiveReadOnly = createMount.RecursiveReadOnly - bindMountFound = true + if createMount.ContainerPath != m.Destination { + continue } + + bindMountFound = true + mount.HostPath = createMount.HostPath + mount.Readonly = createMount.Readonly + mount.RecursiveReadOnly = createMount.RecursiveReadOnly + mount.Propagation = createMount.Propagation + break } if !bindMountFound { missingMount = append(missingMount, m.Destination) diff --git a/server/container_restore_test.go b/server/container_restore_test.go index 2e7e42ebcc9..04a1b0e27f3 100644 --- a/server/container_restore_test.go +++ b/server/container_restore_test.go @@ -68,6 +68,7 @@ var _ = t.Describe("ContainerRestore", func() { ) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "does-not-exist.tar", }, @@ -93,6 +94,7 @@ var _ = t.Describe("ContainerRestore", func() { archive.Close() defer os.RemoveAll("empty.tar") containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "empty.tar", }, @@ -115,6 +117,7 @@ var _ = t.Describe("ContainerRestore", func() { Expect(err).ToNot(HaveOccurred()) defer os.RemoveAll("no.tar") containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "no.tar", }, @@ -149,6 +152,7 @@ var _ = t.Describe("ContainerRestore", func() { _, err = io.Copy(outFile, input) Expect(err).ToNot(HaveOccurred()) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "archive.tar", }, @@ -186,6 +190,7 @@ var _ = t.Describe("ContainerRestore", func() { _, err = io.Copy(outFile, input) Expect(err).ToNot(HaveOccurred()) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "archive.tar", }, @@ -199,7 +204,7 @@ var _ = t.Describe("ContainerRestore", func() { ) // Then - Expect(err.Error()).To(ContainSubstring(`failed to read "io.kubernetes.cri-o.Metadata": unexpected end of JSON input`)) + Expect(err.Error()).To(ContainSubstring(`failed to read "io.kubernetes.cri-o.Annotations": unexpected end of JSON input`)) }) }) t.Describe("ContainerRestore from archive into new pod", func() { @@ -224,6 +229,7 @@ var _ = t.Describe("ContainerRestore", func() { _, err = io.Copy(outFile, input) Expect(err).ToNot(HaveOccurred()) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "archive.tar", }, @@ -269,6 +275,7 @@ var _ = t.Describe("ContainerRestore", func() { _, err = io.Copy(outFile, input) Expect(err).ToNot(HaveOccurred()) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "archive.tar", }, @@ -317,6 +324,7 @@ var _ = t.Describe("ContainerRestore", func() { _, err = io.Copy(outFile, input) Expect(err).ToNot(HaveOccurred()) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "archive.tar", }, @@ -334,57 +342,6 @@ var _ = t.Describe("ContainerRestore", func() { Expect(err.Error()).To(Equal(`failed to read "io.kubernetes.cri-o.Annotations": unexpected end of JSON input`)) }) }) - t.Describe("ContainerRestore from archive into new pod", func() { - It("should fail because archive contains no io.kubernetes.cri-o.Labels", func() { - // Given - addContainerAndSandbox() - testContainer.SetStateAndSpoofPid(&oci.ContainerState{ - State: specs.State{Status: oci.ContainerStateRunning}, - }) - - err := os.WriteFile( - "spec.dump", - []byte( - `{"annotations":{"io.kubernetes.cri-o.Metadata"`+ - `:"{\"name\":\"container-to-restore\"}",`+ - `"io.kubernetes.cri-o.Annotations": "{\"name\":\"NAME\"}"}}`), - 0o644, - ) - Expect(err).ToNot(HaveOccurred()) - defer os.RemoveAll("spec.dump") - err = os.WriteFile("config.dump", []byte(`{"rootfsImageName": "image"}`), 0o644) - Expect(err).ToNot(HaveOccurred()) - defer os.RemoveAll("config.dump") - outFile, err := os.Create("archive.tar") - Expect(err).ToNot(HaveOccurred()) - defer outFile.Close() - input, err := archive.TarWithOptions(".", &archive.TarOptions{ - Compression: archive.Uncompressed, - IncludeSourceDir: true, - IncludeFiles: []string{"spec.dump", "config.dump"}, - }) - Expect(err).ToNot(HaveOccurred()) - defer os.RemoveAll("archive.tar") - _, err = io.Copy(outFile, input) - Expect(err).ToNot(HaveOccurred()) - containerConfig := &types.ContainerConfig{ - Image: &types.ImageSpec{ - Image: "archive.tar", - }, - } - // When - - _, err = sut.CRImportCheckpoint( - context.Background(), - containerConfig, - "", - "", - ) - - // Then - Expect(err.Error()).To(Equal(`failed to read "io.kubernetes.cri-o.Labels": unexpected end of JSON input`)) - }) - }) t.Describe("ContainerRestore from archive into new pod", func() { It("should fail with 'PodSandboxId should not be empty'", func() { // Given @@ -420,6 +377,7 @@ var _ = t.Describe("ContainerRestore", func() { _, err = io.Copy(outFile, input) Expect(err).ToNot(HaveOccurred()) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "archive.tar", }, @@ -508,6 +466,10 @@ var _ = t.Describe("ContainerRestore", func() { Metadata: &types.ContainerMetadata{ Name: "new-container-name", }, + Mounts: []*types.Mount{{ + ContainerPath: "/data", + HostPath: "/data", + }}, } size := uint64(100) @@ -614,6 +576,7 @@ var _ = t.Describe("ContainerRestore", func() { Return(false, nil), ) containerConfig := &types.ContainerConfig{ + Metadata: &types.ContainerMetadata{Name: "name"}, Image: &types.ImageSpec{ Image: "localhost/checkpoint-image:tag1", }, From 0b449cebc721a24c7fa805f6dddf4cf3d5041e10 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Sun, 1 Dec 2024 00:30:30 +0000 Subject: [PATCH 18/47] version: bump to 1.31.3 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 7c57fcf6bbb..75df706c173 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.2" +const Version = "1.31.3" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From cf112c6966a2b9e97332f08404d92f528fd196f7 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Wed, 30 Oct 2024 15:02:40 +0100 Subject: [PATCH 19/47] Disable actuated runners We can't use them any more so we now remove it from CI. Signed-off-by: Sascha Grunert --- .github/workflows/integration.yml | 94 ------------------------------- .github/workflows/test.yml | 10 ---- README.md | 1 - 3 files changed, 105 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index f15a273be6b..2c4380d9b3d 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -23,18 +23,9 @@ jobs: run: - runner: ubuntu-latest arch: amd64 - - runner: actuated-arm64-4cpu-16gb - arch: arm64 name: binaries / ${{ matrix.run.arch }} runs-on: ${{ matrix.run.runner }} steps: - - uses: alexellis/arkade-get@d543d47741e9217ba62ff0214444add9a35825f3 - with: - crane: latest - print-summary: false - - name: Install vmmeter - run: crane export --platform linux/${{ matrix.run.arch }} ghcr.io/openfaasltd/vmmeter:latest | sudo tar -xvf - -C /usr/local/bin - - uses: self-actuated/vmmeter-action@c7e2162e39294a810cab647cacc215ecd68a44f6 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: @@ -74,15 +65,6 @@ jobs: jobs: 1 timeout: 10 - - name: critest / conmon / runc / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: runc - runtimeType: oci - critest: 1 - userns: 0 - timeout: 10 - - name: critest / conmon / crun / amd64 arch: amd64 runner: ubuntu-latest @@ -93,15 +75,6 @@ jobs: jobs: 1 timeout: 10 - - name: critest / conmon / crun / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: crun - runtimeType: oci - critest: 1 - userns: 0 - timeout: 10 - - name: critest / conmon-rs / runc / amd64 arch: amd64 runner: ubuntu-latest @@ -112,16 +85,6 @@ jobs: jobs: 1 timeout: 10 - - name: critest / conmon-rs / runc / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: runc - runtimeType: pod - critest: 1 - userns: 0 - jobs: 1 - timeout: 10 - - name: critest / conmon-rs / crun / amd64 arch: amd64 runner: ubuntu-latest @@ -132,16 +95,6 @@ jobs: jobs: 1 timeout: 10 - - name: critest / conmon-rs / crun / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: crun - runtimeType: pod - critest: 1 - userns: 0 - jobs: 1 - timeout: 10 - - name: integration / conmon / runc / amd64 arch: amd64 runner: ubuntu-latest @@ -152,16 +105,6 @@ jobs: jobs: 2 timeout: 120 - - name: integration / conmon / runc / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: runc - runtimeType: oci - critest: 0 - userns: 0 - jobs: 2 - timeout: 120 - - name: integration / conmon / crun / amd64 arch: amd64 runner: ubuntu-latest @@ -172,16 +115,6 @@ jobs: jobs: 2 timeout: 120 - - name: integration / conmon / crun / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: crun - runtimeType: oci - critest: 0 - userns: 0 - jobs: 2 - timeout: 120 - - name: integration / conmon-rs / runc / amd64 arch: amd64 runner: ubuntu-latest @@ -192,16 +125,6 @@ jobs: jobs: 2 timeout: 120 - - name: integration / conmon-rs / runc / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: runc - runtimeType: pod - critest: 0 - userns: 0 - jobs: 2 - timeout: 120 - - name: integration / userns / runc / amd64 arch: amd64 runner: ubuntu-latest @@ -212,27 +135,10 @@ jobs: jobs: 2 timeout: 120 - - name: integration / userns / runc / arm64 - arch: arm64 - runner: actuated-arm64-8cpu-32gb - defaultRuntime: runc - runtimeType: oci - critest: 0 - userns: 1 - jobs: 2 - timeout: 120 - name: ${{ matrix.run.name }} runs-on: ${{ matrix.run.runner }} timeout-minutes: ${{ matrix.run.timeout }} steps: - - uses: alexellis/arkade-get@d543d47741e9217ba62ff0214444add9a35825f3 - with: - crane: latest - print-summary: false - - name: Install vmmeter - run: crane export --platform linux/${{ matrix.run.arch }} ghcr.io/openfaasltd/vmmeter:latest | sudo tar -xvf - -C /usr/local/bin - - uses: self-actuated/vmmeter-action@c7e2162e39294a810cab647cacc215ecd68a44f6 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b16cfb0b98f..3043fbbf7f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -203,19 +203,9 @@ jobs: - runner: ubuntu-latest arch: amd64 type: rootless - - runner: actuated-arm64-4cpu-16gb - arch: arm64 - type: root name: unit / ${{ matrix.run.arch }} / ${{ matrix.run.type }} runs-on: ${{ matrix.run.runner }} steps: - - uses: alexellis/arkade-get@d543d47741e9217ba62ff0214444add9a35825f3 - with: - crane: latest - print-summary: false - - name: Install vmmeter - run: crane export --platform linux/${{ matrix.run.arch }} ghcr.io/openfaasltd/vmmeter:latest | sudo tar -xvf - -C /usr/local/bin - - uses: self-actuated/vmmeter-action@c7e2162e39294a810cab647cacc215ecd68a44f6 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/README.md b/README.md index 707e62b75f1..569d4be6ace 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fcri-o%2Fcri-o.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fcri-o%2Fcri-o?ref=badge_shield) [![Mentioned in Awesome CRI-O](https://awesome.re/mentioned-badge.svg)](awesome.md) [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cri-o/cri-o) -Arm CI sponsored by Actuated From 26bb3c96a22cf579785c145b3371b52b74508874 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Wed, 27 Nov 2024 10:18:45 +0100 Subject: [PATCH 20/47] Allow to remove pod sandbox on netns removal We should not error on sandbox removal if the netns path gets either removed or invalidated. This path allows removing the sandbox and cleans up the stale netns path. Signed-off-by: Sascha Grunert --- internal/config/nsmgr/types_linux.go | 14 ++++++++++---- server/sandbox_network.go | 15 ++++++++++++++- test/network.bats | 21 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/internal/config/nsmgr/types_linux.go b/internal/config/nsmgr/types_linux.go index 38b30ee8a0e..9a0d538778d 100644 --- a/internal/config/nsmgr/types_linux.go +++ b/internal/config/nsmgr/types_linux.go @@ -83,11 +83,17 @@ func (n *namespace) Remove() error { return nil } - // try to unmount, ignoring "not mounted" (EINVAL) error. - if err := unix.Unmount(fp, unix.MNT_DETACH); err != nil && err != unix.EINVAL { - return fmt.Errorf("unable to unmount %s: %w", fp, err) + // Don't run into unmount issues if the network namespace does not exist any more. + if _, err := os.Stat(fp); err == nil { + // try to unmount, ignoring "not mounted" (EINVAL) error. + if err := unix.Unmount(fp, unix.MNT_DETACH); err != nil && err != unix.EINVAL { + return fmt.Errorf("unable to unmount %s: %w", fp, err) + } + + return os.RemoveAll(fp) } - return os.Remove(fp) + + return nil } // GetNamespace takes a path and type, checks if it is a namespace, and if so diff --git a/server/sandbox_network.go b/server/sandbox_network.go index 2c997af7067..7e75c72f439 100644 --- a/server/sandbox_network.go +++ b/server/sandbox_network.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math" + "os" "time" cnitypes "github.com/containernetworking/cni/pkg/types" @@ -187,7 +188,19 @@ func (s *Server) networkStop(ctx context.Context, sb *sandbox.Sandbox) error { return err } if err := s.config.CNIPlugin().TearDownPodWithContext(stopCtx, podNetwork); err != nil { - return fmt.Errorf("failed to destroy network for pod sandbox %s(%s): %w", sb.Name(), sb.ID(), err) + retErr := fmt.Errorf("failed to destroy network for pod sandbox %s(%s): %w", sb.Name(), sb.ID(), err) + + if _, statErr := os.Stat(podNetwork.NetNS); statErr != nil { + return fmt.Errorf("%w: stat netns path %q: %w", retErr, podNetwork.NetNS, statErr) + } + + // The netns file may still exists, which means that it's likely + // corrupted. Remove it to allow cleanup of the network namespace: + if rmErr := os.RemoveAll(podNetwork.NetNS); rmErr != nil { + return fmt.Errorf("%w: failed to remove netns path: %w", retErr, rmErr) + } + + log.Warnf(ctx, "Removed invalid netns path %s from pod sandbox %s(%s)", podNetwork.NetNS, sb.Name(), sb.ID()) } return sb.SetNetworkStopped(ctx, true) diff --git a/test/network.bats b/test/network.bats index 2d26beda62f..2c89725c66a 100644 --- a/test/network.bats +++ b/test/network.bats @@ -166,3 +166,24 @@ function check_networking() { # shellcheck disable=SC2010 [[ $(ls $CNI_RESULTS_DIR | grep "$POD") == "" ]] } + +@test "Clean up network if pod netns gets destroyed" { + start_crio + + POD=$(crictl runp "$TESTDATA/sandbox_config.json") + + # remove the network namespace + NETNS_PATH=/var/run/netns/ + NS=$(crictl inspectp "$POD" | + jq -er '.info.runtimeSpec.linux.namespaces[] | select(.type == "network").path | sub("'$NETNS_PATH'"; "")') + + # remove network namespace + ip netns del "$NS" + + # fake invalid netns path + touch "$NETNS_PATH$NS" + + # be able to remove the sandbox + crictl rmp -f "$POD" + grep -q "Removed invalid netns path $NETNS_PATH$NS from pod sandbox" "$CRIO_LOG" +} From 284eb93278202393020d5909ec088d1ec9acaa65 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Mon, 9 Dec 2024 16:07:34 -0500 Subject: [PATCH 21/47] config: add default_annotations Signed-off-by: Peter Hunt --- contrib/test/ci/vars.yml | 1 + docs/crio.conf.5.md | 3 +++ internal/oci/oci.go | 10 ++++++++++ pkg/config/config.go | 9 +++++++++ pkg/config/template.go | 6 ++++++ server/sandbox_run_linux.go | 16 +++++++++++++++- test/pod.bats | 22 ++++++++++++++++++++++ 7 files changed, 66 insertions(+), 1 deletion(-) diff --git a/contrib/test/ci/vars.yml b/contrib/test/ci/vars.yml index d6a2b21bc34..242e09e5286 100644 --- a/contrib/test/ci/vars.yml +++ b/contrib/test/ci/vars.yml @@ -167,6 +167,7 @@ kata_skip_pod_tests: - 'test "run container with container_min_memory 17.5MiB"' - 'test "run container with container_min_memory 5.5MiB"' - 'test "run container with empty container_min_memory"' + - 'test "run container with default annotations"' kata_skip_seccomp_oci_artifacts_tests: - 'test "seccomp OCI artifact with pod annotation"' - 'test "seccomp OCI artifact with container annotation"' diff --git a/docs/crio.conf.5.md b/docs/crio.conf.5.md index 877bfb56db4..3bea4f999cc 100644 --- a/docs/crio.conf.5.md +++ b/docs/crio.conf.5.md @@ -378,6 +378,9 @@ A mapping of platforms to the corresponding runtime executable paths for the run If set to true, the runtime will not sync the log file on rotate or container exit. This option is only valid for the 'oci' runtime type. Setting this option to true can cause data loss, e.g. when a machine crash happens. +**default_annotations**={} +A mapping of keys to values of annotations set on containers run by this runtime handler, if not overridden by the pod spec. + ### CRIO.RUNTIME.WORKLOADS TABLE The "crio.runtime.workloads" table defines a list of workloads - a way to customize the behavior of a pod and container. diff --git a/internal/oci/oci.go b/internal/oci/oci.go index 3e0764e1ea2..d254ccb503b 100644 --- a/internal/oci/oci.go +++ b/internal/oci/oci.go @@ -227,6 +227,16 @@ func (r *Runtime) RuntimeSupportsRROMounts(runtimeHandler string) bool { return rh.RuntimeSupportsRROMounts() } +// RuntimeDefaultAnnotations returns the default annotations for this runtime handler. +func (r *Runtime) RuntimeDefaultAnnotations(runtimeHandler string) (map[string]string, error) { + rh, err := r.getRuntimeHandler(runtimeHandler) + if err != nil { + return nil, err + } + + return rh.RuntimeDefaultAnnotations(), nil +} + func (r *Runtime) newRuntimeImpl(c *Container) (RuntimeImpl, error) { rh, err := r.getRuntimeHandler(c.runtimeHandler) if err != nil { diff --git a/pkg/config/config.go b/pkg/config/config.go index dd094830ae6..ac092677598 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -268,6 +268,10 @@ type RuntimeHandler struct { // Inheritance request // Fill in the Runtime information (paths and type) from the default runtime InheritDefaultRuntime bool `toml:"inherit_default_runtime,omitempty"` + + // Default annotations specified for runtime handler if they're not overridden by + // the pod spec. + DefaultAnnotations map[string]string `toml:"default_annotations,omitempty"` } // Multiple runtime Handlers in a map. @@ -1776,6 +1780,11 @@ func (r *RuntimeHandler) RuntimeSupportsMountFlag(flag string) bool { return slices.Contains(r.features.MountOptions, flag) } +// RuntimeDefaultAnnotations returns the default annotations for this handler. +func (r *RuntimeHandler) RuntimeDefaultAnnotations() map[string]string { + return r.DefaultAnnotations +} + func validateAllowedAndGenerateDisallowedAnnotations(allowed []string) (disallowed []string, _ error) { disallowedMap := make(map[string]bool) for _, ann := range annotations.AllAllowedAnnotations { diff --git a/pkg/config/template.go b/pkg/config/template.go index ba98aad60d6..1bbebcd74b4 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -1245,6 +1245,7 @@ const templateStringCrioRuntimeRuntimesRuntimeHandler = `# The "crio.runtime.run # allowed_annotations = [] # platform_runtime_paths = { "os/arch" = "/path/to/binary" } # no_sync_log = false +# default_annotations = {} # Where: # - runtime-handler: Name used to identify the runtime. # - runtime_path (optional, string): Absolute path to the runtime executable in @@ -1297,6 +1298,7 @@ const templateStringCrioRuntimeRuntimesRuntimeHandler = `# The "crio.runtime.run # - no_sync_log (optional, bool): If set to true, the runtime will not sync the log file on rotate or container exit. # This option is only valid for the 'oci' runtime type. Setting this option to true can cause data loss, e.g. # when a machine crash happens. +# - default_annotations (optional, map): Default annotations if not overridden by the pod spec. # # Using the seccomp notifier feature: # @@ -1345,6 +1347,10 @@ const templateStringCrioRuntimeRuntimesRuntimeHandler = `# The "crio.runtime.run {{- $first := true }}{{- range $key, $value := $runtime_handler.PlatformRuntimePaths }} {{- if not $first }},{{ end }}{{- printf "%q = %q" $key $value }}{{- $first = false }}{{- end }}} {{ end }} +{{ if $runtime_handler.DefaultAnnotations }}default_annotations = { +{{- $first := true }}{{- range $key, $value := $runtime_handler.DefaultAnnotations }} +{{- if not $first }},{{ end }}{{- printf "%q = %q" $key $value }}{{- $first = false }}{{- end }}} +{{ end }} {{ end }} ` diff --git a/server/sandbox_run_linux.go b/server/sandbox_run_linux.go index 6c191eda1fb..236ad2ac8a5 100644 --- a/server/sandbox_run_linux.go +++ b/server/sandbox_run_linux.go @@ -427,7 +427,21 @@ func (s *Server) runPodSandbox(ctx context.Context, req *types.RunPodSandboxRequ return nil, err } - kubeAnnotations := sbox.Config().Annotations + kubeAnnotations, err := s.Runtime().RuntimeDefaultAnnotations(runtimeHandler) + if err != nil { + return nil, err + } + if kubeAnnotations == nil { + kubeAnnotations = map[string]string{} + } + + // override default annotations with pod spec specified ones + for k, v := range sbox.Config().Annotations { + if _, ok := kubeAnnotations[k]; ok { + log.Debugf(ctx, "Overriding default pod annotation %s for pod %s", k, sbox.ID()) + } + kubeAnnotations[k] = v + } usernsMode := kubeAnnotations[annotations.UsernsModeAnnotation] if usernsMode != "" { diff --git a/test/pod.bats b/test/pod.bats index 87bdaf73690..cca567c0a62 100644 --- a/test/pod.bats +++ b/test/pod.bats @@ -523,3 +523,25 @@ EOF crictl run "$TESTDIR"/memory.json "$TESTDATA"/sandbox_config.json } + +@test "run container with default annotations" { + setup_crio + + cat << EOF > "$CRIO_CONFIG_DIR/99-ann.conf" +[crio.runtime] +default_runtime = "ann" +[crio.runtime.runtimes.ann] +runtime_path = "$RUNTIME_BINARY_PATH" +default_annotations = { "hello" = "1234", "pod" = "5678" } +EOF + unset CONTAINER_DEFAULT_RUNTIME + unset CONTAINER_RUNTIMES + + start_crio_no_setup + + ctr_id=$(crictl run "$TESTDATA"/container_sleep.json "$TESTDATA"/sandbox_config.json) + annotations=$(crictl inspect "$ctr_id" | jq .info.runtimeSpec.annotations) + grep hello <<< "$annotations" + # pod spec should override default annotations + grep -v "5678" <<< "$annotations" +} From 88939baf2cfc0750d900b7b1b473a7b53326e557 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Wed, 1 Jan 2025 00:26:22 +0000 Subject: [PATCH 22/47] version: bump to 1.31.4 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 75df706c173..f883857ed5b 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.3" +const Version = "1.31.4" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From 8aa8c7e42be9899adba6830f7b93428453595cd3 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Fri, 20 Dec 2024 13:21:16 -0500 Subject: [PATCH 23/47] server: fix panic when default annotations are specified Signed-off-by: Peter Hunt --- server/sandbox_run_linux.go | 14 ++++++++------ test/pod.bats | 4 ++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/server/sandbox_run_linux.go b/server/sandbox_run_linux.go index 236ad2ac8a5..148b6b885e1 100644 --- a/server/sandbox_run_linux.go +++ b/server/sandbox_run_linux.go @@ -423,17 +423,19 @@ func (s *Server) runPodSandbox(ctx context.Context, req *types.RunPodSandboxRequ return nil, err } - if err := s.FilterDisallowedAnnotations(sbox.Config().Annotations, sbox.Config().Annotations, runtimeHandler); err != nil { + defaultAnnotations, err := s.Runtime().RuntimeDefaultAnnotations(runtimeHandler) + if err != nil { return nil, err } + kubeAnnotations := map[string]string{} + // Deep copy to prevent writing to the same map in the config + for k, v := range defaultAnnotations { + kubeAnnotations[k] = v + } - kubeAnnotations, err := s.Runtime().RuntimeDefaultAnnotations(runtimeHandler) - if err != nil { + if err := s.FilterDisallowedAnnotations(sbox.Config().Annotations, sbox.Config().Annotations, runtimeHandler); err != nil { return nil, err } - if kubeAnnotations == nil { - kubeAnnotations = map[string]string{} - } // override default annotations with pod spec specified ones for k, v := range sbox.Config().Annotations { diff --git a/test/pod.bats b/test/pod.bats index cca567c0a62..aef784f54ea 100644 --- a/test/pod.bats +++ b/test/pod.bats @@ -544,4 +544,8 @@ EOF grep hello <<< "$annotations" # pod spec should override default annotations grep -v "5678" <<< "$annotations" + + # verify the internal crio configuration is unchanged + CONFIG=$(crio status -s "$CRIO_SOCKET" config) + jq '.annotations | keys[]' < "$TESTDATA"/sandbox_config.json | while read -r key; do ! echo "$CONFIG" | grep "$key"; done } From 86d8c263bd999ded43b9d430ffa017cf446ca1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Thu, 12 Dec 2024 22:22:29 +0900 Subject: [PATCH 24/47] Cherry-pick changes from containers/image project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-pick the following changes: - containers/image/pull#2636 - containers/image/pull#2643 Signed-off-by: Krzysztof Wilczyński --- go.mod | 2 +- go.sum | 4 +- .../image/v5/storage/storage_dest.go | 94 ++++++++++--------- vendor/modules.txt | 2 +- 4 files changed, 56 insertions(+), 46 deletions(-) diff --git a/go.mod b/go.mod index dd3a284e2ba..e9d779730a6 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/containers/common v0.60.3-0.20241001153533-18930ed8933b github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon-rs v0.6.5 - github.com/containers/image/v5 v5.32.2 + github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9 github.com/containers/kubensmnt v1.2.0 github.com/containers/ocicrypt v1.2.0 github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18 diff --git a/go.sum b/go.sum index da7970301f1..df8daa54581 100644 --- a/go.sum +++ b/go.sum @@ -732,8 +732,8 @@ github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6J github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/conmon-rs v0.6.5 h1:mxdEBF/pjBmryj1ABrTDUqxDyxoZrpo8A1/9+JNvtZU= github.com/containers/conmon-rs v0.6.5/go.mod h1:+1QRvqdKmaFgaKL7IfsnXncePoH4K+5qkyBIAl/m9Zs= -github.com/containers/image/v5 v5.32.2 h1:SzNE2Y6sf9b1GJoC8qjCuMBXwQrACFp4p0RK15+4gmQ= -github.com/containers/image/v5 v5.32.2/go.mod h1:v1l73VeMugfj/QtKI+jhYbwnwFCFnNGckvbST3rQ5Hk= +github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9 h1:RqjeydhQ73aFkYASllZ2/cAHYvmLHrLbxh5hnWVvoa8= +github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9/go.mod h1:v1l73VeMugfj/QtKI+jhYbwnwFCFnNGckvbST3rQ5Hk= github.com/containers/kubensmnt v1.2.0 h1:BDtkaOFQ5fN7FnB9kC6peMW50KkwI1KI8E9ROBFeQIg= github.com/containers/kubensmnt v1.2.0/go.mod h1:1/HG09N/a1+WSD3zkurzeWtqlKRSfUUnlIF/08zloqk= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= diff --git a/vendor/github.com/containers/image/v5/storage/storage_dest.go b/vendor/github.com/containers/image/v5/storage/storage_dest.go index 842a3ab0689..b86a568b5fa 100644 --- a/vendor/github.com/containers/image/v5/storage/storage_dest.go +++ b/vendor/github.com/containers/image/v5/storage/storage_dest.go @@ -21,7 +21,6 @@ import ( "github.com/containers/image/v5/internal/imagedestination/stubs" "github.com/containers/image/v5/internal/private" "github.com/containers/image/v5/internal/putblobdigest" - "github.com/containers/image/v5/internal/set" "github.com/containers/image/v5/internal/signature" "github.com/containers/image/v5/internal/tmpdir" "github.com/containers/image/v5/manifest" @@ -121,6 +120,9 @@ type storageImageDestinationLockProtected struct { filenames map[digest.Digest]string // Mapping from layer blobsums to their sizes. If set, filenames and blobDiffIDs must also be set. fileSizes map[digest.Digest]int64 + + // Config + configDigest digest.Digest // "" if N/A or not known yet. } // addedLayerInfo records data about a layer to use in this image. @@ -214,7 +216,17 @@ func (s *storageImageDestination) PutBlobWithOptions(ctx context.Context, stream return info, err } - if options.IsConfig || options.LayerIndex == nil { + if options.IsConfig { + s.lock.Lock() + defer s.lock.Unlock() + if s.lockProtected.configDigest != "" { + return private.UploadedBlob{}, fmt.Errorf("after config %q, refusing to record another config %q", + s.lockProtected.configDigest.String(), info.Digest.String()) + } + s.lockProtected.configDigest = info.Digest + return info, nil + } + if options.LayerIndex == nil { return info, nil } @@ -343,35 +355,41 @@ func (s *storageImageDestination) PutBlobPartial(ctx context.Context, chunkAcces blobDigest := srcInfo.Digest s.lock.Lock() - if out.UncompressedDigest != "" { - s.lockProtected.indexToDiffID[options.LayerIndex] = out.UncompressedDigest - if out.TOCDigest != "" { - options.Cache.RecordTOCUncompressedPair(out.TOCDigest, out.UncompressedDigest) - } - // Don’t set indexToTOCDigest on this path: - // - Using UncompressedDigest allows image reuse with non-partially-pulled layers, so we want to set indexToDiffID. - // - If UncompressedDigest has been computed, that means the layer was read completely, and the TOC has been created from scratch. - // That TOC is quite unlikely to match any other TOC value. - - // The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is - // responsible for ensuring blobDigest has been validated. - if out.CompressedDigest != blobDigest { - return private.UploadedBlob{}, fmt.Errorf("internal error: ApplyDiffWithDiffer returned CompressedDigest %q not matching expected %q", - out.CompressedDigest, blobDigest) - } - // So, record also information about blobDigest, that might benefit reuse. - // We trust ApplyDiffWithDiffer to validate or create both values correctly. - s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest - options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest) - } else { - // Use diffID for layer identity if it is known. - if uncompressedDigest := options.Cache.UncompressedDigestForTOC(out.TOCDigest); uncompressedDigest != "" { - s.lockProtected.indexToDiffID[options.LayerIndex] = uncompressedDigest + if err := func() error { // A scope for defer + defer s.lock.Unlock() + + if out.UncompressedDigest != "" { + s.lockProtected.indexToDiffID[options.LayerIndex] = out.UncompressedDigest + if out.TOCDigest != "" { + options.Cache.RecordTOCUncompressedPair(out.TOCDigest, out.UncompressedDigest) + } + // Don’t set indexToTOCDigest on this path: + // - Using UncompressedDigest allows image reuse with non-partially-pulled layers, so we want to set indexToDiffID. + // - If UncompressedDigest has been computed, that means the layer was read completely, and the TOC has been created from scratch. + // That TOC is quite unlikely to match any other TOC value. + + // The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is + // responsible for ensuring blobDigest has been validated. + if out.CompressedDigest != blobDigest { + return fmt.Errorf("internal error: ApplyDiffWithDiffer returned CompressedDigest %q not matching expected %q", + out.CompressedDigest, blobDigest) + } + // So, record also information about blobDigest, that might benefit reuse. + // We trust ApplyDiffWithDiffer to validate or create both values correctly. + s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest + options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest) + } else { + // Use diffID for layer identity if it is known. + if uncompressedDigest := options.Cache.UncompressedDigestForTOC(out.TOCDigest); uncompressedDigest != "" { + s.lockProtected.indexToDiffID[options.LayerIndex] = uncompressedDigest + } + s.lockProtected.indexToTOCDigest[options.LayerIndex] = out.TOCDigest } - s.lockProtected.indexToTOCDigest[options.LayerIndex] = out.TOCDigest + s.lockProtected.diffOutputs[options.LayerIndex] = out + return nil + }(); err != nil { + return private.UploadedBlob{}, err } - s.lockProtected.diffOutputs[options.LayerIndex] = out - s.lock.Unlock() succeeded = true return private.UploadedBlob{ @@ -1188,22 +1206,14 @@ func (s *storageImageDestination) Commit(ctx context.Context, unparsedToplevel t options.CreationDate = *inspect.Created } - // Set up to save the non-layer blobs as data items. Since we only share layers, they should all be in files, so - // we just need to screen out the ones that are actually layers to get the list of non-layers. - dataBlobs := set.New[digest.Digest]() - for blob := range s.lockProtected.filenames { - dataBlobs.Add(blob) - } - for _, layerBlob := range layerBlobs { - dataBlobs.Delete(layerBlob.Digest) - } - for _, blob := range dataBlobs.Values() { - v, err := os.ReadFile(s.lockProtected.filenames[blob]) + // Set up to save the config as a data item. Since we only share layers, the config should be in a file. + if s.lockProtected.configDigest != "" { + v, err := os.ReadFile(s.lockProtected.filenames[s.lockProtected.configDigest]) if err != nil { - return fmt.Errorf("copying non-layer blob %q to image: %w", blob, err) + return fmt.Errorf("copying config blob %q to image: %w", s.lockProtected.configDigest, err) } options.BigData = append(options.BigData, storage.ImageBigDataOption{ - Key: blob.String(), + Key: s.lockProtected.configDigest.String(), Data: v, Digest: digest.Canonical.FromBytes(v), }) diff --git a/vendor/modules.txt b/vendor/modules.txt index 8ed2dcf93af..5ecca082f80 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -268,7 +268,7 @@ github.com/containers/conmon/runner/config ## explicit; go 1.22 github.com/containers/conmon-rs/internal/proto github.com/containers/conmon-rs/pkg/client -# github.com/containers/image/v5 v5.32.2 +# github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9 ## explicit; go 1.21.0 github.com/containers/image/v5/copy github.com/containers/image/v5/directory From 244159a026d70e76b6ac596624ffb9999a50f7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Wed, 27 Nov 2024 04:35:47 +0900 Subject: [PATCH 25/47] Cherry-pick changes from containers/storage project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-pick the following changes: - containers/storage/pull#2133 - containers/storage/pull#2156 - containers/storage/pull#2162 - containers/storage/pull#2185 Signed-off-by: Krzysztof Wilczyński --- go.mod | 2 +- go.sum | 4 +- .../github.com/containers/storage/layers.go | 29 ++-- .../storage/pkg/chunked/cache_linux.go | 8 + .../storage/pkg/chunked/compression_linux.go | 143 ++++++++++-------- .../storage/pkg/chunked/storage_linux.go | 129 +++++++++++++--- .../containers/storage/storage.conf | 19 ++- vendor/modules.txt | 2 +- 8 files changed, 224 insertions(+), 112 deletions(-) diff --git a/go.mod b/go.mod index dd3a284e2ba..6704bc03b87 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/containers/image/v5 v5.32.2 github.com/containers/kubensmnt v1.2.0 github.com/containers/ocicrypt v1.2.0 - github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18 + github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192 github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 github.com/cpuguy83/go-md2man v1.0.10 github.com/creack/pty v1.1.23 diff --git a/go.sum b/go.sum index da7970301f1..d5b724eee3a 100644 --- a/go.sum +++ b/go.sum @@ -740,8 +740,8 @@ github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYgle github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= -github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18 h1:YRxFFfDzvXL7WY8OiCKYDbiWQcUPkA7f5mbcfwATHIE= -github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= +github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192 h1:ZI84/Ws/ijsuVczHkmp8ZCfyBlPhdii7dlzO4FJcw6M= +github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 h1:OoRAFlvDGCUqDLampLQjk0yeeSGdF9zzst/3G9IkBbc= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09/go.mod h1:m2r/smMKsKwgMSAoFKHaa68ImdCSNuKE1MxvQ64xuCQ= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go index 6caf28ab71d..ceac34351bc 100644 --- a/vendor/github.com/containers/storage/layers.go +++ b/vendor/github.com/containers/storage/layers.go @@ -909,22 +909,31 @@ func (r *layerStore) load(lockedForWriting bool) (bool, error) { // user of this storage area marked for deletion but didn't manage to // actually delete. var incompleteDeletionErrors error // = nil + var layersToDelete []*Layer for _, layer := range r.layers { if layer.Flags == nil { layer.Flags = make(map[string]interface{}) } if layerHasIncompleteFlag(layer) { - logrus.Warnf("Found incomplete layer %#v, deleting it", layer.ID) - err := r.deleteInternal(layer.ID) - if err != nil { - // Don't return the error immediately, because deleteInternal does not saveLayers(); - // Even if deleting one incomplete layer fails, call saveLayers() so that other possible successfully - // deleted incomplete layers have their metadata correctly removed. - incompleteDeletionErrors = multierror.Append(incompleteDeletionErrors, - fmt.Errorf("deleting layer %#v: %w", layer.ID, err)) - } - modifiedLocations |= layerLocation(layer) + // Important: Do not call r.deleteInternal() here. It modifies r.layers + // which causes unexpected side effects while iterating over r.layers here. + // The range loop has no idea that the underlying elements where shifted + // around. + layersToDelete = append(layersToDelete, layer) + } + } + // Now actually delete the layers + for _, layer := range layersToDelete { + logrus.Warnf("Found incomplete layer %q, deleting it", layer.ID) + err := r.deleteInternal(layer.ID) + if err != nil { + // Don't return the error immediately, because deleteInternal does not saveLayers(); + // Even if deleting one incomplete layer fails, call saveLayers() so that other possible successfully + // deleted incomplete layers have their metadata correctly removed. + incompleteDeletionErrors = multierror.Append(incompleteDeletionErrors, + fmt.Errorf("deleting layer %#v: %w", layer.ID, err)) } + modifiedLocations |= layerLocation(layer) } if err := r.saveLayers(modifiedLocations); err != nil { return false, err diff --git a/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go b/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go index d49ddfed03a..9ebee19aba6 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go +++ b/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go @@ -183,6 +183,9 @@ func makeBinaryDigest(stringDigest string) ([]byte, error) { return buf, nil } +// loadLayerCache attempts to load the cache file for the specified layer. +// If the cache file is not present or it it using a different cache file version, then +// the function returns (nil, nil). func (c *layersCache) loadLayerCache(layerID string) (_ *layer, errRet error) { buffer, mmapBuffer, err := c.loadLayerBigData(layerID, cacheKey) if err != nil && !errors.Is(err, os.ErrNotExist) { @@ -203,6 +206,9 @@ func (c *layersCache) loadLayerCache(layerID string) (_ *layer, errRet error) { if err != nil { return nil, err } + if cacheFile == nil { + return nil, nil + } return c.createLayer(layerID, cacheFile, mmapBuffer) } @@ -617,6 +623,8 @@ func writeCache(manifest []byte, format graphdriver.DifferOutputFormat, id strin }, nil } +// readCacheFileFromMemory reads a cache file from a buffer. +// It can return (nil, nil) if the cache file uses a different file version that the one currently supported. func readCacheFileFromMemory(bigDataBuffer []byte) (*cacheFile, error) { bigData := bytes.NewReader(bigDataBuffer) diff --git a/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go b/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go index 633740a280c..d0c225d5ef5 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go +++ b/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go @@ -17,6 +17,12 @@ import ( expMaps "golang.org/x/exp/maps" ) +const ( + // maxTocSize is the maximum size of a blob that we will attempt to process. + // It is used to prevent DoS attacks from layers that embed a very large TOC file. + maxTocSize = (1 << 20) * 50 +) + var typesToTar = map[string]byte{ TypeReg: tar.TypeReg, TypeLink: tar.TypeLink, @@ -41,25 +47,21 @@ func readEstargzChunkedManifest(blobStream ImageSourceSeekable, blobSize int64, if blobSize <= footerSize { return nil, 0, errors.New("blob too small") } - chunk := ImageSourceChunk{ - Offset: uint64(blobSize - footerSize), - Length: uint64(footerSize), - } - parts, errs, err := blobStream.GetBlobAt([]ImageSourceChunk{chunk}) + + footer := make([]byte, footerSize) + streamsOrErrors, err := getBlobAt(blobStream, ImageSourceChunk{Offset: uint64(blobSize - footerSize), Length: uint64(footerSize)}) if err != nil { return nil, 0, err } - var reader io.ReadCloser - select { - case r := <-parts: - reader = r - case err := <-errs: - return nil, 0, err - } - defer reader.Close() - footer := make([]byte, footerSize) - if _, err := io.ReadFull(reader, footer); err != nil { - return nil, 0, err + + for soe := range streamsOrErrors { + if soe.stream != nil { + _, err = io.ReadFull(soe.stream, footer) + _ = soe.stream.Close() + } + if soe.err != nil && err == nil { + err = soe.err + } } /* Read the ToC offset: @@ -78,48 +80,54 @@ func readEstargzChunkedManifest(blobStream ImageSourceSeekable, blobSize int64, size := int64(blobSize - footerSize - tocOffset) // set a reasonable limit - if size > (1<<20)*50 { + if size > maxTocSize { return nil, 0, errors.New("manifest too big") } - chunk = ImageSourceChunk{ - Offset: uint64(tocOffset), - Length: uint64(size), - } - parts, errs, err = blobStream.GetBlobAt([]ImageSourceChunk{chunk}) - if err != nil { - return nil, 0, err - } - - var tocReader io.ReadCloser - select { - case r := <-parts: - tocReader = r - case err := <-errs: - return nil, 0, err - } - defer tocReader.Close() - - r, err := pgzip.NewReader(tocReader) + streamsOrErrors, err = getBlobAt(blobStream, ImageSourceChunk{Offset: uint64(tocOffset), Length: uint64(size)}) if err != nil { return nil, 0, err } - defer r.Close() - - aTar := archivetar.NewReader(r) - header, err := aTar.Next() - if err != nil { - return nil, 0, err + var manifestUncompressed []byte + + for soe := range streamsOrErrors { + if soe.stream != nil { + err1 := func() error { + defer soe.stream.Close() + + r, err := pgzip.NewReader(soe.stream) + if err != nil { + return err + } + defer r.Close() + + aTar := archivetar.NewReader(r) + + header, err := aTar.Next() + if err != nil { + return err + } + // set a reasonable limit + if header.Size > maxTocSize { + return errors.New("manifest too big") + } + + manifestUncompressed = make([]byte, header.Size) + if _, err := io.ReadFull(aTar, manifestUncompressed); err != nil { + return err + } + return nil + }() + if err == nil { + err = err1 + } + } else if err == nil { + err = soe.err + } } - // set a reasonable limit - if header.Size > (1<<20)*50 { - return nil, 0, errors.New("manifest too big") - } - - manifestUncompressed := make([]byte, header.Size) - if _, err := io.ReadFull(aTar, manifestUncompressed); err != nil { - return nil, 0, err + if manifestUncompressed == nil { + return nil, 0, errors.New("manifest not found") } manifestDigester := digest.Canonical.Digester() @@ -137,7 +145,7 @@ func readEstargzChunkedManifest(blobStream ImageSourceSeekable, blobSize int64, // readZstdChunkedManifest reads the zstd:chunked manifest from the seekable stream blobStream. // Returns (manifest blob, parsed manifest, tar-split blob, manifest offset). -func readZstdChunkedManifest(blobStream ImageSourceSeekable, tocDigest digest.Digest, annotations map[string]string) ([]byte, *internal.TOC, []byte, int64, error) { +func readZstdChunkedManifest(blobStream ImageSourceSeekable, tocDigest digest.Digest, annotations map[string]string) (_ []byte, _ *internal.TOC, _ []byte, _ int64, retErr error) { offsetMetadata := annotations[internal.ManifestInfoKey] if offsetMetadata == "" { return nil, nil, nil, 0, fmt.Errorf("%q annotation missing", internal.ManifestInfoKey) @@ -161,10 +169,10 @@ func readZstdChunkedManifest(blobStream ImageSourceSeekable, tocDigest digest.Di } // set a reasonable limit - if manifestChunk.Length > (1<<20)*50 { + if manifestChunk.Length > maxTocSize { return nil, nil, nil, 0, errors.New("manifest too big") } - if manifestLengthUncompressed > (1<<20)*50 { + if manifestLengthUncompressed > maxTocSize { return nil, nil, nil, 0, errors.New("manifest too big") } @@ -172,26 +180,31 @@ func readZstdChunkedManifest(blobStream ImageSourceSeekable, tocDigest digest.Di if tarSplitChunk.Offset > 0 { chunks = append(chunks, tarSplitChunk) } - parts, errs, err := blobStream.GetBlobAt(chunks) + + streamsOrErrors, err := getBlobAt(blobStream, chunks...) if err != nil { return nil, nil, nil, 0, err } + defer func() { + err := ensureAllBlobsDone(streamsOrErrors) + if retErr == nil { + retErr = err + } + }() + readBlob := func(len uint64) ([]byte, error) { - var reader io.ReadCloser - select { - case r := <-parts: - reader = r - case err := <-errs: - return nil, err + soe, ok := <-streamsOrErrors + if !ok { + return nil, errors.New("stream closed") + } + if soe.err != nil { + return nil, soe.err } + defer soe.stream.Close() blob := make([]byte, len) - if _, err := io.ReadFull(reader, blob); err != nil { - reader.Close() - return nil, err - } - if err := reader.Close(); err != nil { + if _, err := io.ReadFull(soe.stream, blob); err != nil { return nil, err } return blob, nil diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go index 403d7d5aa33..d74727cf63f 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go +++ b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go @@ -146,7 +146,7 @@ func (c *chunkedDiffer) convertTarToZstdChunked(destDirectory string, payload *o func GetDiffer(ctx context.Context, store storage.Store, blobDigest digest.Digest, blobSize int64, annotations map[string]string, iss ImageSourceSeekable) (graphdriver.Differ, error) { pullOptions := store.PullOptions() - if !parseBooleanPullOption(pullOptions, "enable_partial_images", true) { + if !parseBooleanPullOption(pullOptions, "enable_partial_images", false) { return nil, errors.New("enable_partial_images not configured") } @@ -1076,40 +1076,119 @@ func makeEntriesFlat(mergedEntries []fileMetadata) ([]fileMetadata, error) { return new, nil } -func (c *chunkedDiffer) copyAllBlobToFile(destination *os.File) (digest.Digest, error) { - var payload io.ReadCloser - var streams chan io.ReadCloser - var errs chan error - var err error +type streamOrErr struct { + stream io.ReadCloser + err error +} - chunksToRequest := []ImageSourceChunk{ - { - Offset: 0, - Length: uint64(c.blobSize), - }, +// ensureAllBlobsDone ensures that all blobs are closed and returns the first error encountered. +func ensureAllBlobsDone(streamsOrErrors chan streamOrErr) (retErr error) { + for soe := range streamsOrErrors { + if soe.stream != nil { + _ = soe.stream.Close() + } else if retErr == nil { + retErr = soe.err + } } + return +} - streams, errs, err = c.stream.GetBlobAt(chunksToRequest) - if err != nil { - return "", err +// getBlobAtConverterGoroutine reads from the streams and errs channels, then sends +// either a stream or an error to the stream channel. The streams channel is closed when +// there are no more streams and errors to read. +// It ensures that no more than maxStreams streams are returned, and that every item from the +// streams and errs channels is consumed. +func getBlobAtConverterGoroutine(stream chan streamOrErr, streams chan io.ReadCloser, errs chan error, maxStreams int) { + tooManyStreams := false + streamsSoFar := 0 + + err := errors.New("Unexpected error in getBlobAtGoroutine") + + defer func() { + if err != nil { + stream <- streamOrErr{err: err} + } + close(stream) + }() + +loop: + for { + select { + case p, ok := <-streams: + if !ok { + streams = nil + break loop + } + if streamsSoFar >= maxStreams { + tooManyStreams = true + _ = p.Close() + continue + } + streamsSoFar++ + stream <- streamOrErr{stream: p} + case err, ok := <-errs: + if !ok { + errs = nil + break loop + } + stream <- streamOrErr{err: err} + } } - select { - case p := <-streams: - payload = p - case err := <-errs: - return "", err + if streams != nil { + for p := range streams { + if streamsSoFar >= maxStreams { + tooManyStreams = true + _ = p.Close() + continue + } + streamsSoFar++ + stream <- streamOrErr{stream: p} + } } - if payload == nil { - return "", errors.New("invalid stream returned") + if errs != nil { + for err := range errs { + stream <- streamOrErr{err: err} + } } + if tooManyStreams { + stream <- streamOrErr{err: fmt.Errorf("too many streams returned, got more than %d", maxStreams)} + } + err = nil +} - originalRawDigester := digest.Canonical.Digester() +// getBlobAt provides a much more convenient way to consume data returned by ImageSourceSeekable.GetBlobAt. +// GetBlobAt returns two channels, forcing a caller to `select` on both of them — and in Go, reading a closed channel +// always succeeds in select. +// Instead, getBlobAt provides a single channel with all events, which can be consumed conveniently using `range`. +func getBlobAt(is ImageSourceSeekable, chunksToRequest ...ImageSourceChunk) (chan streamOrErr, error) { + streams, errs, err := is.GetBlobAt(chunksToRequest) + if err != nil { + return nil, err + } + stream := make(chan streamOrErr) + go getBlobAtConverterGoroutine(stream, streams, errs, len(chunksToRequest)) + return stream, nil +} - r := io.TeeReader(payload, originalRawDigester.Hash()) +func (c *chunkedDiffer) copyAllBlobToFile(destination *os.File) (digest.Digest, error) { + streamsOrErrors, err := getBlobAt(c.stream, ImageSourceChunk{Offset: 0, Length: uint64(c.blobSize)}) + if err != nil { + return "", err + } - // copy the entire tarball and compute its digest - _, err = io.CopyBuffer(destination, r, c.copyBuffer) + originalRawDigester := digest.Canonical.Digester() + for soe := range streamsOrErrors { + if soe.stream != nil { + r := io.TeeReader(soe.stream, originalRawDigester.Hash()) + // copy the entire tarball and compute its digest + _, err = io.CopyBuffer(destination, r, c.copyBuffer) + _ = soe.stream.Close() + } + if soe.err != nil && err == nil { + err = soe.err + } + } return originalRawDigester.Digest(), err } diff --git a/vendor/github.com/containers/storage/storage.conf b/vendor/github.com/containers/storage/storage.conf index 94a9b36d482..f9d08a03856 100644 --- a/vendor/github.com/containers/storage/storage.conf +++ b/vendor/github.com/containers/storage/storage.conf @@ -8,12 +8,12 @@ # /usr/containers/storage.conf # /etc/containers/storage.conf # $HOME/.config/containers/storage.conf -# $XDG_CONFIG_HOME/containers/storage.conf (If XDG_CONFIG_HOME is set) +# $XDG_CONFIG_HOME/containers/storage.conf (if XDG_CONFIG_HOME is set) # See man 5 containers-storage.conf for more information -# The "container storage" table contains all of the server options. +# The "storage" table contains all of the server options. [storage] -# Default Storage Driver, Must be set for proper operation. +# Default storage driver, must be set for proper operation. driver = "overlay" # Temporary storage location @@ -24,8 +24,8 @@ runroot = "/run/containers/storage" # driver_priority = ["overlay", "btrfs"] # Primary Read/Write location of container storage -# When changing the graphroot location on an SELINUX system, you must -# ensure the labeling matches the default locations labels with the +# When changing the graphroot location on an SELinux system, you must +# ensure the labeling matches the default location's labels with the # following commands: # semanage fcontext -a -e /var/lib/containers/storage /NEWSTORAGEPATH # restorecon -R -v /NEWSTORAGEPATH @@ -65,8 +65,11 @@ additionalimagestores = [ # containers/storage supports four keys # * enable_partial_images="true" | "false" -# Tells containers/storage to look for files previously pulled in storage -# rather then always pulling them from the container registry. +# Enable the "zstd:chunked" feature, which allows partial pulls, reusing +# content that already exists on the system. This is disabled by default, +# and must be explicitly enabled to be used. For more on zstd:chunked, see +# https://github.com/containers/storage/blob/main/docs/containers-storage-zstd-chunked.md +# This is a "string bool": "false" | "true" (cannot be native TOML boolean) # * use_hard_links = "false" | "true" # Tells containers/storage to use hard links rather then create new files in # the image, if an identical file already existed in storage. @@ -79,7 +82,7 @@ additionalimagestores = [ # format compatible with partial pulls in order to take advantage # of local deduplication and hard linking. It is an expensive # operation so it is not enabled by default. -pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""} +pull_options = {enable_partial_images = "false", use_hard_links = "false", ostree_repos=""} # Root-auto-userns-user is a user name which can be used to look up one or more UID/GID # ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned diff --git a/vendor/modules.txt b/vendor/modules.txt index 8ed2dcf93af..ed651774780 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -357,7 +357,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/storage v1.55.1-0.20241015045236-02f1845caa18 +# github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192 ## explicit; go 1.21 github.com/containers/storage github.com/containers/storage/drivers From 8f2ca7b06e3800c1b353bbcf5645d933ddae4b6a Mon Sep 17 00:00:00 2001 From: Ayato Tokubi Date: Thu, 19 Dec 2024 16:43:33 +0000 Subject: [PATCH 26/47] Avoid using UpdateContainerStatus for ReopenContainerLog and add logs tests Signed-off-by: Ayato Tokubi --- internal/oci/container.go | 3 ++ internal/oci/oci.go | 10 +++++++ internal/oci/runtime_oci.go | 4 +++ internal/oci/runtime_pod.go | 4 +++ internal/oci/runtime_vm.go | 4 +++ server/container_reopen_log.go | 10 +++---- test/logs.bats | 53 ++++++++++++++++++++++++++++++++++ test/mocks/oci/oci.go | 14 +++++++++ 8 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 test/logs.bats diff --git a/internal/oci/container.go b/internal/oci/container.go index d6b299d7b88..87b161357b2 100644 --- a/internal/oci/container.go +++ b/internal/oci/container.go @@ -423,6 +423,7 @@ func (c *Container) State() *ContainerState { } // StateNoLock returns the state of a container without using a lock. +// It has been known to cause segfaults in the past so it really should be used sparingly. func (c *Container) StateNoLock() *ContainerState { return c.state } @@ -494,6 +495,8 @@ func (c *Container) exitFilePath() string { // Living checks if a container's init PID exists and it's running, without calling // a given runtime directly to check the state, which is expensive. +// This can't be used for runtimeVM because it uses the VM's pid as a container pid, +// and the VM doesn't necessarily stop when the container stops. func (c *Container) Living() error { _, _, err := c.pid() if err != nil { diff --git a/internal/oci/oci.go b/internal/oci/oci.go index d254ccb503b..c5f08f520b5 100644 --- a/internal/oci/oci.go +++ b/internal/oci/oci.go @@ -80,6 +80,7 @@ type RuntimeImpl interface { ReopenContainerLog(context.Context, *Container) error CheckpointContainer(context.Context, *Container, *rspec.Spec, bool) error RestoreContainer(context.Context, *Container, string, string) error + IsContainerAlive(*Container) bool } // New creates a new Runtime with options provided. @@ -504,3 +505,12 @@ func (r *Runtime) RestoreContainer(ctx context.Context, c *Container, cgroupPare return impl.RestoreContainer(ctx, c, cgroupParent, mountLabel) } + +func (r *Runtime) IsContainerAlive(c *Container) (bool, error) { + impl, err := r.RuntimeImpl(c) + if err != nil { + return false, err + } + + return impl.IsContainerAlive(c), nil +} diff --git a/internal/oci/runtime_oci.go b/internal/oci/runtime_oci.go index 3cbf0ced210..cdf01d05645 100644 --- a/internal/oci/runtime_oci.go +++ b/internal/oci/runtime_oci.go @@ -1577,3 +1577,7 @@ func (r *runtimeOCI) checkpointRestoreSupported(runtimePath string) error { } return nil } + +func (r *runtimeOCI) IsContainerAlive(c *Container) bool { + return c.Living() == nil +} diff --git a/internal/oci/runtime_pod.go b/internal/oci/runtime_pod.go index f6b7d276bec..be674d318eb 100644 --- a/internal/oci/runtime_pod.go +++ b/internal/oci/runtime_pod.go @@ -297,3 +297,7 @@ func (r *runtimePod) ReopenContainerLog(ctx context.Context, c *Container) error ID: c.ID(), }) } + +func (r *runtimePod) IsContainerAlive(c *Container) bool { + return c.Living() == nil +} diff --git a/internal/oci/runtime_vm.go b/internal/oci/runtime_vm.go index 00e83bca50b..f8c4afbefc0 100644 --- a/internal/oci/runtime_vm.go +++ b/internal/oci/runtime_vm.go @@ -1275,3 +1275,7 @@ func EncodeKataVirtualVolumeToBase64(ctx context.Context, volume *katavolume.Kat option := base64.StdEncoding.EncodeToString(validKataVirtualVolumeJSON) return option, nil } + +func (r *runtimeVM) IsContainerAlive(c *Container) bool { + return r.kill(c.ID(), "", 0, false) == nil +} diff --git a/server/container_reopen_log.go b/server/container_reopen_log.go index 33724d877b3..38b91eb7efc 100644 --- a/server/container_reopen_log.go +++ b/server/container_reopen_log.go @@ -8,7 +8,6 @@ import ( types "k8s.io/cri-api/pkg/apis/runtime/v1" "github.com/cri-o/cri-o/internal/log" - "github.com/cri-o/cri-o/internal/oci" ) // ReopenContainerLog reopens the containers log file. @@ -20,13 +19,12 @@ func (s *Server) ReopenContainerLog(ctx context.Context, req *types.ReopenContai return nil, fmt.Errorf("could not find container %s: %w", req.ContainerId, err) } - if err := s.ContainerServer.Runtime().UpdateContainerStatus(ctx, c); err != nil { + isRunning, err := s.ContainerServer.Runtime().IsContainerAlive(c) + if err != nil { return nil, err } - - cState := c.State() - if !(cState.Status == oci.ContainerStateRunning || cState.Status == oci.ContainerStateCreated) { - return nil, errors.New("container is not created or running") + if !isRunning { + return nil, errors.New("container is not running") } if err := s.ContainerServer.Runtime().ReopenContainerLog(ctx, c); err != nil { diff --git a/test/logs.bats b/test/logs.bats new file mode 100644 index 00000000000..d703f7247e4 --- /dev/null +++ b/test/logs.bats @@ -0,0 +1,53 @@ +#!/usr/bin/env bats +# vim:set ft=bash : + +load helpers + +function setup() { + setup_test +} + +function teardown() { + cleanup_test +} + +@test "ReopenContainerLog should succeed when the container is running" { + start_crio + + jq '.metadata.name = "sleep" + | .command = ["/bin/sh", "-c", "sleep 600"]' \ + "$TESTDATA"/container_config.json > "$TESTDIR"/trap.json + + ctr_id=$(crictl run "$TESTDIR"/trap.json "$TESTDATA"/sandbox_config.json) + crictl logs -r "$ctr_id" +} + +@test "ReopenContainerLog should fail when the container is stopped" { + start_crio + + jq '.metadata.name = "sleep" + | .command = ["/bin/sh", "-c", "sleep 600"]' \ + "$TESTDATA"/container_config.json > "$TESTDIR"/trap.json + + ctr_id=$(crictl run "$TESTDIR"/trap.json "$TESTDATA"/sandbox_config.json) + crictl stop "$ctr_id" + run ! crictl logs -r "$ctr_id" +} + +@test "ReopenContainerLog should not be blocked during deletion" { + start_crio + + jq '.metadata.name = "trap" + | .command = ["/bin/sh", "-c", "trap \"sleep 600\" TERM && sleep 600"]' \ + "$TESTDATA"/container_config.json > "$TESTDIR"/trap.json + + ctr_id=$(crictl run "$TESTDIR"/trap.json "$TESTDATA"/sandbox_config.json) + # Especially when using kata, it sometimes takes a few seconds to actually run container + sleep 5 + + crictl stop -t 10 "$ctr_id" & + wait_for_log "Request: &StopContainerRequest" + crictl logs -r "$ctr_id" + output=$(crictl inspect "$ctr_id" | jq -r ".status.state") + [[ "$output" == "CONTAINER_RUNNING" ]] +} diff --git a/test/mocks/oci/oci.go b/test/mocks/oci/oci.go index 460151366fe..fc26b762599 100644 --- a/test/mocks/oci/oci.go +++ b/test/mocks/oci/oci.go @@ -141,6 +141,20 @@ func (mr *MockRuntimeImplMockRecorder) ExecSyncContainer(arg0, arg1, arg2, arg3 return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecSyncContainer", reflect.TypeOf((*MockRuntimeImpl)(nil).ExecSyncContainer), arg0, arg1, arg2, arg3) } +// IsContainerAlive mocks base method. +func (m *MockRuntimeImpl) IsContainerAlive(arg0 *oci.Container) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsContainerAlive", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsContainerAlive indicates an expected call of IsContainerAlive. +func (mr *MockRuntimeImplMockRecorder) IsContainerAlive(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsContainerAlive", reflect.TypeOf((*MockRuntimeImpl)(nil).IsContainerAlive), arg0) +} + // PauseContainer mocks base method. func (m *MockRuntimeImpl) PauseContainer(arg0 context.Context, arg1 *oci.Container) error { m.ctrl.T.Helper() From a8ba0a2debaf46c3288fc8ff32ebdd8107af3f66 Mon Sep 17 00:00:00 2001 From: Ayato Tokubi Date: Wed, 29 Jan 2025 20:20:32 +0000 Subject: [PATCH 27/47] Bump containers/storage Signed-off-by: Ayato Tokubi --- go.mod | 8 +- go.sum | 16 +- .../storage/pkg/chrootarchive/archive.go | 2 +- .../cpuguy83/go-md2man/v2/md2man/debug.go | 62 ++++++++ .../cpuguy83/go-md2man/v2/md2man/md2man.go | 9 +- .../cpuguy83/go-md2man/v2/md2man/roff.go | 88 +++++++---- .../vbatts/tar-split/archive/tar/format.go | 4 + .../vbatts/tar-split/archive/tar/reader.go | 19 ++- .../vbatts/tar-split/tar/asm/iterate.go | 57 ++++++++ vendor/golang.org/x/sys/cpu/cpu.go | 19 +++ .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 2 +- .../golang.org/x/sys/cpu/cpu_linux_riscv64.go | 137 ++++++++++++++++++ vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 11 +- vendor/golang.org/x/sys/unix/README.md | 2 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 5 +- vendor/golang.org/x/sys/unix/syscall_aix.go | 2 +- .../golang.org/x/sys/unix/syscall_darwin.go | 37 +++++ vendor/golang.org/x/sys/unix/syscall_hurd.go | 1 + vendor/golang.org/x/sys/unix/syscall_linux.go | 63 +++++++- .../x/sys/unix/syscall_linux_arm64.go | 2 + .../x/sys/unix/syscall_linux_loong64.go | 2 + .../x/sys/unix/syscall_linux_riscv64.go | 2 + .../golang.org/x/sys/unix/vgetrandom_linux.go | 13 ++ .../x/sys/unix/vgetrandom_unsupported.go | 11 ++ .../x/sys/unix/zerrors_darwin_amd64.go | 7 + .../x/sys/unix/zerrors_darwin_arm64.go | 7 + vendor/golang.org/x/sys/unix/zerrors_linux.go | 13 +- .../x/sys/unix/zerrors_linux_386.go | 5 + .../x/sys/unix/zerrors_linux_amd64.go | 5 + .../x/sys/unix/zerrors_linux_arm.go | 5 + .../x/sys/unix/zerrors_linux_arm64.go | 5 + .../x/sys/unix/zerrors_linux_loong64.go | 5 + .../x/sys/unix/zerrors_linux_mips.go | 5 + .../x/sys/unix/zerrors_linux_mips64.go | 5 + .../x/sys/unix/zerrors_linux_mips64le.go | 5 + .../x/sys/unix/zerrors_linux_mipsle.go | 5 + .../x/sys/unix/zerrors_linux_ppc.go | 5 + .../x/sys/unix/zerrors_linux_ppc64.go | 5 + .../x/sys/unix/zerrors_linux_ppc64le.go | 5 + .../x/sys/unix/zerrors_linux_riscv64.go | 5 + .../x/sys/unix/zerrors_linux_s390x.go | 5 + .../x/sys/unix/zerrors_linux_sparc64.go | 5 + .../x/sys/unix/zerrors_zos_s390x.go | 2 + .../x/sys/unix/zsyscall_darwin_amd64.go | 20 +++ .../x/sys/unix/zsyscall_darwin_amd64.s | 5 + .../x/sys/unix/zsyscall_darwin_arm64.go | 20 +++ .../x/sys/unix/zsyscall_darwin_arm64.s | 5 + .../golang.org/x/sys/unix/zsyscall_linux.go | 17 --- .../x/sys/unix/zsysnum_linux_amd64.go | 1 + .../x/sys/unix/zsysnum_linux_arm64.go | 2 +- .../x/sys/unix/zsysnum_linux_loong64.go | 2 + .../x/sys/unix/zsysnum_linux_riscv64.go | 2 +- .../x/sys/unix/ztypes_darwin_amd64.go | 13 ++ .../x/sys/unix/ztypes_darwin_arm64.go | 13 ++ .../x/sys/unix/ztypes_freebsd_386.go | 1 + .../x/sys/unix/ztypes_freebsd_amd64.go | 1 + .../x/sys/unix/ztypes_freebsd_arm.go | 1 + .../x/sys/unix/ztypes_freebsd_arm64.go | 1 + .../x/sys/unix/ztypes_freebsd_riscv64.go | 1 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 90 ++++++++---- .../x/sys/unix/ztypes_linux_riscv64.go | 33 +++++ .../golang.org/x/sys/windows/dll_windows.go | 2 +- .../x/sys/windows/syscall_windows.go | 4 + .../golang.org/x/sys/windows/types_windows.go | 1 + .../x/sys/windows/zsyscall_windows.go | 38 +++++ vendor/modules.txt | 8 +- 66 files changed, 848 insertions(+), 111 deletions(-) create mode 100644 vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go create mode 100644 vendor/github.com/vbatts/tar-split/tar/asm/iterate.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_linux.go create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go diff --git a/go.mod b/go.mod index 6704bc03b87..f9da3bb2611 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/containers/image/v5 v5.32.2 github.com/containers/kubensmnt v1.2.0 github.com/containers/ocicrypt v1.2.0 - github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192 + github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622 github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 github.com/cpuguy83/go-md2man v1.0.10 github.com/creack/pty v1.1.23 @@ -72,7 +72,7 @@ require ( go.opentelemetry.io/otel/trace v1.29.0 golang.org/x/net v0.28.0 golang.org/x/sync v0.8.0 - golang.org/x/sys v0.24.0 + golang.org/x/sys v0.26.0 google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 k8s.io/api v0.31.0 @@ -111,7 +111,7 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect @@ -201,7 +201,7 @@ require ( github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/ulikunitz/xz v0.5.12 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.1 // indirect - github.com/vbatts/tar-split v0.11.5 // indirect + github.com/vbatts/tar-split v0.11.7 // indirect github.com/vbauerster/mpb/v8 v8.7.5 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/x448/float16 v0.8.4 // indirect diff --git a/go.sum b/go.sum index d5b724eee3a..1e3d549ea91 100644 --- a/go.sum +++ b/go.sum @@ -740,14 +740,14 @@ github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYgle github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= -github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192 h1:ZI84/Ws/ijsuVczHkmp8ZCfyBlPhdii7dlzO4FJcw6M= -github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= +github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622 h1:l9Ac/lg0yGbpPQMcF2h0GcPvinjoGvCwpWIFoHkmlDs= +github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622/go.mod h1:YMWW2yZKeL1xcK8zM8ioGKILPwVIJsIGpXC4x8DBqpo= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 h1:OoRAFlvDGCUqDLampLQjk0yeeSGdF9zzst/3G9IkBbc= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09/go.mod h1:m2r/smMKsKwgMSAoFKHaa68ImdCSNuKE1MxvQ64xuCQ= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= @@ -1274,8 +1274,8 @@ github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.1 h1:Suvl9fe12MM0oi8/rcG github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.1/go.mod h1:aiX/F5+EYbY2ed2OQEYRXzMcNGvI9pip5gW2ZtBDers= github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= -github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= -github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= +github.com/vbatts/tar-split v0.11.7 h1:ixZ93pO/GmvaZw4Vq9OwmfZK/kc2zKdPfu0B+gYqs3U= +github.com/vbatts/tar-split v0.11.7/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= github.com/vbauerster/mpb/v8 v8.7.5 h1:hUF3zaNsuaBBwzEFoCvfuX3cpesQXZC0Phm/JcHZQ+c= github.com/vbauerster/mpb/v8 v8.7.5/go.mod h1:bRCnR7K+mj5WXKsy0NWB6Or+wctYGvVwKn6huwvxKa0= github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= @@ -1630,8 +1630,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= diff --git a/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go b/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go index 5ff9f6b5117..82c47655bef 100644 --- a/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go +++ b/vendor/github.com/containers/storage/pkg/chrootarchive/archive.go @@ -47,7 +47,7 @@ func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error // This should be used to prevent a potential attacker from manipulating `dest` // such that it would provide access to files outside of `dest` through things // like symlinks. Normally `ResolveSymlinksInScope` would handle this, however -// sanitizing symlinks in this manner is inherrently racey: +// sanitizing symlinks in this manner is inherently racey: // ref: CVE-2018-15664 func UntarWithRoot(tarArchive io.Reader, dest string, options *archive.TarOptions, root string) error { return untarHandler(tarArchive, dest, options, true, root) diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go new file mode 100644 index 00000000000..0ec4b12c75d --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go @@ -0,0 +1,62 @@ +package md2man + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/russross/blackfriday/v2" +) + +func fmtListFlags(flags blackfriday.ListType) string { + knownFlags := []struct { + name string + flag blackfriday.ListType + }{ + {"ListTypeOrdered", blackfriday.ListTypeOrdered}, + {"ListTypeDefinition", blackfriday.ListTypeDefinition}, + {"ListTypeTerm", blackfriday.ListTypeTerm}, + {"ListItemContainsBlock", blackfriday.ListItemContainsBlock}, + {"ListItemBeginningOfList", blackfriday.ListItemBeginningOfList}, + {"ListItemEndOfList", blackfriday.ListItemEndOfList}, + } + + var f []string + for _, kf := range knownFlags { + if flags&kf.flag != 0 { + f = append(f, kf.name) + flags &^= kf.flag + } + } + if flags != 0 { + f = append(f, fmt.Sprintf("Unknown(%#x)", flags)) + } + return strings.Join(f, "|") +} + +type debugDecorator struct { + blackfriday.Renderer +} + +func depth(node *blackfriday.Node) int { + d := 0 + for n := node.Parent; n != nil; n = n.Parent { + d++ + } + return d +} + +func (d *debugDecorator) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + fmt.Fprintf(os.Stderr, "%s%s %v %v\n", + strings.Repeat(" ", depth(node)), + map[bool]string{true: "+", false: "-"}[entering], + node, + fmtListFlags(node.ListFlags)) + var b strings.Builder + status := d.Renderer.RenderNode(io.MultiWriter(&b, w), node, entering) + if b.Len() > 0 { + fmt.Fprintf(os.Stderr, ">> %q\n", b.String()) + } + return status +} diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go index 42bf32aab00..62d91b77d58 100644 --- a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go @@ -1,16 +1,23 @@ package md2man import ( + "os" + "strconv" + "github.com/russross/blackfriday/v2" ) // Render converts a markdown document into a roff formatted document. func Render(doc []byte) []byte { renderer := NewRoffRenderer() + var r blackfriday.Renderer = renderer + if v, _ := strconv.ParseBool(os.Getenv("MD2MAN_DEBUG")); v { + r = &debugDecorator{Renderer: r} + } return blackfriday.Run(doc, []blackfriday.Option{ - blackfriday.WithRenderer(renderer), + blackfriday.WithRenderer(r), blackfriday.WithExtensions(renderer.GetExtensions()), }...) } diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go index 8a290f1972a..9d6c473fdc0 100644 --- a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go @@ -14,10 +14,8 @@ import ( // roffRenderer implements the blackfriday.Renderer interface for creating // roff format (manpages) from markdown text type roffRenderer struct { - extensions blackfriday.Extensions listCounters []int firstHeader bool - firstDD bool listDepth int } @@ -43,7 +41,7 @@ const ( quoteTag = "\n.PP\n.RS\n" quoteCloseTag = "\n.RE\n" listTag = "\n.RS\n" - listCloseTag = "\n.RE\n" + listCloseTag = ".RE\n" dtTag = "\n.TP\n" dd2Tag = "\n" tableStart = "\n.TS\nallbox;\n" @@ -56,23 +54,18 @@ const ( // NewRoffRenderer creates a new blackfriday Renderer for generating roff documents // from markdown func NewRoffRenderer() *roffRenderer { // nolint: golint - var extensions blackfriday.Extensions - - extensions |= blackfriday.NoIntraEmphasis - extensions |= blackfriday.Tables - extensions |= blackfriday.FencedCode - extensions |= blackfriday.SpaceHeadings - extensions |= blackfriday.Footnotes - extensions |= blackfriday.Titleblock - extensions |= blackfriday.DefinitionLists - return &roffRenderer{ - extensions: extensions, - } + return &roffRenderer{} } // GetExtensions returns the list of extensions used by this renderer implementation -func (r *roffRenderer) GetExtensions() blackfriday.Extensions { - return r.extensions +func (*roffRenderer) GetExtensions() blackfriday.Extensions { + return blackfriday.NoIntraEmphasis | + blackfriday.Tables | + blackfriday.FencedCode | + blackfriday.SpaceHeadings | + blackfriday.Footnotes | + blackfriday.Titleblock | + blackfriday.DefinitionLists } // RenderHeader handles outputting the header at document start @@ -103,7 +96,23 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering switch node.Type { case blackfriday.Text: - escapeSpecialChars(w, node.Literal) + // Special case: format the NAME section as required for proper whatis parsing. + // Refer to the lexgrog(1) and groff_man(7) manual pages for details. + if node.Parent != nil && + node.Parent.Type == blackfriday.Paragraph && + node.Parent.Prev != nil && + node.Parent.Prev.Type == blackfriday.Heading && + node.Parent.Prev.FirstChild != nil && + bytes.EqualFold(node.Parent.Prev.FirstChild.Literal, []byte("NAME")) { + before, after, found := bytes.Cut(node.Literal, []byte(" - ")) + escapeSpecialChars(w, before) + if found { + out(w, ` \- `) + escapeSpecialChars(w, after) + } + } else { + escapeSpecialChars(w, node.Literal) + } case blackfriday.Softbreak: out(w, crTag) case blackfriday.Hardbreak: @@ -141,14 +150,25 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering case blackfriday.Document: break case blackfriday.Paragraph: - // roff .PP markers break lists - if r.listDepth > 0 { - return blackfriday.GoToNext - } if entering { - out(w, paraTag) + if r.listDepth > 0 { + // roff .PP markers break lists + if node.Prev != nil { // continued paragraph + if node.Prev.Type == blackfriday.List && node.Prev.ListFlags&blackfriday.ListTypeDefinition == 0 { + out(w, ".IP\n") + } else { + out(w, crTag) + } + } + } else if node.Prev != nil && node.Prev.Type == blackfriday.Heading { + out(w, crTag) + } else { + out(w, paraTag) + } } else { - out(w, crTag) + if node.Next == nil || node.Next.Type != blackfriday.List { + out(w, crTag) + } } case blackfriday.BlockQuote: if entering { @@ -211,6 +231,10 @@ func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, enteri func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) { openTag := listTag closeTag := listCloseTag + if (entering && r.listDepth == 0) || (!entering && r.listDepth == 1) { + openTag = crTag + closeTag = "" + } if node.ListFlags&blackfriday.ListTypeDefinition != 0 { // tags for definition lists handled within Item node openTag = "" @@ -239,23 +263,25 @@ func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering } else if node.ListFlags&blackfriday.ListTypeTerm != 0 { // DT (definition term): line just before DD (see below). out(w, dtTag) - r.firstDD = true } else if node.ListFlags&blackfriday.ListTypeDefinition != 0 { // DD (definition description): line that starts with ": ". // // We have to distinguish between the first DD and the // subsequent ones, as there should be no vertical // whitespace between the DT and the first DD. - if r.firstDD { - r.firstDD = false - } else { - out(w, dd2Tag) + if node.Prev != nil && node.Prev.ListFlags&(blackfriday.ListTypeTerm|blackfriday.ListTypeDefinition) == blackfriday.ListTypeDefinition { + if node.Prev.Type == blackfriday.Item && + node.Prev.LastChild != nil && + node.Prev.LastChild.Type == blackfriday.List && + node.Prev.LastChild.ListFlags&blackfriday.ListTypeDefinition == 0 { + out(w, ".IP\n") + } else { + out(w, dd2Tag) + } } } else { out(w, ".IP \\(bu 2\n") } - } else { - out(w, "\n") } } diff --git a/vendor/github.com/vbatts/tar-split/archive/tar/format.go b/vendor/github.com/vbatts/tar-split/archive/tar/format.go index 1f89d0c59a1..60977980c5a 100644 --- a/vendor/github.com/vbatts/tar-split/archive/tar/format.go +++ b/vendor/github.com/vbatts/tar-split/archive/tar/format.go @@ -143,6 +143,10 @@ const ( blockSize = 512 // Size of each block in a tar stream nameSize = 100 // Max length of the name field in USTAR format prefixSize = 155 // Max length of the prefix field in USTAR format + + // Max length of a special file (PAX header, GNU long name or link). + // This matches the limit used by libarchive. + maxSpecialFileSize = 1 << 20 ) // blockPadding computes the number of bytes needed to pad offset up to the diff --git a/vendor/github.com/vbatts/tar-split/archive/tar/reader.go b/vendor/github.com/vbatts/tar-split/archive/tar/reader.go index af006fc92e8..248a7ccb15a 100644 --- a/vendor/github.com/vbatts/tar-split/archive/tar/reader.go +++ b/vendor/github.com/vbatts/tar-split/archive/tar/reader.go @@ -56,6 +56,11 @@ func (tr *Reader) RawBytes() []byte { } +// ExpectedPadding returns the number of bytes of padding expected after the last header returned by Next() +func (tr *Reader) ExpectedPadding() int64 { + return tr.pad +} + // NewReader creates a new Reader reading from r. func NewReader(r io.Reader) *Reader { return &Reader{r: r, curr: ®FileReader{r, 0}} @@ -139,7 +144,7 @@ func (tr *Reader) next() (*Header, error) { continue // This is a meta header affecting the next header case TypeGNULongName, TypeGNULongLink: format.mayOnlyBe(FormatGNU) - realname, err := io.ReadAll(tr) + realname, err := readSpecialFile(tr) if err != nil { return nil, err } @@ -333,7 +338,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { // parsePAX parses PAX headers. // If an extended header (type 'x') is invalid, ErrHeader is returned func parsePAX(r io.Reader) (map[string]string, error) { - buf, err := io.ReadAll(r) + buf, err := readSpecialFile(r) if err != nil { return nil, err } @@ -884,6 +889,16 @@ func tryReadFull(r io.Reader, b []byte) (n int, err error) { return n, err } +// readSpecialFile is like io.ReadAll except it returns +// ErrFieldTooLong if more than maxSpecialFileSize is read. +func readSpecialFile(r io.Reader) ([]byte, error) { + buf, err := io.ReadAll(io.LimitReader(r, maxSpecialFileSize+1)) + if len(buf) > maxSpecialFileSize { + return nil, ErrFieldTooLong + } + return buf, err +} + // discard skips n bytes in r, reporting an error if unable to do so. func discard(tr *Reader, n int64) error { var seekSkipped, copySkipped int64 diff --git a/vendor/github.com/vbatts/tar-split/tar/asm/iterate.go b/vendor/github.com/vbatts/tar-split/tar/asm/iterate.go new file mode 100644 index 00000000000..8a65887cf22 --- /dev/null +++ b/vendor/github.com/vbatts/tar-split/tar/asm/iterate.go @@ -0,0 +1,57 @@ +package asm + +import ( + "bytes" + "fmt" + "io" + + "github.com/vbatts/tar-split/archive/tar" + "github.com/vbatts/tar-split/tar/storage" +) + +// IterateHeaders calls handler for each tar header provided by Unpacker +func IterateHeaders(unpacker storage.Unpacker, handler func(hdr *tar.Header) error) error { + // We assume about NewInputTarStream: + // - There is a separate SegmentType entry for every tar header, but only one SegmentType entry for the full header incl. any extensions + // - (There is a FileType entry for every tar header, we ignore it) + // - Trailing padding of a file, if any, is included in the next SegmentType entry + // - At the end, there may be SegmentType entries just for the terminating zero blocks. + + var pendingPadding int64 = 0 + for { + tsEntry, err := unpacker.Next() + if err != nil { + if err == io.EOF { + return nil + } + return fmt.Errorf("reading tar-split entries: %w", err) + } + switch tsEntry.Type { + case storage.SegmentType: + payload := tsEntry.Payload + if int64(len(payload)) < pendingPadding { + return fmt.Errorf("expected %d bytes of padding after previous file, but next SegmentType only has %d bytes", pendingPadding, len(payload)) + } + payload = payload[pendingPadding:] + pendingPadding = 0 + + tr := tar.NewReader(bytes.NewReader(payload)) + hdr, err := tr.Next() + if err != nil { + if err == io.EOF { // Probably the last entry, but let’s let the unpacker drive that. + break + } + return fmt.Errorf("decoding a tar header from a tar-split entry: %w", err) + } + if err := handler(hdr); err != nil { + return err + } + pendingPadding = tr.ExpectedPadding() + + case storage.FileType: + // Nothing + default: + return fmt.Errorf("unexpected tar-split entry type %q", tsEntry.Type) + } + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go index ec07aab0578..02609d5b21d 100644 --- a/vendor/golang.org/x/sys/cpu/cpu.go +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -201,6 +201,25 @@ var S390X struct { _ CacheLinePad } +// RISCV64 contains the supported CPU features and performance characteristics for riscv64 +// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate +// the presence of RISC-V extensions. +// +// It is safe to assume that all the RV64G extensions are supported and so they are omitted from +// this structure. As riscv64 Go programs require at least RV64G, the code that populates +// this structure cannot run successfully if some of the RV64G extensions are missing. +// The struct is padded to avoid false sharing. +var RISCV64 struct { + _ CacheLinePad + HasFastMisaligned bool // Fast misaligned accesses + HasC bool // Compressed instruction-set extension + HasV bool // Vector extension compatible with RVV 1.0 + HasZba bool // Address generation instructions extension + HasZbb bool // Basic bit-manipulation extension + HasZbs bool // Single-bit instructions extension + _ CacheLinePad +} + func init() { archInit() initOptions() diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go index cd63e733557..7d902b6847b 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x +//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64 package cpu diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go new file mode 100644 index 00000000000..cb4a0c57280 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go @@ -0,0 +1,137 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "syscall" + "unsafe" +) + +// RISC-V extension discovery code for Linux. The approach here is to first try the riscv_hwprobe +// syscall falling back to HWCAP to check for the C extension if riscv_hwprobe is not available. +// +// A note on detection of the Vector extension using HWCAP. +// +// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5. +// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe +// syscall is not available then neither is the Vector extension (which needs kernel support). +// The riscv_hwprobe syscall should then be all we need to detect the Vector extension. +// However, some RISC-V board manufacturers ship boards with an older kernel on top of which +// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe +// patches. These kernels advertise support for the Vector extension using HWCAP. Falling +// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not +// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option. +// +// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by +// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board +// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified +// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use +// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector +// extension are binary incompatible. HWCAP can then not be used in isolation to populate the +// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0. +// +// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector +// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype +// register. This check would allow us to safely detect version 1.0 of the Vector extension +// with HWCAP, if riscv_hwprobe were not available. However, the check cannot +// be added until the assembler supports the Vector instructions. +// +// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the +// extensions it advertises support for are explicitly versioned. It's also worth noting that +// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zba. +// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority +// of RISC-V extensions. +// +// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information. + +// golang.org/x/sys/cpu is not allowed to depend on golang.org/x/sys/unix so we must +// reproduce the constants, types and functions needed to make the riscv_hwprobe syscall +// here. + +const ( + // Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. + riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4 + riscv_HWPROBE_IMA_C = 0x2 + riscv_HWPROBE_IMA_V = 0x4 + riscv_HWPROBE_EXT_ZBA = 0x8 + riscv_HWPROBE_EXT_ZBB = 0x10 + riscv_HWPROBE_EXT_ZBS = 0x20 + riscv_HWPROBE_KEY_CPUPERF_0 = 0x5 + riscv_HWPROBE_MISALIGNED_FAST = 0x3 + riscv_HWPROBE_MISALIGNED_MASK = 0x7 +) + +const ( + // sys_RISCV_HWPROBE is copied from golang.org/x/sys/unix/zsysnum_linux_riscv64.go. + sys_RISCV_HWPROBE = 258 +) + +// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. +type riscvHWProbePairs struct { + key int64 + value uint64 +} + +const ( + // CPU features + hwcap_RISCV_ISA_C = 1 << ('C' - 'A') +) + +func doinit() { + // A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key + // field should be initialised with one of the key constants defined above, e.g., + // RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value. + // If the kernel does not recognise a key it will set the key field to -1 and the value field to 0. + + pairs := []riscvHWProbePairs{ + {riscv_HWPROBE_KEY_IMA_EXT_0, 0}, + {riscv_HWPROBE_KEY_CPUPERF_0, 0}, + } + + // This call only indicates that extensions are supported if they are implemented on all cores. + if riscvHWProbe(pairs, 0) { + if pairs[0].key != -1 { + v := uint(pairs[0].value) + RISCV64.HasC = isSet(v, riscv_HWPROBE_IMA_C) + RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V) + RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA) + RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB) + RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS) + } + if pairs[1].key != -1 { + v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK + RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST + } + } + + // Let's double check with HWCAP if the C extension does not appear to be supported. + // This may happen if we're running on a kernel older than 6.4. + + if !RISCV64.HasC { + RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C) + } +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} + +// riscvHWProbe is a simplified version of the generated wrapper function found in +// golang.org/x/sys/unix/zsyscall_linux_riscv64.go. We simplify it by removing the +// cpuCount and cpus parameters which we do not need. We always want to pass 0 for +// these parameters here so the kernel only reports the extensions that are present +// on all cores. +func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool { + var _zero uintptr + var p0 unsafe.Pointer + if len(pairs) > 0 { + p0 = unsafe.Pointer(&pairs[0]) + } else { + p0 = unsafe.Pointer(&_zero) + } + + _, _, e1 := syscall.Syscall6(sys_RISCV_HWPROBE, uintptr(p0), uintptr(len(pairs)), uintptr(0), uintptr(0), uintptr(flags), 0) + return e1 == 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go index 7f0c79c004b..aca3199c911 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go +++ b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go @@ -8,4 +8,13 @@ package cpu const cacheLineSize = 64 -func initOptions() {} +func initOptions() { + options = []option{ + {Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned}, + {Name: "c", Feature: &RISCV64.HasC}, + {Name: "v", Feature: &RISCV64.HasV}, + {Name: "zba", Feature: &RISCV64.HasZba}, + {Name: "zbb", Feature: &RISCV64.HasZbb}, + {Name: "zbs", Feature: &RISCV64.HasZbs}, + } +} diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md index 7d3c060e122..6e08a76a716 100644 --- a/vendor/golang.org/x/sys/unix/README.md +++ b/vendor/golang.org/x/sys/unix/README.md @@ -156,7 +156,7 @@ from the generated architecture-specific files listed below, and merge these into a common file for each OS. The merge is performed in the following steps: -1. Construct the set of common code that is idential in all architecture-specific files. +1. Construct the set of common code that is identical in all architecture-specific files. 2. Write this common code to the merged file. 3. Remove the common code from all architecture-specific files. diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index d07dd09eb50..ac54ecaba0a 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -552,6 +552,7 @@ ccflags="$@" $2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ && $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ || $2 ~ /^SOCK_|SK_DIAG_|SKNLGRP_$/ || + $2 ~ /^(CONNECT|SAE)_/ || $2 ~ /^FIORDCHK$/ || $2 ~ /^SIOC/ || $2 ~ /^TIOC/ || @@ -655,7 +656,7 @@ errors=$( signals=$( echo '#include ' | $CC -x c - -E -dM $ccflags | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | - grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' | + grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | sort ) @@ -665,7 +666,7 @@ echo '#include ' | $CC -x c - -E -dM $ccflags | sort >_error.grep echo '#include ' | $CC -x c - -E -dM $ccflags | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | - grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' | + grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | sort >_signal.grep echo '// mkerrors.sh' "$@" diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go index 67ce6cef2d5..6f15ba1eaff 100644 --- a/vendor/golang.org/x/sys/unix/syscall_aix.go +++ b/vendor/golang.org/x/sys/unix/syscall_aix.go @@ -360,7 +360,7 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, var status _C_int var r Pid_t err = ERESTART - // AIX wait4 may return with ERESTART errno, while the processus is still + // AIX wait4 may return with ERESTART errno, while the process is still // active. for err == ERESTART { r, err = wait4(Pid_t(pid), &status, options, rusage) diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 2d15200adb4..099867deede 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -566,6 +566,43 @@ func PthreadFchdir(fd int) (err error) { return pthread_fchdir_np(fd) } +// Connectx calls connectx(2) to initiate a connection on a socket. +// +// srcIf, srcAddr, and dstAddr are filled into a [SaEndpoints] struct and passed as the endpoints argument. +// +// - srcIf is the optional source interface index. 0 means unspecified. +// - srcAddr is the optional source address. nil means unspecified. +// - dstAddr is the destination address. +// +// On success, Connectx returns the number of bytes enqueued for transmission. +func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocID, flags uint32, iov []Iovec, connid *SaeConnID) (n uintptr, err error) { + endpoints := SaEndpoints{ + Srcif: srcIf, + } + + if srcAddr != nil { + addrp, addrlen, err := srcAddr.sockaddr() + if err != nil { + return 0, err + } + endpoints.Srcaddr = (*RawSockaddr)(addrp) + endpoints.Srcaddrlen = uint32(addrlen) + } + + if dstAddr != nil { + addrp, addrlen, err := dstAddr.sockaddr() + if err != nil { + return 0, err + } + endpoints.Dstaddr = (*RawSockaddr)(addrp) + endpoints.Dstaddrlen = uint32(addrlen) + } + + err = connectx(fd, &endpoints, associd, flags, iov, &n, connid) + return +} + +//sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_hurd.go b/vendor/golang.org/x/sys/unix/syscall_hurd.go index ba46651f8e3..a6a2d2fc2b9 100644 --- a/vendor/golang.org/x/sys/unix/syscall_hurd.go +++ b/vendor/golang.org/x/sys/unix/syscall_hurd.go @@ -11,6 +11,7 @@ package unix int ioctl(int, unsigned long int, uintptr_t); */ import "C" +import "unsafe" func ioctl(fd int, req uint, arg uintptr) (err error) { r0, er := C.ioctl(C.int(fd), C.ulong(req), C.uintptr_t(arg)) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 3f1d3d4cb25..f08abd434ff 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -1295,6 +1295,48 @@ func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) { return &value, err } +// GetsockoptTCPCCVegasInfo returns algorithm specific congestion control information for a socket using the "vegas" +// algorithm. +// +// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option: +// +// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION) +func GetsockoptTCPCCVegasInfo(fd, level, opt int) (*TCPVegasInfo, error) { + var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment + vallen := _Socklen(SizeofTCPCCInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + out := (*TCPVegasInfo)(unsafe.Pointer(&value[0])) + return out, err +} + +// GetsockoptTCPCCDCTCPInfo returns algorithm specific congestion control information for a socket using the "dctp" +// algorithm. +// +// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option: +// +// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION) +func GetsockoptTCPCCDCTCPInfo(fd, level, opt int) (*TCPDCTCPInfo, error) { + var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment + vallen := _Socklen(SizeofTCPCCInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + out := (*TCPDCTCPInfo)(unsafe.Pointer(&value[0])) + return out, err +} + +// GetsockoptTCPCCBBRInfo returns algorithm specific congestion control information for a socket using the "bbr" +// algorithm. +// +// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option: +// +// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION) +func GetsockoptTCPCCBBRInfo(fd, level, opt int) (*TCPBBRInfo, error) { + var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment + vallen := _Socklen(SizeofTCPCCInfo) + err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen) + out := (*TCPBBRInfo)(unsafe.Pointer(&value[0])) + return out, err +} + // GetsockoptString returns the string value of the socket option opt for the // socket associated with fd at the given socket level. func GetsockoptString(fd, level, opt int) (string, error) { @@ -1959,7 +2001,26 @@ func Getpgrp() (pid int) { //sysnb Getpid() (pid int) //sysnb Getppid() (ppid int) //sys Getpriority(which int, who int) (prio int, err error) -//sys Getrandom(buf []byte, flags int) (n int, err error) + +func Getrandom(buf []byte, flags int) (n int, err error) { + vdsoRet, supported := vgetrandom(buf, uint32(flags)) + if supported { + if vdsoRet < 0 { + return 0, errnoErr(syscall.Errno(-vdsoRet)) + } + return vdsoRet, nil + } + var p *byte + if len(buf) > 0 { + p = &buf[0] + } + r, _, e := Syscall(SYS_GETRANDOM, uintptr(unsafe.Pointer(p)), uintptr(len(buf)), uintptr(flags)) + if e != 0 { + return 0, errnoErr(e) + } + return int(r), nil +} + //sysnb Getrusage(who int, rusage *Rusage) (err error) //sysnb Getsid(pid int) (sid int, err error) //sysnb Gettid() (tid int) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index cf2ee6c75ef..745e5c7e6c0 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -182,3 +182,5 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error } return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) } + +const SYS_FSTATAT = SYS_NEWFSTATAT diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go index 3d0e98451f8..dd2262a4079 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go @@ -214,3 +214,5 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error } return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) } + +const SYS_FSTATAT = SYS_NEWFSTATAT diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go index 6f5a288944d..8cf3670bda6 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -187,3 +187,5 @@ func RISCVHWProbe(pairs []RISCVHWProbePairs, set *CPUSet, flags uint) (err error } return riscvHWProbe(pairs, setSize, set, flags) } + +const SYS_FSTATAT = SYS_NEWFSTATAT diff --git a/vendor/golang.org/x/sys/unix/vgetrandom_linux.go b/vendor/golang.org/x/sys/unix/vgetrandom_linux.go new file mode 100644 index 00000000000..07ac8e09d1b --- /dev/null +++ b/vendor/golang.org/x/sys/unix/vgetrandom_linux.go @@ -0,0 +1,13 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && go1.24 + +package unix + +import _ "unsafe" + +//go:linkname vgetrandom runtime.vgetrandom +//go:noescape +func vgetrandom(p []byte, flags uint32) (ret int, supported bool) diff --git a/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go b/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go new file mode 100644 index 00000000000..297e97bce92 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go @@ -0,0 +1,11 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux || !go1.24 + +package unix + +func vgetrandom(p []byte, flags uint32) (ret int, supported bool) { + return -1, false +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go index 4308ac1772b..d73c4652e6c 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go @@ -237,6 +237,9 @@ const ( CLOCK_UPTIME_RAW_APPROX = 0x9 CLONE_NOFOLLOW = 0x1 CLONE_NOOWNERCOPY = 0x2 + CONNECT_DATA_AUTHENTICATED = 0x4 + CONNECT_DATA_IDEMPOTENT = 0x2 + CONNECT_RESUME_ON_READ_WRITE = 0x1 CR0 = 0x0 CR1 = 0x1000 CR2 = 0x2000 @@ -1265,6 +1268,10 @@ const ( RTV_SSTHRESH = 0x20 RUSAGE_CHILDREN = -0x1 RUSAGE_SELF = 0x0 + SAE_ASSOCID_ALL = 0xffffffff + SAE_ASSOCID_ANY = 0x0 + SAE_CONNID_ALL = 0xffffffff + SAE_CONNID_ANY = 0x0 SCM_CREDS = 0x3 SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go index c8068a7a169..4a55a400588 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go @@ -237,6 +237,9 @@ const ( CLOCK_UPTIME_RAW_APPROX = 0x9 CLONE_NOFOLLOW = 0x1 CLONE_NOOWNERCOPY = 0x2 + CONNECT_DATA_AUTHENTICATED = 0x4 + CONNECT_DATA_IDEMPOTENT = 0x2 + CONNECT_RESUME_ON_READ_WRITE = 0x1 CR0 = 0x0 CR1 = 0x1000 CR2 = 0x2000 @@ -1265,6 +1268,10 @@ const ( RTV_SSTHRESH = 0x20 RUSAGE_CHILDREN = -0x1 RUSAGE_SELF = 0x0 + SAE_ASSOCID_ALL = 0xffffffff + SAE_ASSOCID_ANY = 0x0 + SAE_CONNID_ALL = 0xffffffff + SAE_CONNID_ANY = 0x0 SCM_CREDS = 0x3 SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index 01a70b24638..de3b462489c 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -495,6 +495,7 @@ const ( BPF_F_TEST_REG_INVARIANTS = 0x80 BPF_F_TEST_RND_HI32 = 0x4 BPF_F_TEST_RUN_ON_CPU = 0x1 + BPF_F_TEST_SKB_CHECKSUM_COMPLETE = 0x4 BPF_F_TEST_STATE_FREQ = 0x8 BPF_F_TEST_XDP_LIVE_FRAMES = 0x2 BPF_F_XDP_DEV_BOUND_ONLY = 0x40 @@ -1922,6 +1923,7 @@ const ( MNT_EXPIRE = 0x4 MNT_FORCE = 0x1 MNT_ID_REQ_SIZE_VER0 = 0x18 + MNT_ID_REQ_SIZE_VER1 = 0x20 MODULE_INIT_COMPRESSED_FILE = 0x4 MODULE_INIT_IGNORE_MODVERSIONS = 0x1 MODULE_INIT_IGNORE_VERMAGIC = 0x2 @@ -2187,7 +2189,7 @@ const ( NFT_REG_SIZE = 0x10 NFT_REJECT_ICMPX_MAX = 0x3 NFT_RT_MAX = 0x4 - NFT_SECMARK_CTX_MAXLEN = 0x100 + NFT_SECMARK_CTX_MAXLEN = 0x1000 NFT_SET_MAXNAMELEN = 0x100 NFT_SOCKET_MAX = 0x3 NFT_TABLE_F_MASK = 0x7 @@ -2356,9 +2358,11 @@ const ( PERF_MEM_LVLNUM_IO = 0xa PERF_MEM_LVLNUM_L1 = 0x1 PERF_MEM_LVLNUM_L2 = 0x2 + PERF_MEM_LVLNUM_L2_MHB = 0x5 PERF_MEM_LVLNUM_L3 = 0x3 PERF_MEM_LVLNUM_L4 = 0x4 PERF_MEM_LVLNUM_LFB = 0xc + PERF_MEM_LVLNUM_MSC = 0x6 PERF_MEM_LVLNUM_NA = 0xf PERF_MEM_LVLNUM_PMEM = 0xe PERF_MEM_LVLNUM_RAM = 0xd @@ -2431,6 +2435,7 @@ const ( PRIO_PGRP = 0x1 PRIO_PROCESS = 0x0 PRIO_USER = 0x2 + PROCFS_IOCTL_MAGIC = 'f' PROC_SUPER_MAGIC = 0x9fa0 PROT_EXEC = 0x4 PROT_GROWSDOWN = 0x1000000 @@ -2933,11 +2938,12 @@ const ( RUSAGE_SELF = 0x0 RUSAGE_THREAD = 0x1 RWF_APPEND = 0x10 + RWF_ATOMIC = 0x40 RWF_DSYNC = 0x2 RWF_HIPRI = 0x1 RWF_NOAPPEND = 0x20 RWF_NOWAIT = 0x8 - RWF_SUPPORTED = 0x3f + RWF_SUPPORTED = 0x7f RWF_SYNC = 0x4 RWF_WRITE_LIFE_NOT_SET = 0x0 SCHED_BATCH = 0x3 @@ -3210,6 +3216,7 @@ const ( STATX_ATTR_MOUNT_ROOT = 0x2000 STATX_ATTR_NODUMP = 0x40 STATX_ATTR_VERITY = 0x100000 + STATX_ATTR_WRITE_ATOMIC = 0x400000 STATX_BASIC_STATS = 0x7ff STATX_BLOCKS = 0x400 STATX_BTIME = 0x800 @@ -3226,6 +3233,7 @@ const ( STATX_SUBVOL = 0x8000 STATX_TYPE = 0x1 STATX_UID = 0x8 + STATX_WRITE_ATOMIC = 0x10000 STATX__RESERVED = 0x80000000 SYNC_FILE_RANGE_WAIT_AFTER = 0x4 SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 @@ -3624,6 +3632,7 @@ const ( XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 XDP_UMEM_PGOFF_FILL_RING = 0x100000000 XDP_UMEM_REG = 0x4 + XDP_UMEM_TX_METADATA_LEN = 0x4 XDP_UMEM_TX_SW_CSUM = 0x2 XDP_UMEM_UNALIGNED_CHUNK_FLAG = 0x1 XDP_USE_NEED_WAKEUP = 0x8 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 684a5168dac..8aa6d77c018 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -153,9 +153,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 61d74b592d6..da428f42533 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -153,9 +153,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index a28c9e3e893..bf45bfec78a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -150,9 +150,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index ab5d1fe8ead..71c67162b73 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -154,9 +154,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index c523090e7c1..9476628fa02 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -154,9 +154,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 01e6ea7804b..b9e85f3cf0c 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -150,9 +150,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 7aa610b1e71..a48b68a7647 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -150,9 +150,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 92af771b44a..ea00e8522a1 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -150,9 +150,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index b27ef5e6f11..91c64687176 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -150,9 +150,14 @@ const ( NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index 237a2cefb3e..8cbf38d6390 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -152,9 +152,14 @@ const ( NL3 = 0x300 NLDLY = 0x300 NOFLSH = 0x80000000 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x4 ONLCR = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 4a5c555a36e..a2df7341917 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -152,9 +152,14 @@ const ( NL3 = 0x300 NLDLY = 0x300 NOFLSH = 0x80000000 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x4 ONLCR = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index a02fb49a5f8..24791379233 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -152,9 +152,14 @@ const ( NL3 = 0x300 NLDLY = 0x300 NOFLSH = 0x80000000 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x4 ONLCR = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index e26a7c61b2b..d265f146ee0 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -150,9 +150,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index c48f7c2103b..3f2d6443964 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -150,9 +150,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x8008b705 NS_GET_NSTYPE = 0xb703 NS_GET_OWNER_UID = 0xb704 NS_GET_PARENT = 0xb702 + NS_GET_PID_FROM_PIDNS = 0x8004b706 + NS_GET_PID_IN_PIDNS = 0x8004b708 + NS_GET_TGID_FROM_PIDNS = 0x8004b707 + NS_GET_TGID_IN_PIDNS = 0x8004b709 NS_GET_USERNS = 0xb701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index ad4b9aace7b..5d8b727a1c8 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -155,9 +155,14 @@ const ( NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 + NS_GET_MNTNS_ID = 0x4008b705 NS_GET_NSTYPE = 0x2000b703 NS_GET_OWNER_UID = 0x2000b704 NS_GET_PARENT = 0x2000b702 + NS_GET_PID_FROM_PIDNS = 0x4004b706 + NS_GET_PID_IN_PIDNS = 0x4004b708 + NS_GET_TGID_FROM_PIDNS = 0x4004b707 + NS_GET_TGID_IN_PIDNS = 0x4004b709 NS_GET_USERNS = 0x2000b701 OLCUC = 0x2 ONLCR = 0x4 diff --git a/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go index da08b2ab3d9..1ec2b1407b1 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go @@ -581,6 +581,8 @@ const ( AT_EMPTY_PATH = 0x1000 AT_REMOVEDIR = 0x200 RENAME_NOREPLACE = 1 << 0 + ST_RDONLY = 1 + ST_NOSUID = 2 ) const ( diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index b622533ef2c..24b346e1a35 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -841,6 +841,26 @@ var libc_pthread_fchdir_np_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) { + var _p0 unsafe.Pointer + if len(iov) > 0 { + _p0 = unsafe.Pointer(&iov[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := syscall_syscall9(libc_connectx_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(endpoints)), uintptr(associd), uintptr(flags), uintptr(_p0), uintptr(len(iov)), uintptr(unsafe.Pointer(n)), uintptr(unsafe.Pointer(connid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_connectx_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_connectx connectx "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index cfe6646baf2..ebd213100b3 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -248,6 +248,11 @@ TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) +TEXT libc_connectx_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_connectx(SB) +GLOBL ·libc_connectx_trampoline_addr(SB), RODATA, $8 +DATA ·libc_connectx_trampoline_addr(SB)/8, $libc_connectx_trampoline<>(SB) + TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 13f624f69f1..824b9c2d5e0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -841,6 +841,26 @@ var libc_pthread_fchdir_np_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) { + var _p0 unsafe.Pointer + if len(iov) > 0 { + _p0 = unsafe.Pointer(&iov[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := syscall_syscall9(libc_connectx_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(endpoints)), uintptr(associd), uintptr(flags), uintptr(_p0), uintptr(len(iov)), uintptr(unsafe.Pointer(n)), uintptr(unsafe.Pointer(connid)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_connectx_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_connectx connectx "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) { _, _, e1 := syscall_syscall6(libc_sendfile_trampoline_addr, uintptr(infd), uintptr(outfd), uintptr(offset), uintptr(unsafe.Pointer(len)), uintptr(hdtr), uintptr(flags)) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index fe222b75df0..4f178a22934 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -248,6 +248,11 @@ TEXT libc_pthread_fchdir_np_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_pthread_fchdir_np_trampoline_addr(SB), RODATA, $8 DATA ·libc_pthread_fchdir_np_trampoline_addr(SB)/8, $libc_pthread_fchdir_np_trampoline<>(SB) +TEXT libc_connectx_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_connectx(SB) +GLOBL ·libc_connectx_trampoline_addr(SB), RODATA, $8 +DATA ·libc_connectx_trampoline_addr(SB)/8, $libc_connectx_trampoline<>(SB) + TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) GLOBL ·libc_sendfile_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go index 1bc1a5adb25..af30da55780 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -971,23 +971,6 @@ func Getpriority(which int, who int) (prio int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Getrandom(buf []byte, flags int) (n int, err error) { - var _p0 unsafe.Pointer - if len(buf) > 0 { - _p0 = unsafe.Pointer(&buf[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall(SYS_GETRANDOM, uintptr(_p0), uintptr(len(buf)), uintptr(flags)) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getrusage(who int, rusage *Rusage) (err error) { _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index d3e38f681ab..f485dbf4565 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -341,6 +341,7 @@ const ( SYS_STATX = 332 SYS_IO_PGETEVENTS = 333 SYS_RSEQ = 334 + SYS_URETPROBE = 335 SYS_PIDFD_SEND_SIGNAL = 424 SYS_IO_URING_SETUP = 425 SYS_IO_URING_ENTER = 426 diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 6c778c23278..1893e2fe884 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -85,7 +85,7 @@ const ( SYS_SPLICE = 76 SYS_TEE = 77 SYS_READLINKAT = 78 - SYS_FSTATAT = 79 + SYS_NEWFSTATAT = 79 SYS_FSTAT = 80 SYS_SYNC = 81 SYS_FSYNC = 82 diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go index 37281cf51a8..16a4017da0a 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go @@ -84,6 +84,8 @@ const ( SYS_SPLICE = 76 SYS_TEE = 77 SYS_READLINKAT = 78 + SYS_NEWFSTATAT = 79 + SYS_FSTAT = 80 SYS_SYNC = 81 SYS_FSYNC = 82 SYS_FDATASYNC = 83 diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 9889f6a5591..a5459e766f5 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -84,7 +84,7 @@ const ( SYS_SPLICE = 76 SYS_TEE = 77 SYS_READLINKAT = 78 - SYS_FSTATAT = 79 + SYS_NEWFSTATAT = 79 SYS_FSTAT = 80 SYS_SYNC = 81 SYS_FSYNC = 82 diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go index 091d107f3a5..d003c3d4378 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go @@ -306,6 +306,19 @@ type XVSockPgen struct { type _Socklen uint32 +type SaeAssocID uint32 + +type SaeConnID uint32 + +type SaEndpoints struct { + Srcif uint32 + Srcaddr *RawSockaddr + Srcaddrlen uint32 + Dstaddr *RawSockaddr + Dstaddrlen uint32 + _ [4]byte +} + type Xucred struct { Version uint32 Uid uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go index 28ff4ef74d0..0d45a941aae 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go @@ -306,6 +306,19 @@ type XVSockPgen struct { type _Socklen uint32 +type SaeAssocID uint32 + +type SaeConnID uint32 + +type SaEndpoints struct { + Srcif uint32 + Srcaddr *RawSockaddr + Srcaddrlen uint32 + Dstaddr *RawSockaddr + Dstaddrlen uint32 + _ [4]byte +} + type Xucred struct { Version uint32 Uid uint32 diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go index 6cbd094a3aa..51e13eb055f 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go @@ -625,6 +625,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go index 7c03b6ee77f..d002d8ef3cc 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go @@ -630,6 +630,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go index 422107ee8b1..3f863d898dd 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go @@ -616,6 +616,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go index 505a12acfd9..61c72931066 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go @@ -610,6 +610,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go index cc986c79006..b5d17414f03 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go @@ -612,6 +612,7 @@ const ( POLLRDNORM = 0x40 POLLWRBAND = 0x100 POLLWRNORM = 0x4 + POLLRDHUP = 0x4000 ) type CapRights struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index 7f1961b907a..3a69e454962 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -87,31 +87,35 @@ type StatxTimestamp struct { } type Statx_t struct { - Mask uint32 - Blksize uint32 - Attributes uint64 - Nlink uint32 - Uid uint32 - Gid uint32 - Mode uint16 - _ [1]uint16 - Ino uint64 - Size uint64 - Blocks uint64 - Attributes_mask uint64 - Atime StatxTimestamp - Btime StatxTimestamp - Ctime StatxTimestamp - Mtime StatxTimestamp - Rdev_major uint32 - Rdev_minor uint32 - Dev_major uint32 - Dev_minor uint32 - Mnt_id uint64 - Dio_mem_align uint32 - Dio_offset_align uint32 - Subvol uint64 - _ [11]uint64 + Mask uint32 + Blksize uint32 + Attributes uint64 + Nlink uint32 + Uid uint32 + Gid uint32 + Mode uint16 + _ [1]uint16 + Ino uint64 + Size uint64 + Blocks uint64 + Attributes_mask uint64 + Atime StatxTimestamp + Btime StatxTimestamp + Ctime StatxTimestamp + Mtime StatxTimestamp + Rdev_major uint32 + Rdev_minor uint32 + Dev_major uint32 + Dev_minor uint32 + Mnt_id uint64 + Dio_mem_align uint32 + Dio_offset_align uint32 + Subvol uint64 + Atomic_write_unit_min uint32 + Atomic_write_unit_max uint32 + Atomic_write_segments_max uint32 + _ [1]uint32 + _ [9]uint64 } type Fsid struct { @@ -516,6 +520,29 @@ type TCPInfo struct { Total_rto_time uint32 } +type TCPVegasInfo struct { + Enabled uint32 + Rttcnt uint32 + Rtt uint32 + Minrtt uint32 +} + +type TCPDCTCPInfo struct { + Enabled uint16 + Ce_state uint16 + Alpha uint32 + Ab_ecn uint32 + Ab_tot uint32 +} + +type TCPBBRInfo struct { + Bw_lo uint32 + Bw_hi uint32 + Min_rtt uint32 + Pacing_gain uint32 + Cwnd_gain uint32 +} + type CanFilter struct { Id uint32 Mask uint32 @@ -557,6 +584,7 @@ const ( SizeofICMPv6Filter = 0x20 SizeofUcred = 0xc SizeofTCPInfo = 0xf8 + SizeofTCPCCInfo = 0x14 SizeofCanFilter = 0x8 SizeofTCPRepairOpt = 0x8 ) @@ -2486,7 +2514,7 @@ type XDPMmapOffsets struct { type XDPUmemReg struct { Addr uint64 Len uint64 - Chunk_size uint32 + Size uint32 Headroom uint32 Flags uint32 Tx_metadata_len uint32 @@ -3766,7 +3794,7 @@ const ( ETHTOOL_MSG_PSE_GET = 0x24 ETHTOOL_MSG_PSE_SET = 0x25 ETHTOOL_MSG_RSS_GET = 0x26 - ETHTOOL_MSG_USER_MAX = 0x2b + ETHTOOL_MSG_USER_MAX = 0x2c ETHTOOL_MSG_KERNEL_NONE = 0x0 ETHTOOL_MSG_STRSET_GET_REPLY = 0x1 ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2 @@ -3806,7 +3834,7 @@ const ( ETHTOOL_MSG_MODULE_NTF = 0x24 ETHTOOL_MSG_PSE_GET_REPLY = 0x25 ETHTOOL_MSG_RSS_GET_REPLY = 0x26 - ETHTOOL_MSG_KERNEL_MAX = 0x2b + ETHTOOL_MSG_KERNEL_MAX = 0x2c ETHTOOL_FLAG_COMPACT_BITSETS = 0x1 ETHTOOL_FLAG_OMIT_REPLY = 0x2 ETHTOOL_FLAG_STATS = 0x4 @@ -3951,7 +3979,7 @@ const ( ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17 ETHTOOL_A_COALESCE_USE_CQE_MODE_TX = 0x18 ETHTOOL_A_COALESCE_USE_CQE_MODE_RX = 0x19 - ETHTOOL_A_COALESCE_MAX = 0x1c + ETHTOOL_A_COALESCE_MAX = 0x1e ETHTOOL_A_PAUSE_UNSPEC = 0x0 ETHTOOL_A_PAUSE_HEADER = 0x1 ETHTOOL_A_PAUSE_AUTONEG = 0x2 @@ -4609,7 +4637,7 @@ const ( NL80211_ATTR_MAC_HINT = 0xc8 NL80211_ATTR_MAC_MASK = 0xd7 NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca - NL80211_ATTR_MAX = 0x14a + NL80211_ATTR_MAX = 0x14c NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4 NL80211_ATTR_MAX_CSA_COUNTERS = 0xce NL80211_ATTR_MAX_MATCH_SETS = 0x85 @@ -5213,7 +5241,7 @@ const ( NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf - NL80211_FREQUENCY_ATTR_MAX = 0x20 + NL80211_FREQUENCY_ATTR_MAX = 0x21 NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index 15adc04142f..ad05b51a603 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -727,6 +727,37 @@ const ( RISCV_HWPROBE_EXT_ZBA = 0x8 RISCV_HWPROBE_EXT_ZBB = 0x10 RISCV_HWPROBE_EXT_ZBS = 0x20 + RISCV_HWPROBE_EXT_ZICBOZ = 0x40 + RISCV_HWPROBE_EXT_ZBC = 0x80 + RISCV_HWPROBE_EXT_ZBKB = 0x100 + RISCV_HWPROBE_EXT_ZBKC = 0x200 + RISCV_HWPROBE_EXT_ZBKX = 0x400 + RISCV_HWPROBE_EXT_ZKND = 0x800 + RISCV_HWPROBE_EXT_ZKNE = 0x1000 + RISCV_HWPROBE_EXT_ZKNH = 0x2000 + RISCV_HWPROBE_EXT_ZKSED = 0x4000 + RISCV_HWPROBE_EXT_ZKSH = 0x8000 + RISCV_HWPROBE_EXT_ZKT = 0x10000 + RISCV_HWPROBE_EXT_ZVBB = 0x20000 + RISCV_HWPROBE_EXT_ZVBC = 0x40000 + RISCV_HWPROBE_EXT_ZVKB = 0x80000 + RISCV_HWPROBE_EXT_ZVKG = 0x100000 + RISCV_HWPROBE_EXT_ZVKNED = 0x200000 + RISCV_HWPROBE_EXT_ZVKNHA = 0x400000 + RISCV_HWPROBE_EXT_ZVKNHB = 0x800000 + RISCV_HWPROBE_EXT_ZVKSED = 0x1000000 + RISCV_HWPROBE_EXT_ZVKSH = 0x2000000 + RISCV_HWPROBE_EXT_ZVKT = 0x4000000 + RISCV_HWPROBE_EXT_ZFH = 0x8000000 + RISCV_HWPROBE_EXT_ZFHMIN = 0x10000000 + RISCV_HWPROBE_EXT_ZIHINTNTL = 0x20000000 + RISCV_HWPROBE_EXT_ZVFH = 0x40000000 + RISCV_HWPROBE_EXT_ZVFHMIN = 0x80000000 + RISCV_HWPROBE_EXT_ZFA = 0x100000000 + RISCV_HWPROBE_EXT_ZTSO = 0x200000000 + RISCV_HWPROBE_EXT_ZACAS = 0x400000000 + RISCV_HWPROBE_EXT_ZICOND = 0x800000000 + RISCV_HWPROBE_EXT_ZIHINTPAUSE = 0x1000000000 RISCV_HWPROBE_KEY_CPUPERF_0 = 0x5 RISCV_HWPROBE_MISALIGNED_UNKNOWN = 0x0 RISCV_HWPROBE_MISALIGNED_EMULATED = 0x1 @@ -734,4 +765,6 @@ const ( RISCV_HWPROBE_MISALIGNED_FAST = 0x3 RISCV_HWPROBE_MISALIGNED_UNSUPPORTED = 0x4 RISCV_HWPROBE_MISALIGNED_MASK = 0x7 + RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE = 0x6 + RISCV_HWPROBE_WHICH_CPUS = 0x1 ) diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go index 115341fba66..4e613cf6335 100644 --- a/vendor/golang.org/x/sys/windows/dll_windows.go +++ b/vendor/golang.org/x/sys/windows/dll_windows.go @@ -65,7 +65,7 @@ func LoadDLL(name string) (dll *DLL, err error) { return d, nil } -// MustLoadDLL is like LoadDLL but panics if load operation failes. +// MustLoadDLL is like LoadDLL but panics if load operation fails. func MustLoadDLL(name string) *DLL { d, e := LoadDLL(name) if e != nil { diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 1fa34fd17c5..5cee9a3143f 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -313,6 +313,10 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetConsoleMode(console Handle, mode uint32) (err error) = kernel32.SetConsoleMode //sys GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) = kernel32.GetConsoleScreenBufferInfo //sys setConsoleCursorPosition(console Handle, position uint32) (err error) = kernel32.SetConsoleCursorPosition +//sys GetConsoleCP() (cp uint32, err error) = kernel32.GetConsoleCP +//sys GetConsoleOutputCP() (cp uint32, err error) = kernel32.GetConsoleOutputCP +//sys SetConsoleCP(cp uint32) (err error) = kernel32.SetConsoleCP +//sys SetConsoleOutputCP(cp uint32) (err error) = kernel32.SetConsoleOutputCP //sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW //sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW //sys resizePseudoConsole(pconsole Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index 3f03b3d57cc..7b97a154c95 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -1060,6 +1060,7 @@ const ( SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6 SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4 SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 + SIO_UDP_NETRESET = IOC_IN | IOC_VENDOR | 15 // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460 diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 9bb979a3e47..4c2e1bdc01e 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -247,7 +247,9 @@ var ( procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") procGetComputerNameW = modkernel32.NewProc("GetComputerNameW") + procGetConsoleCP = modkernel32.NewProc("GetConsoleCP") procGetConsoleMode = modkernel32.NewProc("GetConsoleMode") + procGetConsoleOutputCP = modkernel32.NewProc("GetConsoleOutputCP") procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo") procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW") procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId") @@ -347,8 +349,10 @@ var ( procSetCommMask = modkernel32.NewProc("SetCommMask") procSetCommState = modkernel32.NewProc("SetCommState") procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") + procSetConsoleCP = modkernel32.NewProc("SetConsoleCP") procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition") procSetConsoleMode = modkernel32.NewProc("SetConsoleMode") + procSetConsoleOutputCP = modkernel32.NewProc("SetConsoleOutputCP") procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW") procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") @@ -2162,6 +2166,15 @@ func GetComputerName(buf *uint16, n *uint32) (err error) { return } +func GetConsoleCP() (cp uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0) + cp = uint32(r0) + if cp == 0 { + err = errnoErr(e1) + } + return +} + func GetConsoleMode(console Handle, mode *uint32) (err error) { r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0) if r1 == 0 { @@ -2170,6 +2183,15 @@ func GetConsoleMode(console Handle, mode *uint32) (err error) { return } +func GetConsoleOutputCP() (cp uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetConsoleOutputCP.Addr(), 0, 0, 0, 0) + cp = uint32(r0) + if cp == 0 { + err = errnoErr(e1) + } + return +} + func GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) { r1, _, e1 := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(info)), 0) if r1 == 0 { @@ -3038,6 +3060,14 @@ func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { return } +func SetConsoleCP(cp uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetConsoleCP.Addr(), 1, uintptr(cp), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func setConsoleCursorPosition(console Handle, position uint32) (err error) { r1, _, e1 := syscall.Syscall(procSetConsoleCursorPosition.Addr(), 2, uintptr(console), uintptr(position), 0) if r1 == 0 { @@ -3054,6 +3084,14 @@ func SetConsoleMode(console Handle, mode uint32) (err error) { return } +func SetConsoleOutputCP(cp uint32) (err error) { + r1, _, e1 := syscall.Syscall(procSetConsoleOutputCP.Addr(), 1, uintptr(cp), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func SetCurrentDirectory(path *uint16) (err error) { r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) if r1 == 0 { diff --git a/vendor/modules.txt b/vendor/modules.txt index ed651774780..88d63136509 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -357,7 +357,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/storage v1.55.1-0.20241204053541-a868bc017192 +# github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622 ## explicit; go 1.21 github.com/containers/storage github.com/containers/storage/drivers @@ -413,7 +413,7 @@ github.com/coreos/go-systemd/v22/dbus ## explicit; go 1.12 github.com/cpuguy83/go-md2man github.com/cpuguy83/go-md2man/md2man -# github.com/cpuguy83/go-md2man/v2 v2.0.4 +# github.com/cpuguy83/go-md2man/v2 v2.0.5 ## explicit; go 1.11 github.com/cpuguy83/go-md2man/v2/md2man # github.com/creack/pty v1.1.23 @@ -990,7 +990,7 @@ github.com/uptrace/opentelemetry-go-extra/otelutil # github.com/urfave/cli/v2 v2.27.4 ## explicit; go 1.18 github.com/urfave/cli/v2 -# github.com/vbatts/tar-split v0.11.5 +# github.com/vbatts/tar-split v0.11.7 ## explicit; go 1.17 github.com/vbatts/tar-split/archive/tar github.com/vbatts/tar-split/tar/asm @@ -1160,7 +1160,7 @@ golang.org/x/oauth2/internal ## explicit; go 1.18 golang.org/x/sync/errgroup golang.org/x/sync/semaphore -# golang.org/x/sys v0.24.0 +# golang.org/x/sys v0.26.0 ## explicit; go 1.18 golang.org/x/sys/cpu golang.org/x/sys/execabs From 811fc3502c0be2e20ad5f196b36f7ada9333dc09 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Sat, 1 Feb 2025 00:25:27 +0000 Subject: [PATCH 28/47] version: bump to 1.31.5 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index f883857ed5b..4b41862320d 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.4" +const Version = "1.31.5" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From f3cc44f2ad121973b1b6975376a918722c935ac8 Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Fri, 31 Jan 2025 09:47:37 -0500 Subject: [PATCH 29/47] internal/linklogs: sanitize the directory path before using it Signed-off-by: Sohan Kunkerkar --- internal/linklogs/link_logs.go | 47 ++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/internal/linklogs/link_logs.go b/internal/linklogs/link_logs.go index dabf6cefaa9..e72879047de 100644 --- a/internal/linklogs/link_logs.go +++ b/internal/linklogs/link_logs.go @@ -5,8 +5,9 @@ import ( "errors" "fmt" "os" - "path/filepath" + "strings" + securejoin "github.com/cyphar/filepath-securejoin" "github.com/opencontainers/selinux/go-selinux/label" "golang.org/x/sys/unix" "k8s.io/apimachinery/pkg/util/validation" @@ -29,12 +30,22 @@ func MountPodLogs(ctx context.Context, kubePodUID, emptyDirVolName, namespace, k if errs := validation.IsDNS1123Label(emptyDirVolName); len(errs) != 0 { return errors.New("empty dir vol name is invalid") } - emptyDirLoggingVolumePath := podEmptyDirPath(kubePodUID, emptyDirVolName) + + emptyDirLoggingVolumePath, err := podEmptyDirPath(kubePodUID, emptyDirVolName) + if err != nil { + return fmt.Errorf("failed to get empty dir path: %w", err) + } + if _, err := os.Stat(emptyDirLoggingVolumePath); err != nil { return fmt.Errorf("failed to find %v: %w", emptyDirLoggingVolumePath, err) } podLogsDirectory := namespace + "_" + kubeName + "_" + kubePodUID - podLogsPath := filepath.Join(kubeletPodLogsRootDir, podLogsDirectory) + + podLogsPath, err := securejoin.SecureJoin(kubeletPodLogsRootDir, podLogsDirectory) + if err != nil { + return fmt.Errorf("failed to join %v and %v: %w", kubeletPodLogsRootDir, podLogsDirectory, err) + } + log.Infof(ctx, "Mounting from %s to %s for linked logs", podLogsPath, emptyDirLoggingVolumePath) if err := unix.Mount(podLogsPath, emptyDirLoggingVolumePath, "bind", unix.MS_BIND|unix.MS_RDONLY, ""); err != nil { return fmt.Errorf("failed to mount %v to %v: %w", podLogsPath, emptyDirLoggingVolumePath, err) @@ -47,7 +58,11 @@ func MountPodLogs(ctx context.Context, kubePodUID, emptyDirVolName, namespace, k // UnmountPodLogs unmounts the pod log directory from the specified empty dir volume. func UnmountPodLogs(ctx context.Context, kubePodUID, emptyDirVolName string) error { - emptyDirLoggingVolumePath := podEmptyDirPath(kubePodUID, emptyDirVolName) + emptyDirLoggingVolumePath, err := podEmptyDirPath(kubePodUID, emptyDirVolName) + if err != nil { + return fmt.Errorf("failed to get empty dir path: %w", err) + } + log.Infof(ctx, "Unmounting %s for linked logs", emptyDirLoggingVolumePath) if _, err := os.Stat(emptyDirLoggingVolumePath); !os.IsNotExist(err) { if err := unix.Unmount(emptyDirLoggingVolumePath, unix.MNT_DETACH); err != nil { @@ -58,14 +73,30 @@ func UnmountPodLogs(ctx context.Context, kubePodUID, emptyDirVolName string) err } func LinkContainerLogs(ctx context.Context, kubePodUID, emptyDirVolName, id string, metadata *types.ContainerMetadata) error { - emptyDirLoggingVolumePath := podEmptyDirPath(kubePodUID, emptyDirVolName) + emptyDirLoggingVolumePath, err := podEmptyDirPath(kubePodUID, emptyDirVolName) + if err != nil { + return fmt.Errorf("failed to get empty dir path: %w", err) + } + // Symlink a relative path so the location is legitimate inside and outside the container. from := fmt.Sprintf("%s/%d.log", metadata.Name, metadata.Attempt) - to := filepath.Join(emptyDirLoggingVolumePath, id+".log") + + to, err := securejoin.SecureJoin(emptyDirLoggingVolumePath, id+".log") + if err != nil { + return fmt.Errorf("failed to join %v and %v: %w", emptyDirLoggingVolumePath, id+".log", err) + } + log.Infof(ctx, "Symlinking from %s to %s for linked logs", from, to) return os.Symlink(from, to) } -func podEmptyDirPath(podUID, emptyDirVolName string) string { - return filepath.Join(kubeletPodsRootDir, podUID, "volumes", kubeletEmptyDirLogDir, emptyDirVolName) +func podEmptyDirPath(podUID, emptyDirVolName string) (string, error) { + relativePath := strings.Join([]string{podUID, "volumes", kubeletEmptyDirLogDir, emptyDirVolName}, "/") + + dirPath, err := securejoin.SecureJoin(kubeletPodsRootDir, relativePath) + if err != nil { + return "", fmt.Errorf("failed to join %v and %v: %w", kubeletPodsRootDir, relativePath, err) + } + + return dirPath, err } From 6ae8478bb99f8ea067aa9a2182960bb2153da59b Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Fri, 31 Jan 2025 09:49:38 -0500 Subject: [PATCH 30/47] test: add test coverage for LinkLogs malicious paths Signed-off-by: Sohan Kunkerkar --- test/ctr.bats | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/test/ctr.bats b/test/ctr.bats index 7f341ccd3e7..9560054e060 100644 --- a/test/ctr.bats +++ b/test/ctr.bats @@ -62,6 +62,54 @@ function create_test_rro_mounts() { echo "$directory" } +function setup_log_linking_test() { + local pod_uid=$1 + local pod_name pod_namespace pod_log_dir pod_empty_dir_volume_path pod_id ctr_name ctr_attempt ctr_id + + pod_name=$(jq -r '.metadata.name' "$TESTDATA/sandbox_config.json") + pod_namespace=$(jq -r '.metadata.namespace' "$TESTDATA/sandbox_config.json") + pod_log_dir="/var/log/pods/${pod_namespace}_${pod_name}_${pod_uid}" + pod_empty_dir_volume_path="/var/lib/kubelet/pods/$pod_uid/volumes/kubernetes.io~empty-dir/logging-volume" + + # Create directories and set up pod/container. + mkdir -p "$pod_log_dir" "$pod_empty_dir_volume_path" + jq --arg pod_log_dir "$pod_log_dir" --arg pod_uid "$pod_uid" '.annotations["io.kubernetes.cri-o.LinkLogs"] = "logging-volume" + | .log_directory = $pod_log_dir | .metadata.uid = $pod_uid' \ + "$TESTDATA/sandbox_config.json" > "$TESTDIR/sandbox_config.json" + pod_id=$(crictl runp "$TESTDIR/sandbox_config.json") + + # Touch the log file. + ctr_name=$(jq -r '.metadata.name' "$TESTDATA/container_config.json") + ctr_attempt=$(jq -r '.metadata.attempt' "$TESTDATA/container_config.json") + mkdir -p "$pod_log_dir/$ctr_name" + touch "$pod_log_dir/$ctr_name/$ctr_attempt.log" + + jq --arg host_path "$pod_empty_dir_volume_path" --arg ctr_path "/mnt/logging-volume" --arg log_path "$ctr_name/$ctr_attempt.log" \ + '.command = ["sh", "-c", "echo Hello log linking && sleep 1000"] + | .log_path = $log_path + | .mounts = [ { host_path: $host_path, container_path: $ctr_path } ]' \ + "$TESTDATA"/container_config.json > "$TESTDIR/container_config.json" + ctr_id=$(crictl create "$pod_id" "$TESTDIR/container_config.json" "$TESTDIR/sandbox_config.json") +} + +function assert_log_linking() { + local pod_empty_dir_volume_path=$1 + local ctr_name=$2 + local ctr_attempt=$3 + local ctr_id=$4 + local should_succeed=$5 + + if $should_succeed; then + [ -f "$pod_empty_dir_volume_path/$ctr_name/$ctr_attempt.log" ] + [ -f "$pod_empty_dir_volume_path/$ctr_id.log" ] + grep -E "Hello log linking" "$pod_empty_dir_volume_path/$ctr_name/$ctr_attempt.log" + grep -E "Hello log linking" "$pod_empty_dir_volume_path/$ctr_id.log" + else + [ ! -f "$pod_empty_dir_volume_path/$ctr_name/$ctr_attempt.log" ] + [ ! -f "$pod_empty_dir_volume_path/$ctr_id.log" ] + fi +} + @test "ctr not found correct error message" { start_crio run ! crictl inspect "container_not_exist" @@ -1392,6 +1440,32 @@ function create_test_rro_mounts() { [ ! -f "$linked_log_path" ] } +@test "ctr log linking with malicious paths" { + if [[ $RUNTIME_TYPE == vm ]]; then + skip "not applicable to vm runtime type" + fi + setup_crio + create_runtime_with_allowed_annotation logs io.kubernetes.cri-o.LinkLogs + start_crio_no_setup + + read -r pod_empty_dir_volume_path ctr_name ctr_attempt ctr_id <<< "$(setup_log_linking_test "../../../malicious")" + assert_log_linking "$pod_empty_dir_volume_path" "$ctr_name" "$ctr_attempt" "$ctr_id" false + crictl rmp -fa +} + +@test "ctr log linking with invalid paths" { + if [[ $RUNTIME_TYPE == vm ]]; then + skip "not applicable to vm runtime type" + fi + setup_crio + create_runtime_with_allowed_annotation logs io.kubernetes.cri-o.LinkLogs + start_crio_no_setup + + read -r pod_empty_dir_volume_path ctr_name ctr_attempt ctr_id <<< "$(setup_log_linking_test "invalid path")" + assert_log_linking "$pod_empty_dir_volume_path" "$ctr_name" "$ctr_attempt" "$ctr_id" false + crictl rmp -fa +} + @test "ctr stop loop kill retry attempts" { FAKE_RUNTIME_BINARY_PATH="$TESTDIR"/fake FAKE_RUNTIME_ATTEMPTS_LOG="$TESTDIR"/fake.log From 98efdfcb4091ed98d38ffb658ece3f7636e3335f Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Fri, 7 Feb 2025 16:20:15 -0500 Subject: [PATCH 31/47] test: fix unit test for IsContainerAlive Signed-off-by: Sohan Kunkerkar --- test/mocks/oci/oci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mocks/oci/oci.go b/test/mocks/oci/oci.go index fc26b762599..90ab4c8bf14 100644 --- a/test/mocks/oci/oci.go +++ b/test/mocks/oci/oci.go @@ -150,7 +150,7 @@ func (m *MockRuntimeImpl) IsContainerAlive(arg0 *oci.Container) bool { } // IsContainerAlive indicates an expected call of IsContainerAlive. -func (mr *MockRuntimeImplMockRecorder) IsContainerAlive(arg0 any) *gomock.Call { +func (mr *MockRuntimeImplMockRecorder) IsContainerAlive(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsContainerAlive", reflect.TypeOf((*MockRuntimeImpl)(nil).IsContainerAlive), arg0) } From ac198612b5019a86ad7e696615ff855ac9cd1aa6 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Wed, 12 Feb 2025 14:26:58 +0100 Subject: [PATCH 32/47] Fix context cancellation when image pull progress timeout is `0` We should never cancel the context when the pull timeout is `0`, means we now add an additional check to prevent this corner case. Deflakes the integration tests and also fixes possible issues around a disabled pull progress timeout. Signed-off-by: Sascha Grunert --- server/image_pull.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/image_pull.go b/server/image_pull.go index 0f65de89718..b406273d9bd 100644 --- a/server/image_pull.go +++ b/server/image_pull.go @@ -255,8 +255,10 @@ func (s *Server) pullImageCandidate(ctx context.Context, sourceCtx *imageTypes.S // the cancel function will be called. func consumeImagePullProgress(ctx context.Context, cancel context.CancelFunc, pullProgressTimeout time.Duration, progress <-chan imageTypes.ProgressProperties, remoteCandidateName storage.RegistryImageReference) { timer := time.AfterFunc(pullProgressTimeout, func() { - log.Warnf(ctx, "Timed out on waiting up to %s for image pull progress updates", pullProgressTimeout) - cancel() + if pullProgressTimeout != 0 { + log.Warnf(ctx, "Timed out on waiting up to %s for image pull progress updates", pullProgressTimeout) + cancel() + } }) timer.Stop() // don't start the timer immediately defer timer.Stop() // ensure that the timer is stopped when we exit the progress loop From ad1ac604e3b2e57551fc58d9b9850f0ba5bfb552 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Sat, 1 Mar 2025 00:26:54 +0000 Subject: [PATCH 33/47] version: bump to 1.31.6 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 4b41862320d..1758f1e4030 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.5" +const Version = "1.31.6" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From 4b2bcca41f78a7fc51c837e6a7a73497302c83ac Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Fri, 21 Mar 2025 08:50:43 +0100 Subject: [PATCH 34/47] [release-1.31] Update c/image to latest crio-1.31 commit Signed-off-by: Sascha Grunert --- go.mod | 2 +- go.sum | 4 ++-- vendor/github.com/containers/image/v5/storage/storage_dest.go | 2 +- vendor/modules.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index cbf939a0cae..77ad7c75516 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/containers/common v0.60.3-0.20241001153533-18930ed8933b github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon-rs v0.6.5 - github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9 + github.com/containers/image/v5 v5.32.3-0.20250321090242-db55860a7cf9 github.com/containers/kubensmnt v1.2.0 github.com/containers/ocicrypt v1.2.0 github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622 diff --git a/go.sum b/go.sum index 74276cb1a6b..59b7de14625 100644 --- a/go.sum +++ b/go.sum @@ -732,8 +732,8 @@ github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6J github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/conmon-rs v0.6.5 h1:mxdEBF/pjBmryj1ABrTDUqxDyxoZrpo8A1/9+JNvtZU= github.com/containers/conmon-rs v0.6.5/go.mod h1:+1QRvqdKmaFgaKL7IfsnXncePoH4K+5qkyBIAl/m9Zs= -github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9 h1:RqjeydhQ73aFkYASllZ2/cAHYvmLHrLbxh5hnWVvoa8= -github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9/go.mod h1:v1l73VeMugfj/QtKI+jhYbwnwFCFnNGckvbST3rQ5Hk= +github.com/containers/image/v5 v5.32.3-0.20250321090242-db55860a7cf9 h1:bFVDgCjoYm+Fr6DkQDjjqBTkA3Cgwjrr7Z2+uULJTPc= +github.com/containers/image/v5 v5.32.3-0.20250321090242-db55860a7cf9/go.mod h1:v1l73VeMugfj/QtKI+jhYbwnwFCFnNGckvbST3rQ5Hk= github.com/containers/kubensmnt v1.2.0 h1:BDtkaOFQ5fN7FnB9kC6peMW50KkwI1KI8E9ROBFeQIg= github.com/containers/kubensmnt v1.2.0/go.mod h1:1/HG09N/a1+WSD3zkurzeWtqlKRSfUUnlIF/08zloqk= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= diff --git a/vendor/github.com/containers/image/v5/storage/storage_dest.go b/vendor/github.com/containers/image/v5/storage/storage_dest.go index b86a568b5fa..225a397f509 100644 --- a/vendor/github.com/containers/image/v5/storage/storage_dest.go +++ b/vendor/github.com/containers/image/v5/storage/storage_dest.go @@ -515,7 +515,7 @@ func (s *storageImageDestination) tryReusingBlobAsPending(blobDigest digest.Dige return false, private.ReusedBlob{}, fmt.Errorf(`looking for layers with digest %q: %w`, uncompressedDigest, err) } if found, reused := reusedBlobFromLayerLookup(layers, blobDigest, size, options); found { - s.lockProtected.blobDiffIDs[blobDigest] = uncompressedDigest + s.lockProtected.blobDiffIDs[reused.Digest] = uncompressedDigest return true, reused, nil } } diff --git a/vendor/modules.txt b/vendor/modules.txt index d0531752f86..cb8ad091bdc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -268,7 +268,7 @@ github.com/containers/conmon/runner/config ## explicit; go 1.22 github.com/containers/conmon-rs/internal/proto github.com/containers/conmon-rs/pkg/client -# github.com/containers/image/v5 v5.32.3-0.20241128085047-0c20855557c9 +# github.com/containers/image/v5 v5.32.3-0.20250321090242-db55860a7cf9 ## explicit; go 1.21.0 github.com/containers/image/v5/copy github.com/containers/image/v5/directory From a3ae444035ec7f7f93aed84334f62de917bdcf00 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Sat, 29 Mar 2025 00:54:31 -0400 Subject: [PATCH 35/47] [release-1.31] Update c/storage update from c/storage crio-1.31 branch to fetch the PR https://github.com/containers/storage/pull/2129. Signed-off-by: Qi Wang --- go.mod | 2 +- go.sum | 4 +- .../drivers/quota/projectquota_supported.go | 48 +++++++++++++++++++ vendor/modules.txt | 2 +- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 77ad7c75516..8e3808c3089 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/containers/image/v5 v5.32.3-0.20250321090242-db55860a7cf9 github.com/containers/kubensmnt v1.2.0 github.com/containers/ocicrypt v1.2.0 - github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622 + github.com/containers/storage v1.55.1-0.20250328180621-028e88d2378c github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 github.com/cpuguy83/go-md2man v1.0.10 github.com/creack/pty v1.1.23 diff --git a/go.sum b/go.sum index 59b7de14625..f97cc81fdc3 100644 --- a/go.sum +++ b/go.sum @@ -740,8 +740,8 @@ github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYgle github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= -github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622 h1:l9Ac/lg0yGbpPQMcF2h0GcPvinjoGvCwpWIFoHkmlDs= -github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622/go.mod h1:YMWW2yZKeL1xcK8zM8ioGKILPwVIJsIGpXC4x8DBqpo= +github.com/containers/storage v1.55.1-0.20250328180621-028e88d2378c h1:1P3a43hPMaxIOkbhJKIPAg38mJjJ6iLah1Od5RL0Xhc= +github.com/containers/storage v1.55.1-0.20250328180621-028e88d2378c/go.mod h1:YMWW2yZKeL1xcK8zM8ioGKILPwVIJsIGpXC4x8DBqpo= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 h1:OoRAFlvDGCUqDLampLQjk0yeeSGdF9zzst/3G9IkBbc= github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09/go.mod h1:m2r/smMKsKwgMSAoFKHaa68ImdCSNuKE1MxvQ64xuCQ= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= diff --git a/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go b/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go index 92e4001d766..2fab7e75bb3 100644 --- a/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go +++ b/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go @@ -19,6 +19,16 @@ package quota #include #include +#ifndef FS_XFLAG_PROJINHERIT +struct fsxattr { + __u32 fsx_xflags; + __u32 fsx_extsize; + __u32 fsx_nextents; + __u32 fsx_projid; + unsigned char fsx_pad[12]; +}; +#define FS_XFLAG_PROJINHERIT 0x00000200 +#endif #ifndef FS_IOC_FSGETXATTR #define FS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) #endif @@ -163,6 +173,11 @@ func NewControl(basePath string) (*Control, error) { return nil, err } + // Clear inherit flag from top-level directory if necessary. + if err := stripProjectInherit(basePath); err != nil { + return nil, err + } + // // get first project id to be used for next container // @@ -340,6 +355,8 @@ func setProjectID(targetPath string, projectID uint32) error { } defer closeDir(dir) + logrus.Debugf("Setting quota project ID %d on %s", projectID, targetPath) + var fsx C.struct_fsxattr _, _, errno := unix.Syscall(unix.SYS_IOCTL, getDirFd(dir), C.FS_IOC_FSGETXATTR, uintptr(unsafe.Pointer(&fsx))) @@ -347,6 +364,7 @@ func setProjectID(targetPath string, projectID uint32) error { return fmt.Errorf("failed to get projid for %s: %w", targetPath, errno) } fsx.fsx_projid = C.__u32(projectID) + fsx.fsx_xflags |= C.FS_XFLAG_PROJINHERIT _, _, errno = unix.Syscall(unix.SYS_IOCTL, getDirFd(dir), C.FS_IOC_FSSETXATTR, uintptr(unsafe.Pointer(&fsx))) if errno != 0 { @@ -356,6 +374,36 @@ func setProjectID(targetPath string, projectID uint32) error { return nil } +// stripProjectInherit strips the project inherit flag from a directory. +// Used on the top-level directory to ensure project IDs are only inherited for +// files in directories we set quotas on - not the directories we want to set +// the quotas on, as that would make everything use the same project ID. +func stripProjectInherit(targetPath string) error { + dir, err := openDir(targetPath) + if err != nil { + return err + } + defer closeDir(dir) + + var fsx C.struct_fsxattr + _, _, errno := unix.Syscall(unix.SYS_IOCTL, getDirFd(dir), C.FS_IOC_FSGETXATTR, + uintptr(unsafe.Pointer(&fsx))) + if errno != 0 { + return fmt.Errorf("failed to get xfs attrs for %s: %w", targetPath, errno) + } + if fsx.fsx_xflags&C.FS_XFLAG_PROJINHERIT != 0 { + // Flag is set, need to clear it. + logrus.Debugf("Clearing PROJINHERIT flag from directory %s", targetPath) + fsx.fsx_xflags = fsx.fsx_xflags &^ C.FS_XFLAG_PROJINHERIT + _, _, errno = unix.Syscall(unix.SYS_IOCTL, getDirFd(dir), C.FS_IOC_FSSETXATTR, + uintptr(unsafe.Pointer(&fsx))) + if errno != 0 { + return fmt.Errorf("failed to clear PROJINHERIT for %s: %w", targetPath, errno) + } + } + return nil +} + // findNextProjectID - find the next project id to be used for containers // by scanning driver home directory to find used project ids func (q *Control) findNextProjectID() error { diff --git a/vendor/modules.txt b/vendor/modules.txt index cb8ad091bdc..c1d443770e2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -357,7 +357,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/storage v1.55.1-0.20250123153357-a030a4472622 +# github.com/containers/storage v1.55.1-0.20250328180621-028e88d2378c ## explicit; go 1.21 github.com/containers/storage github.com/containers/storage/drivers From 7eb9f8bbb6cadb954903b990a0c7dfb675df2eba Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Tue, 1 Apr 2025 00:29:30 +0000 Subject: [PATCH 36/47] version: bump to 1.31.7 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 1758f1e4030..1f9c4459fa8 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.6" +const Version = "1.31.7" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From b695c554be5b7a0d2fcab6cfde0d1d6b98edc617 Mon Sep 17 00:00:00 2001 From: Pannaga Rao Bhoja Ramamanohara Date: Wed, 12 Mar 2025 15:39:28 -0400 Subject: [PATCH 37/47] crio wipe should remove storage only once per reboot Signed-off-by: Pannaga Rao Bhoja Ramamanohara --- internal/criocli/wipe.go | 17 ++++++++++++++++- test/crio-wipe.bats | 30 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/internal/criocli/wipe.go b/internal/criocli/wipe.go index cbccfba11e2..ffa5c06fd46 100644 --- a/internal/criocli/wipe.go +++ b/internal/criocli/wipe.go @@ -2,6 +2,7 @@ package criocli import ( "errors" + "fmt" "os" cstorage "github.com/containers/storage" @@ -69,8 +70,22 @@ func crioWipe(c *cli.Context) error { config.CleanShutdownFile, store.GraphRoot(), ) + + wipeMarkerFile := "/run/crio/crio-wipe-done" + if _, err := os.Stat(wipeMarkerFile); err == nil { + logrus.Infof("Unclean shutdown check already succeeded by previous crio wipe command") + + return nil + } + // This will fail if there are any containers currently running. - return lib.RemoveStorageDirectory(config, store, false) + if err := lib.RemoveStorageDirectory(config, store, false); err != nil { + return fmt.Errorf("failed to remove storage directory %w", err) + } + + if err = os.WriteFile(wipeMarkerFile, []byte("done"), 0o644); err != nil { + logrus.Warnf("Failed to create crio wipe marker file: %v", err) + } } // If crio is configured to wipe internally (and `--force` wasn't set) diff --git a/test/crio-wipe.bats b/test/crio-wipe.bats index 089b70a9526..b50b741aa2a 100644 --- a/test/crio-wipe.bats +++ b/test/crio-wipe.bats @@ -85,6 +85,7 @@ function start_crio_with_stopped_pod() { rm "$CONTAINER_VERSION_FILE" rm "$CONTAINER_VERSION_FILE_PERSIST" + rm -f "/run/crio/crio-wipe-done" run_crio_wipe CONTAINER_INTERNAL_WIPE=false start_crio_no_setup @@ -97,6 +98,7 @@ function start_crio_with_stopped_pod() { stop_crio_no_clean rm "$CONTAINER_VERSION_FILE" + rm -f "/run/crio/crio-wipe-done" run_crio_wipe CONTAINER_INTERNAL_WIPE=false start_crio_no_setup @@ -109,6 +111,7 @@ function start_crio_with_stopped_pod() { stop_crio_no_clean rm "$CONTAINER_VERSION_FILE_PERSIST" + rm -f "/run/crio/crio-wipe-done" run_crio_wipe CONTAINER_INTERNAL_WIPE=false start_crio_no_setup @@ -123,6 +126,7 @@ function start_crio_with_stopped_pod() { CONTAINER_INTERNAL_WIPE=false start_crio_with_stopped_pod stop_crio_no_clean + rm -f "/run/crio/crio-wipe-done" run_podman_with_args run --name test -d quay.io/crio/fedora-crio-ci:latest top @@ -137,6 +141,7 @@ function start_crio_with_stopped_pod() { rm "$CONTAINER_CLEAN_SHUTDOWN_FILE" rm "$CONTAINER_VERSION_FILE" + rm -f "/run/crio/crio-wipe-done" run_crio_wipe @@ -160,6 +165,7 @@ function start_crio_with_stopped_pod() { rm "$CONTAINER_CLEAN_SHUTDOWN_FILE" rm "$CONTAINER_VERSION_FILE" + rm -f "/run/crio/crio-wipe-done" run_crio_wipe @@ -179,6 +185,7 @@ function start_crio_with_stopped_pod() { rm "$CONTAINER_CLEAN_SHUTDOWN_FILE" rm "$CONTAINER_VERSION_FILE" + rm -f "/run/crio/crio-wipe-done" run ! "$CRIO_BINARY_PATH" --config "$CRIO_CONFIG" -d "$CRIO_CONFIG_DIR" wipe } @@ -187,6 +194,7 @@ function start_crio_with_stopped_pod() { CONTAINER_INTERNAL_WIPE=false start_crio_with_stopped_pod stop_crio_no_clean "-9" || true + rm -f "/run/crio/crio-wipe-done" run_crio_wipe CONTAINER_INTERNAL_WIPE=false start_crio_no_setup @@ -201,6 +209,7 @@ function start_crio_with_stopped_pod() { rm "$CONTAINER_CLEAN_SHUTDOWN_FILE.supported" + rm -f "/run/crio/crio-wipe-done" run_crio_wipe CONTAINER_INTERNAL_WIPE=false start_crio_no_setup @@ -376,3 +385,24 @@ function start_crio_with_stopped_pod() { return 1 fi } + +@test "crio-wipe should create /run/crio/crio-wipe-done and not wipe again" { + CONTAINER_INTERNAL_WIPE=false start_crio_with_stopped_pod + stop_crio_no_clean + + rm "$CONTAINER_CLEAN_SHUTDOWN_FILE" + rm "$CONTAINER_VERSION_FILE" + rm -f "/run/crio/crio-wipe-done" + + run_crio_wipe + + ls -l /run/crio/crio-wipe-done + + run cat /run/crio/crio-wipe-done + [[ "$output" == "done" ]] + + run_crio_wipe + [[ ! "$output" == *"Wiping storage directory"* ]] + + ls -l /run/crio/crio-wipe-done +} From 9214db184b2ff61c60a16b78e2f369c501490c79 Mon Sep 17 00:00:00 2001 From: Pannaga Rao Bhoja Ramamanohara Date: Thu, 17 Apr 2025 09:44:38 -0400 Subject: [PATCH 38/47] Update internal/criocli/wipe.go Co-authored-by: Sascha Grunert Signed-off-by: Pannaga Rao Bhoja Ramamanohara --- internal/criocli/wipe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/criocli/wipe.go b/internal/criocli/wipe.go index ffa5c06fd46..3efa33f3ebc 100644 --- a/internal/criocli/wipe.go +++ b/internal/criocli/wipe.go @@ -71,7 +71,7 @@ func crioWipe(c *cli.Context) error { store.GraphRoot(), ) - wipeMarkerFile := "/run/crio/crio-wipe-done" + const wipeMarkerFile = "/run/crio/crio-wipe-done" if _, err := os.Stat(wipeMarkerFile); err == nil { logrus.Infof("Unclean shutdown check already succeeded by previous crio wipe command") From 4ee63aa0f5188ccaed732de5184f8cac9aa519dc Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Mon, 14 Apr 2025 09:35:32 +0200 Subject: [PATCH 39/47] Disable pull-progress-timeout per default Follow-up on https://github.com/cri-o/cri-o/pull/9108 and multiple requests to disable the timeout per default. Cherry-picked: 44d9073dd1133856ffd0858b5d550ce7427335d6 Signed-off-by: Sascha Grunert --- docs/crio.8.md | 2 +- docs/crio.conf.5.md | 2 +- pkg/config/config.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/crio.8.md b/docs/crio.8.md index 7c2bf007ec5..ee972dcb36d 100644 --- a/docs/crio.8.md +++ b/docs/crio.8.md @@ -383,7 +383,7 @@ crio [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] **--profile-port**="": Port for the pprof profiler. (default: 6060) -**--pull-progress-timeout**="": The timeout for an image pull to make progress until the pull operation gets canceled. This value will be also used for calculating the pull progress interval to --pull-progress-timeout / 10. Can be set to 0 to disable the timeout as well as the progress output. (default: 10s) +**--pull-progress-timeout**="": The timeout for an image pull to make progress until the pull operation gets canceled. This value will be also used for calculating the pull progress interval to --pull-progress-timeout / 10. Can be set to 0 to disable the timeout as well as the progress output. (default: 0s) **--rdt-config-file**="": Path to the RDT configuration file for configuring the resctrl pseudo-filesystem. diff --git a/docs/crio.conf.5.md b/docs/crio.conf.5.md index 3bea4f999cc..9327199c9a4 100644 --- a/docs/crio.conf.5.md +++ b/docs/crio.conf.5.md @@ -494,7 +494,7 @@ Path to the temporary directory to use for storing big files, used to store imag **auto_reload_registries**=false If true, CRI-O will automatically reload the mirror registry when there is an update to the 'registries.conf.d' directory. Default value is set to 'false'. -**pull_progress_timeout**="10s" +**pull_progress_timeout**="0s" The timeout for an image pull to make progress until the pull operation gets canceled. This value will be also used for calculating the pull progress interval to pull_progress_timeout / 10. Can be set to 0 to disable the timeout as well as the progress output. ## CRIO.NETWORK TABLE diff --git a/pkg/config/config.go b/pkg/config/config.go index ac092677598..fa979047456 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -956,7 +956,7 @@ func DefaultConfig() (*Config, error) { PauseCommand: "/pause", ImageVolumes: ImageVolumesMkdir, SignaturePolicyDir: "/etc/crio/policies", - PullProgressTimeout: 10 * time.Second, + PullProgressTimeout: 0, }, NetworkConfig: NetworkConfig{ NetworkDir: cniConfigDir, From 3feea4aa61c19b0f90ef4265c33edc4773569a83 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 24 Mar 2025 04:08:32 -0400 Subject: [PATCH 40/47] fix schema v1 images not resolve to image ID error Signed-off-by: Qi Wang --- internal/storage/image.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/storage/image.go b/internal/storage/image.go index 3d41f320ce8..58f40ab17e7 100644 --- a/internal/storage/image.go +++ b/internal/storage/image.go @@ -841,7 +841,12 @@ func pullImageImplementation(ctx context.Context, lookup *imageLookupService, st return nil, nil, err } - canonicalRef, err := reference.WithDigest(reference.TrimNamed(imageName.Raw()), digest.FromBytes(manifestBytes)) + digest, err := manifest.Digest(manifestBytes) + if err != nil { + return RegistryImageReference{}, fmt.Errorf("digesting image: %w", err) + } + + canonicalRef, err := reference.WithDigest(reference.TrimNamed(imageName.Raw()), digest) if err != nil { return nil, nil, fmt.Errorf("create canonical reference: %w", err) } From de8542250ed32a6aaaadf29339c860fa8f994ef6 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Thu, 1 May 2025 00:29:45 +0000 Subject: [PATCH 41/47] version: bump to 1.31.8 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 1f9c4459fa8..7884e2edfad 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.7" +const Version = "1.31.8" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From fbe567bca3991570716988894206ec0a0664f755 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Mon, 5 May 2025 15:51:56 -0400 Subject: [PATCH 42/47] fix compile error on older versions Signed-off-by: Peter Hunt --- internal/storage/image.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/storage/image.go b/internal/storage/image.go index 58f40ab17e7..6aa47138082 100644 --- a/internal/storage/image.go +++ b/internal/storage/image.go @@ -841,12 +841,12 @@ func pullImageImplementation(ctx context.Context, lookup *imageLookupService, st return nil, nil, err } - digest, err := manifest.Digest(manifestBytes) + dgst, err := manifest.Digest(manifestBytes) if err != nil { - return RegistryImageReference{}, fmt.Errorf("digesting image: %w", err) + return nil, nil, fmt.Errorf("digesting image: %w", err) } - canonicalRef, err := reference.WithDigest(reference.TrimNamed(imageName.Raw()), digest) + canonicalRef, err := reference.WithDigest(reference.TrimNamed(imageName.Raw()), dgst) if err != nil { return nil, nil, fmt.Errorf("create canonical reference: %w", err) } From 8df984791b0d6a67e390d0f9d477eb1a2d8c73c8 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Sun, 1 Jun 2025 00:38:40 +0000 Subject: [PATCH 43/47] version: bump to 1.31.9 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 7884e2edfad..e34e1430f25 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.8" +const Version = "1.31.9" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From 5982eff5ecacb09c5e479347ce51719658430fab Mon Sep 17 00:00:00 2001 From: Ayato Tokubi Date: Wed, 18 Dec 2024 17:25:11 +0000 Subject: [PATCH 44/47] Refactor man page variables in Makefile. Cherry-pick of: 0daeb208f107ab73602b78d2b35b151b938365b9 Signed-off-by: Ayato Tokubi Signed-off-by: Sascha Grunert --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 34f9d429d9d..d288323f199 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,9 @@ COVERAGE_PATH := ${BUILD_PATH}/coverage TESTBIN_PATH := ${BUILD_PATH}/test MOCK_PATH := ${PWD}/test/mocks +MANPAGES_MD := $(wildcard docs/*.md) +MANPAGES := $(MANPAGES_MD:%.md=%) + BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions FISHINSTALLDIR=${PREFIX}/share/fish/completions ZSHINSTALLDIR=${PREFIX}/share/zsh/site-functions @@ -532,9 +535,6 @@ mock-ociartifact-types: ${MOCKGEN} -destination ${MOCK_PATH}/ociartifact/ociartifact.go \ github.com/cri-o/cri-o/internal/config/ociartifact Impl -MANPAGES_MD := $(wildcard docs/*.md) -MANPAGES := $(MANPAGES_MD:%.md=%) - docs/%.5: docs/%.5.md ${GO_MD2MAN} (${GO_MD2MAN} -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@) || \ (${GO_MD2MAN} -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@) From 0ae758380226b4907b8fa2a4cd7c67d67c22db9c Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 29 Apr 2025 11:45:45 -0400 Subject: [PATCH 45/47] sandbox: use created/stopped instead of infra container for readiness As we hit cases of deadlock when a sandbox is stuck stopping Signed-off-by: Peter Hunt --- internal/lib/container_server.go | 5 +++ internal/lib/sandbox/sandbox.go | 67 +++++++++++++++++----------- internal/lib/sandbox/sandbox_test.go | 2 + server/container_portforward.go | 2 +- server/sandbox_list_test.go | 3 +- server/sandbox_status.go | 5 +-- server/server.go | 6 +++ 7 files changed, 57 insertions(+), 33 deletions(-) diff --git a/internal/lib/container_server.go b/internal/lib/container_server.go index b252e56e22f..7fa78857749 100644 --- a/internal/lib/container_server.go +++ b/internal/lib/container_server.go @@ -353,6 +353,11 @@ func (c *ContainerServer) LoadSandbox(ctx context.Context, id string) (sb *sandb } sb.SetCreated() + + if scontainer.State().Status == oci.ContainerStateStopped { + sb.SetStopped(ctx, true) + } + if err := label.ReserveLabel(processLabel); err != nil { return sb, err } diff --git a/internal/lib/sandbox/sandbox.go b/internal/lib/sandbox/sandbox.go index b6b9707a704..c4c9a591ddf 100644 --- a/internal/lib/sandbox/sandbox.go +++ b/internal/lib/sandbox/sandbox.go @@ -57,15 +57,18 @@ type Sandbox struct { nsOpts *types.NamespaceOption dnsConfig *types.DNSConfig stopMutex sync.RWMutex - created bool - stopped bool - networkStopped bool - privileged bool - hostNetwork bool - usernsMode string - containerEnvPath string - podLinuxOverhead *types.LinuxContainerResources - podLinuxResources *types.LinuxContainerResources + // stateMutex protects the use of created, stopped and networkStopped bools + // which are all fields that can change at runtime + stateMutex sync.RWMutex + created bool + stopped bool + networkStopped bool + privileged bool + hostNetwork bool + usernsMode string + containerEnvPath string + podLinuxOverhead *types.LinuxContainerResources + podLinuxResources *types.LinuxContainerResources } // DefaultShmSize is the default shm size. @@ -353,6 +356,10 @@ func (s *Sandbox) RemoveInfraContainer() { func (s *Sandbox) SetStopped(ctx context.Context, createFile bool) { ctx, span := log.StartSpan(ctx) defer span.End() + + s.stateMutex.Lock() + defer s.stateMutex.Unlock() + if s.stopped { return } @@ -367,16 +374,24 @@ func (s *Sandbox) SetStopped(ctx context.Context, createFile bool) { // Stopped returns whether the sandbox state has been // set to stopped. func (s *Sandbox) Stopped() bool { + s.stateMutex.RLock() + defer s.stateMutex.RUnlock() + return s.stopped } // SetCreated sets the created status of sandbox to true. func (s *Sandbox) SetCreated() { + s.stateMutex.Lock() + defer s.stateMutex.Unlock() s.created = true } // NetworkStopped returns whether the network has been stopped. func (s *Sandbox) NetworkStopped() bool { + s.stateMutex.RLock() + defer s.stateMutex.RUnlock() + return s.networkStopped } @@ -390,6 +405,10 @@ func (s *Sandbox) NetworkStopped() bool { func (s *Sandbox) SetNetworkStopped(ctx context.Context, createFile bool) error { ctx, span := log.StartSpan(ctx) defer span.End() + + s.stateMutex.Lock() + defer s.stateMutex.Unlock() + if s.networkStopped { return nil } @@ -421,6 +440,7 @@ func (s *Sandbox) SetContainerEnvFile(ctx context.Context) error { return nil } +// This function assumes the state lock has been taken for this sandbox. func (s *Sandbox) createFileInInfraDir(ctx context.Context, filename string) error { // If the sandbox is not yet created, // this function is being called when @@ -446,6 +466,9 @@ func (s *Sandbox) createFileInInfraDir(ctx context.Context, filename string) err } func (s *Sandbox) RestoreStopped() { + s.stateMutex.Lock() + defer s.stateMutex.Unlock() + if s.fileExistsInInfraDir(sbStoppedFilename) { s.stopped = true } @@ -468,11 +491,14 @@ func (s *Sandbox) fileExistsInInfraDir(filename string) bool { // Created returns the created status of sandbox. func (s *Sandbox) Created() bool { + s.stateMutex.RLock() + defer s.stateMutex.RUnlock() + return s.created } func (s *Sandbox) State() types.PodSandboxState { - if s.Ready(false) { + if s.Ready() { return types.PodSandboxState_SANDBOX_READY } return types.PodSandboxState_SANDBOX_NOTREADY @@ -483,22 +509,9 @@ func (s *Sandbox) State() types.PodSandboxState { // `takeLock` should be set if we need to take the lock to get the infra container's state. // If there is no infra container, it is never considered ready. // If the infra container is spoofed, the pod is considered ready when it has been created, but not stopped. -func (s *Sandbox) Ready(takeLock bool) bool { - podInfraContainer := s.InfraContainer() - if podInfraContainer == nil { - return false - } - if podInfraContainer.Spoofed() { - return s.created && !s.stopped - } - // Assume the sandbox is ready, unless it has an infra container that - // isn't running - var cState *oci.ContainerState - if takeLock { - cState = podInfraContainer.State() - } else { - cState = podInfraContainer.StateNoLock() - } +func (s *Sandbox) Ready() bool { + s.stateMutex.RLock() + defer s.stateMutex.RUnlock() - return cState.Status == oci.ContainerStateRunning + return s.created && !s.stopped } diff --git a/internal/lib/sandbox/sandbox_test.go b/internal/lib/sandbox/sandbox_test.go index e9c27e7bc04..916e8ae0062 100644 --- a/internal/lib/sandbox/sandbox_test.go +++ b/internal/lib/sandbox/sandbox_test.go @@ -115,6 +115,7 @@ var _ = t.Describe("Sandbox", func() { // Then Expect(testSandbox.Stopped()).To(BeTrue()) + Expect(testSandbox.Ready()).To(BeFalse()) }) }) @@ -160,6 +161,7 @@ var _ = t.Describe("Sandbox", func() { // Then Expect(testSandbox.Created()).To(BeTrue()) + Expect(testSandbox.Ready()).To(BeTrue()) }) }) diff --git a/server/container_portforward.go b/server/container_portforward.go index b9b52b00cee..b38e2b19a04 100644 --- a/server/container_portforward.go +++ b/server/container_portforward.go @@ -50,7 +50,7 @@ func (s StreamService) PortForward(ctx context.Context, podSandboxID string, por return fmt.Errorf("could not find sandbox %s", podSandboxID) } - if !sb.Ready(true) { + if !sb.Ready() { return fmt.Errorf("sandbox %s is not running", podSandboxID) } diff --git a/server/sandbox_list_test.go b/server/sandbox_list_test.go index c17a89fd250..1f1a1e35afa 100644 --- a/server/sandbox_list_test.go +++ b/server/sandbox_list_test.go @@ -96,8 +96,9 @@ var _ = t.Describe("ListPodSandbox", func() { // Given mockDirs(testManifest) createDummyState() - _, err := sut.LoadSandbox(context.Background(), sandboxID) + sb, err := sut.LoadSandbox(context.Background(), sandboxID) Expect(err).ToNot(HaveOccurred()) + sb.SetStopped(context.Background(), false) // When response, err := sut.ListPodSandbox(context.Background(), diff --git a/server/sandbox_status.go b/server/sandbox_status.go index 484e9abac21..6aa8c7dd3c0 100644 --- a/server/sandbox_status.go +++ b/server/sandbox_status.go @@ -24,10 +24,7 @@ func (s *Server) PodSandboxStatus(ctx context.Context, req *types.PodSandboxStat return nil, status.Errorf(codes.NotFound, "could not find pod %q: %v", req.PodSandboxId, err) } - rStatus := types.PodSandboxState_SANDBOX_NOTREADY - if sb.Ready(true) { - rStatus = types.PodSandboxState_SANDBOX_READY - } + rStatus := sb.State() var linux *types.LinuxPodSandboxStatus if sb.NamespaceOptions() != nil { diff --git a/server/server.go b/server/server.go index 4cc3e7c3f4a..4a819b20425 100644 --- a/server/server.go +++ b/server/server.go @@ -808,6 +808,12 @@ func (s *Server) handleExit(ctx context.Context, event fsnotify.Event) { } c = sb.InfraContainer() resource = "sandbox infra" + // We discovered the infra container stopped (potentially unexpectedly). + // Since sandboxes status is now being judged by the sb.stopped boolean, + // rather than the infra container's status, we have to manually set stopped here. + // It's likely we're doing double the work here, but that's better than missing it + // if the infra container crashed. + sb.SetStopped(ctx, true) } else { sb = s.GetSandbox(c.Sandbox()) } From 01e609c6c637acf7814e94e24e7c8b84b9fdb245 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Tue, 1 Jul 2025 00:32:19 +0000 Subject: [PATCH 46/47] version: bump to 1.31.10 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index e34e1430f25..e7291f1e6c6 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -21,7 +21,7 @@ import ( ) // Version is the version of the build. -const Version = "1.31.9" +const Version = "1.31.10" // ReleaseMinorVersions are the currently supported minor versions. var ReleaseMinorVersions = []string{"1.30", "1.29", "1.28"} From 103e03f8abcc2215f79a7845be887b6405e5d1bb Mon Sep 17 00:00:00 2001 From: Ayato Tokubi Date: Fri, 13 Jun 2025 04:24:32 +0000 Subject: [PATCH 47/47] fix deadlock when the container is in uninterruptible sleep Signed-off-by: Ayato Tokubi (cherry picked from commit 1e751b490b2f8eb48cc39efa9eca2c0ffcd9ac0c) Signed-off-by: Ayato Tokubi # Conflicts: # internal/oci/container.go # internal/oci/runtime_oci.go --- internal/oci/container.go | 52 +++++++++++++++++++++++++------------ internal/oci/runtime_oci.go | 6 ++++- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/internal/oci/container.go b/internal/oci/container.go index 87b161357b2..c92df49de09 100644 --- a/internal/oci/container.go +++ b/internal/oci/container.go @@ -69,6 +69,7 @@ type Container struct { stopLock sync.Mutex stopTimeoutChan chan int64 stopWatchers []chan struct{} + stopKillLoopBegun bool pidns nsmgr.Namespace restore bool restoreArchivePath string @@ -155,22 +156,23 @@ func NewContainer(id, name, bundlePath, logPath string, labels, crioAnnotations, ImageRef: externalImageRef, ImageId: imageIDString, }, - name: name, - bundlePath: bundlePath, - logPath: logPath, - terminal: terminal, - stdin: stdin, - stdinOnce: stdinOnce, - runtimeHandler: runtimeHandler, - crioAnnotations: crioAnnotations, - imageName: imageName, - imageID: imageID, - dir: dir, - state: state, - stopSignal: stopSignal, - stopTimeoutChan: make(chan int64, 10), - stopWatchers: []chan struct{}{}, - execPIDs: map[int]bool{}, + name: name, + bundlePath: bundlePath, + logPath: logPath, + terminal: terminal, + stdin: stdin, + stdinOnce: stdinOnce, + runtimeHandler: runtimeHandler, + crioAnnotations: crioAnnotations, + imageName: imageName, + imageID: imageID, + dir: dir, + state: state, + stopSignal: stopSignal, + stopTimeoutChan: make(chan int64, 10), + stopWatchers: []chan struct{}{}, + stopKillLoopBegun: false, + execPIDs: map[int]bool{}, } return c, nil } @@ -611,6 +613,13 @@ func (c *Container) SetAsStopping() (setToStopping bool) { return false } +// SetStopKillLoopBegun sets the stopKillLoopBegun flag to true. +func (c *Container) SetStopKillLoopBegun() { + c.stopLock.Lock() + defer c.stopLock.Unlock() + c.stopKillLoopBegun = true +} + func (c *Container) WaitOnStopTimeout(ctx context.Context, timeout int64) { c.stopLock.Lock() if !c.stopping { @@ -618,7 +627,16 @@ func (c *Container) WaitOnStopTimeout(ctx context.Context, timeout int64) { return } - c.stopTimeoutChan <- timeout + // Don't use the stopTimeoutChan when the container is in kill loop + // because values in the channel are no longer consumed. + if !c.stopKillLoopBegun { + // Use select and default not to block when the stopTimeoutChan is full. + // The channel is very unlikely to be full, but it could happen in theory. + select { + case c.stopTimeoutChan <- timeout: + default: + } + } watcher := make(chan struct{}, 1) c.stopWatchers = append(c.stopWatchers, watcher) diff --git a/internal/oci/runtime_oci.go b/internal/oci/runtime_oci.go index cdf01d05645..b855c6be044 100644 --- a/internal/oci/runtime_oci.go +++ b/internal/oci/runtime_oci.go @@ -949,7 +949,9 @@ func (r *runtimeOCI) StopLoopForContainer(c *Container, bm kwait.BackoffManager) } case <-time.After(time.Until(targetTime)): - log.Warnf(ctx, "Stopping container %s with stop signal timed out. Killing...", c.ID()) + log.Warnf(ctx, "Stopping container %s with stop signal(%s) timed out. Killing...", c.ID(), c.GetStopSignal()) + c.SetStopKillLoopBegun() + goto killContainer case <-done: @@ -971,9 +973,11 @@ killContainer: } if err := c.Living(); err != nil { + log.Debugf(ctx, "Container is no longer alive") stop() return } + log.Debugf(ctx, "Killing failed for some reasons, retrying...") // Reschedule the timer so that the periodic reminder can continue. blockedTimer.Reset(stopProcessBlockedInterval) }, bm, true, ctx.Done())