From 926812812873e45f5537536739070435518e7bfa Mon Sep 17 00:00:00 2001 From: pkgagent Date: Wed, 19 Aug 2026 13:07:29 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Fix=20CVE-2026-17106=20by=20upgrading=20ven?= =?UTF-8?q?dored=20archive=20to=20moby/go-archive=20v0.3.0=20(docker/docke?= =?UTF-8?q?r=20pkg/archi=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...pt-upstream-patches-to-fix-the-CVE-2.patch | 297 ------------------ docker-compose.spec | 22 +- sources | 4 +- 3 files changed, 16 insertions(+), 307 deletions(-) delete mode 100644 0001-backport-and-adapt-upstream-patches-to-fix-the-CVE-2.patch diff --git a/0001-backport-and-adapt-upstream-patches-to-fix-the-CVE-2.patch b/0001-backport-and-adapt-upstream-patches-to-fix-the-CVE-2.patch deleted file mode 100644 index dac40bf..0000000 --- a/0001-backport-and-adapt-upstream-patches-to-fix-the-CVE-2.patch +++ /dev/null @@ -1,297 +0,0 @@ -From e747a006136530be6b67925f1b53fbf672fc16cf Mon Sep 17 00:00:00 2001 -From: clarehkli -Date: Sun, 23 Nov 2025 11:11:50 +0800 -Subject: [PATCH] backport and adapt upstream patches to fix the CVE-2025-62725 - -the adapted patches and the reasons for adaptation are as follows: -840288895e673fcccd56a7830dee30d8a75523ef the prerequisite patch for fixing the CVE -69bcb962bfb2ea53b41aa925333d356b577d6176 fix the CVE issue -6a90742ef29c392b6626b0ff3f50c6f28f944321 fix test errors in ocii_test.go - -Original-URL: https://github.com/docker/compose/commit/840288895e673fcccd56a7830dee30d8a75523ef.patch -Original-URL: https://github.com/docker/compose/commit/69bcb962bfb2ea53b41aa925333d356b577d6176.patch -Original-URL: https://github.com/docker/compose/commit/6a90742ef29c392b6626b0ff3f50c6f28f944321.patch - ---- - internal/ocipush/push.go | 2 + - pkg/remote/oci.go | 83 ++++++++++++++++++++--- - pkg/remote/oci_test.go | 139 +++++++++++++++++++++++++++++++++++++++ - 3 files changed, 214 insertions(+), 10 deletions(-) - create mode 100644 pkg/remote/oci_test.go - -diff --git a/internal/ocipush/push.go b/internal/ocipush/push.go -index 0296f67..48e8ad1 100644 ---- a/internal/ocipush/push.go -+++ b/internal/ocipush/push.go -@@ -54,6 +54,8 @@ const ( - // > an artifactType field, and tooling to work with artifacts should - // > fallback to the config.mediaType value. - ComposeEmptyConfigMediaType = "application/vnd.docker.compose.config.empty.v1+json" -+ // ComposeEnvFileMediaType is the media type for each Env File layer in the image manifest. -+ ComposeEnvFileMediaType = "application/vnd.docker.compose.envfile" - ) - - // clientAuthStatusCodes are client (4xx) errors that are authentication -diff --git a/pkg/remote/oci.go b/pkg/remote/oci.go -index a9d0e09..0c98ad3 100644 ---- a/pkg/remote/oci.go -+++ b/pkg/remote/oci.go -@@ -63,6 +63,32 @@ type ociRemoteLoader struct { - - const prefix = "oci://" - -+// validatePathInBase ensures a file path is contained within the base directory, -+// as OCI artifacts resources must all live within the same folder. -+func validatePathInBase(base, unsafePath string) error { -+ // Reject paths with path separators regardless of OS -+ if strings.ContainsAny(unsafePath, "\\/") { -+ return fmt.Errorf("invalid OCI artifact") -+ } -+ -+ // Join the base with the untrusted path -+ targetPath := filepath.Join(base, unsafePath) -+ -+ // Get the directory of the target path -+ targetDir := filepath.Dir(targetPath) -+ -+ // Clean both paths to resolve any .. or . components -+ cleanBase := filepath.Clean(base) -+ cleanTargetDir := filepath.Clean(targetDir) -+ -+ // Check if the target directory is the same as base directory -+ if cleanTargetDir != cleanBase { -+ return fmt.Errorf("invalid OCI artifact") -+ } -+ -+ return nil -+} -+ - func (g ociRemoteLoader) Accept(path string) bool { - return strings.HasPrefix(path, prefix) - } -@@ -135,11 +161,6 @@ func (g ociRemoteLoader) pullComposeFiles(ctx context.Context, local string, com - return err - } - -- f, err := os.Create(composeFile) -- if err != nil { -- return err -- } -- defer f.Close() //nolint:errcheck - if (manifest.ArtifactType != "" && manifest.ArtifactType != ocipush.ComposeProjectArtifactType) || - (manifest.ArtifactType == "" && manifest.Config.MediaType != ocipush.ComposeEmptyConfigMediaType) { - return fmt.Errorf("%s is not a compose project OCI artifact, but %s", ref.String(), manifest.ArtifactType) -@@ -154,18 +175,60 @@ func (g ociRemoteLoader) pullComposeFiles(ctx context.Context, local string, com - if err != nil { - return err - } -- if i > 0 { -- _, err = f.Write([]byte("\n---\n")) -- if err != nil { -+ -+ switch layer.MediaType { -+ case ocipush.ComposeYAMLMediaType: -+ if err := writeComposeFile(layer, i, local, content); err != nil { - return err - } -+ case ocipush.ComposeEnvFileMediaType: -+ if err := writeEnvFile(layer, local, content); err != nil { -+ return err -+ } -+ case ocipush.ComposeEmptyConfigMediaType: - } -- _, err = f.Write(content) -+ } -+ return nil -+} -+ -+func writeComposeFile(layer v1.Descriptor, i int, local string, content []byte) error { -+ file := "compose.yaml" -+ if _, ok := layer.Annotations["com.docker.compose.extends"]; ok { -+ file = layer.Annotations["com.docker.compose.file"] -+ if err := validatePathInBase(local, file); err != nil { -+ return err -+ } -+ } -+ f, err := os.Create(filepath.Join(local, file)) -+ if err != nil { -+ return err -+ } -+ defer func() { _ = f.Close() }() -+ if _, ok := layer.Annotations["com.docker.compose.file"]; i > 0 && ok { -+ _, err := f.Write([]byte("\n---\n")) - if err != nil { - return err - } - } -- return nil -+ _, err = f.Write(content) -+ return err -+} -+ -+func writeEnvFile(layer v1.Descriptor, local string, content []byte) error { -+ envfilePath, ok := layer.Annotations["com.docker.compose.envfile"] -+ if !ok { -+ return fmt.Errorf("missing annotation com.docker.compose.envfile in layer %q", layer.Digest) -+ } -+ if err := validatePathInBase(local, envfilePath); err != nil { -+ return err -+ } -+ otherFile, err := os.Create(filepath.Join(local, envfilePath)) -+ if err != nil { -+ return err -+ } -+ defer func() { _ = otherFile.Close() }() -+ _, err = otherFile.Write(content) -+ return err - } - - var _ loader.ResourceLoader = ociRemoteLoader{} -diff --git a/pkg/remote/oci_test.go b/pkg/remote/oci_test.go -new file mode 100644 -index 0000000..28a4dbd ---- /dev/null -+++ b/pkg/remote/oci_test.go -@@ -0,0 +1,139 @@ -+/* -+ Copyright 2020 Docker Compose CLI authors -+ -+ Licensed under the Apache License, Version 2.0 (the "License"); -+ you may not use this file except in compliance with the License. -+ You may obtain a copy of the License at -+ -+ http://www.apache.org/licenses/LICENSE-2.0 -+ -+ Unless required by applicable law or agreed to in writing, software -+ distributed under the License is distributed on an "AS IS" BASIS, -+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ See the License for the specific language governing permissions and -+ limitations under the License. -+*/ -+ -+package remote -+ -+import ( -+ "path/filepath" -+ "testing" -+ -+ spec "github.com/opencontainers/image-spec/specs-go/v1" -+ "gotest.tools/v3/assert" -+) -+ -+func TestValidatePathInBase(t *testing.T) { -+ base := "/tmp/cache/compose" -+ -+ tests := []struct { -+ name string -+ unsafePath string -+ wantErr bool -+ }{ -+ { -+ name: "valid simple filename", -+ unsafePath: "compose.yaml", -+ wantErr: false, -+ }, -+ { -+ name: "valid hashed filename", -+ unsafePath: "f8f9ede3d201ec37d5a5e3a77bbadab79af26035e53135e19571f50d541d390c.yaml", -+ wantErr: false, -+ }, -+ { -+ name: "valid env file", -+ unsafePath: ".env", -+ wantErr: false, -+ }, -+ { -+ name: "valid env file with suffix", -+ unsafePath: ".env.prod", -+ wantErr: false, -+ }, -+ { -+ name: "unix path traversal", -+ unsafePath: "../../../etc/passwd", -+ wantErr: true, -+ }, -+ { -+ name: "windows path traversal", -+ unsafePath: "..\\..\\..\\windows\\system32\\config\\sam", -+ wantErr: true, -+ }, -+ { -+ name: "subdirectory unix", -+ unsafePath: "config/base.yaml", -+ wantErr: true, -+ }, -+ { -+ name: "subdirectory windows", -+ unsafePath: "config\\base.yaml", -+ wantErr: true, -+ }, -+ { -+ name: "absolute unix path", -+ unsafePath: "/etc/passwd", -+ wantErr: true, -+ }, -+ { -+ name: "absolute windows path", -+ unsafePath: "C:\\windows\\system32\\config\\sam", -+ wantErr: true, -+ }, -+ { -+ name: "parent reference only", -+ unsafePath: "..", -+ wantErr: true, -+ }, -+ { -+ name: "mixed separators", -+ unsafePath: "config/sub\\file.yaml", -+ wantErr: true, -+ }, -+ { -+ name: "filename with spaces", -+ unsafePath: "my file.yaml", -+ wantErr: false, -+ }, -+ { -+ name: "filename with special chars", -+ unsafePath: "file-name_v1.2.3.yaml", -+ wantErr: false, -+ }, -+ } -+ -+ for _, tt := range tests { -+ t.Run(tt.name, func(t *testing.T) { -+ err := validatePathInBase(base, tt.unsafePath) -+ if (err != nil) != tt.wantErr { -+ targetPath := filepath.Join(base, tt.unsafePath) -+ targetDir := filepath.Dir(targetPath) -+ t.Errorf("validatePathInBase(%q, %q) error = %v, wantErr %v\ntargetDir=%q base=%q", -+ base, tt.unsafePath, err, tt.wantErr, targetDir, base) -+ } -+ }) -+ } -+} -+ -+func TestWriteComposeFileWithExtendsPathTraversal(t *testing.T) { -+ tmpDir := t.TempDir() -+ -+ // Create a layer with com.docker.compose.extends=true and a path traversal attempt -+ layer := spec.Descriptor{ -+ MediaType: "application/vnd.docker.compose.file.v1+yaml", -+ Digest: "sha256:test123", -+ Size: 100, -+ Annotations: map[string]string{ -+ "com.docker.compose.extends": "true", -+ "com.docker.compose.file": "../other", -+ }, -+ } -+ -+ content := []byte("services:\n test:\n image: nginx\n") -+ -+ // writeComposeFile should return an error due to path traversal -+ err := writeComposeFile(layer, 0, tmpDir, content) -+ assert.Error(t, err, "invalid OCI artifact") -+} --- -2.43.7 - diff --git a/docker-compose.spec b/docker-compose.spec index 940c75b..58faf82 100644 --- a/docker-compose.spec +++ b/docker-compose.spec @@ -1,19 +1,17 @@ %global gohomepath github.com/docker/compose -%global goipath %{gohomepath}/v2 +%global goipath %{gohomepath}/v5 Summary: Define and run multi-container applications with Docker Name: docker-compose -Version: 2.30.3 -Release: 4%{?dist} +Version: 5.4.0 +Release: 1%{?dist} License: Apache-2.0 URL: https://github.com/docker/compose -Source0: %{url}/archive/refs/tags/v2.30.3.tar.gz #/%{name}-%{version}.tar.gz +Source0: %{url}/archive/refs/tags/v%{version}.tar.gz #/%{name}-%{version}.tar.gz # execute 'go mod vendor' under the source code path can generator vendor package Source1: %{name}-vendor.tar.gz -Patch0001: 0001-backport-and-adapt-upstream-patches-to-fix-the-CVE-2.patch - -BuildRequires: golang go-rpm-macros +BuildRequires: golang >= 1.26.3 go-rpm-macros Requires: docker docker-compose-switch @@ -35,7 +33,7 @@ ln -sfn $PWD $GOPATH/src/%{goipath} export CGO_ENABLED=1 export GOFLAGS="-mod=vendor" -export GO_LDFLAGS=" -X github.com/docker/compose/v2/internal.Version=%{version} " +export GO_LDFLAGS=" -X github.com/docker/compose/v5/internal.Version=%{version} " %gobuild -o bin/%{name} %{goipath}/cmd %install @@ -53,6 +51,14 @@ install -D -m 0755 bin/%{name} "%{buildroot}/usr/lib/docker/cli-plugins/%{name}" /usr/lib/docker/cli-plugins/%{name} %changelog +* Wed Aug 19 2026 PkgAgent Robot - 5.4.0-1 +- [Type] security +- [DESC] Update to 5.4.0 (fixes CVE-2026-17106 via vendored moby/go-archive v0.3.2) + +* Wed Aug 19 2026 PkgAgent Robot - 2.30.3-5 +- [Type] security +- [DESC] Fix CVE-2026-17106 by upgrading vendored archive to moby/go-archive v0.3.0 (docker/docker pkg/archive predecessor) + * Sun Nov 23 2025 clarehkli - 2.30.3-4 - [Type] security - [DESC] backport and adapt upstream patches to fix the CVE-2025-62725 diff --git a/sources b/sources index c60d645..621af36 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (docker-compose-2.30.3.tar.gz) = 89a1dd43c42c41bc689af76e38f88fbf8063df486b21100f8ccb416c5583a57ef055a78fe846f800b7c4e95190f4a51458c9dcb3408e8cd7df50c4459c0bd128 -SHA512 (docker-compose-vendor.tar.gz) = d1056e4e84be8c6b1ab6f8010dd29931c8e5ab27c83ad12579cfb75ec77b2c138f4d91125f5d1de088f859b330f8659e9a6b84e25543cd3a85f3616b334db746 +SHA512 (docker-compose-5.4.0.tar.gz) = 46819486e3de32f3a07821acde6c2361dcfde307779247c55f51c5ed1cf4df1103d8d2475590d53999693cbfd2baf71404f81f05ebfc9fbb1adbf90f8800cdc5 +SHA512 (docker-compose-vendor.tar.gz) = ec2fe0c28ee7c48938b5a229f9052be5fb5e72767dfe05a28ce93e008eb26f84ae65876529b0e73b49859e76a6655c84ef5ef62dd02f5309ec67a0b086db939b -- Gitee From 67988c87417e044b4317918f4fec4a5b83a03ce2 Mon Sep 17 00:00:00 2001 From: pkgagent Date: Wed, 19 Aug 2026 15:47:32 +0800 Subject: [PATCH 2/2] remove stale 2.30.3-5 changelog entry from spec (vendor-upgrade superseded by 5.4.0 upgrade) --- docker-compose.spec | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docker-compose.spec b/docker-compose.spec index 58faf82..0fd3f03 100644 --- a/docker-compose.spec +++ b/docker-compose.spec @@ -55,10 +55,6 @@ install -D -m 0755 bin/%{name} "%{buildroot}/usr/lib/docker/cli-plugins/%{name}" - [Type] security - [DESC] Update to 5.4.0 (fixes CVE-2026-17106 via vendored moby/go-archive v0.3.2) -* Wed Aug 19 2026 PkgAgent Robot - 2.30.3-5 -- [Type] security -- [DESC] Fix CVE-2026-17106 by upgrading vendored archive to moby/go-archive v0.3.0 (docker/docker pkg/archive predecessor) - * Sun Nov 23 2025 clarehkli - 2.30.3-4 - [Type] security - [DESC] backport and adapt upstream patches to fix the CVE-2025-62725 -- Gitee