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 dac40bfea86eedc01f49937a34fe4848a3f87cbc..0000000000000000000000000000000000000000 --- 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 940c75bf1388d7ec523dbe2509df301088d959d8..a73c26721319417a2ad3c0e23341ebfd42763240 100644 --- a/docker-compose.spec +++ b/docker-compose.spec @@ -3,16 +3,14 @@ Summary: Define and run multi-container applications with Docker Name: docker-compose -Version: 2.30.3 -Release: 4%{?dist} +Version: 5.1.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/v5.1.0.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 Requires: docker docker-compose-switch @@ -53,6 +51,10 @@ install -D -m 0755 bin/%{name} "%{buildroot}/usr/lib/docker/cli-plugins/%{name}" /usr/lib/docker/cli-plugins/%{name} %changelog +* Fri Apr 24 2026 clarehkli - 5.1.0-1 +- [Type] security +- [DESC] upgrade to 5.1.0 to fix CVE-2025-58181 and CVE-2025-47914 + * 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 c60d64528423d693cfa29483670b04935ec58e77..f56c9b8d59e588bfcecc69a7aa505387983fc0fe 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.1.0.tar.gz) = 993cdc321d645e9a62aa057b68bd5c886169e17a97321edcb80f99045a9f1003a813e004c442d087414bd212762dd4372fbf42574085ddf5603c1dfb87f0f21c +SHA512 (docker-compose-vendor.tar.gz) = f5eef6579392ffc362fead4ce2703d6665285aafb00873e9da5323c95ad11f46ee954c7276aa3724f73dd3d608df4ba7b9b54ad6b797157e4bbda01de438bece