Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:FrontRunner
gradle.36305
gradle-CVE-2023-35946.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File gradle-CVE-2023-35946.patch of Package gradle.36305
From 859eae2b2acf751ae7db3c9ffefe275aa5da0d5d Mon Sep 17 00:00:00 2001 From: Louis Jacomet <louis@gradle.com> Date: Thu, 15 Jun 2023 17:10:18 +0200 Subject: [PATCH] Fix dependency cache path traversal vulnerability Gradle leverages the protection added to prevent ZipSlip for any path computation inside a Gradle cache. See https://github.com/gradle/gradle/security/advisories/GHSA-2h6c-rv6q-494v --- .../local/DefaultPathKeyFileStore.java | 26 ++- .../local/DefaultPathKeyFileStoreTest.groovy | 3 +- .../CacheResolveIntegrationTest.groovy | 151 ++++++++++++++++++ 3 files changed, 174 insertions(+), 6 deletions(-) --- a/subprojects/core/src/main/java/org/gradle/internal/resource/local/DefaultPathKeyFileStore.java +++ b/subprojects/core/src/main/java/org/gradle/internal/resource/local/DefaultPathKeyFileStore.java @@ -26,11 +26,15 @@ import org.gradle.api.internal.file.dele import org.gradle.internal.UncheckedException; import org.gradle.util.GFileUtils; import org.gradle.util.RelativePathUtil; +import org.gradle.wrapper.PathTraversalChecker; import java.io.File; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; import static org.gradle.internal.FileUtils.hasExtension; @@ -79,8 +83,17 @@ public class DefaultPathKeyFileStore imp return saveIntoFileStore(source, getFile(path), false); } - private File getFile(String path) { - return new File(baseDir, path); + private File getFile(String... path) { + String composedPath; + if (path.length == 1) { + composedPath = path[0]; + } else { + // We need to ignore empty Strings as this is what "new File(parent, path)" was doing for "path" empty. + composedPath = Arrays.stream(path) + .filter(((Predicate<String>) String::isEmpty).negate()) + .collect(Collectors.joining(File.separator)); + } + return new File(baseDir, PathTraversalChecker.safePathName(trimLeadingSlash(composedPath))); } private File getFileWhileCleaningInProgress(String path) { @@ -234,4 +247,10 @@ public class DefaultPathKeyFileStore imp return new File(baseDir, path); } } -} + + private static String trimLeadingSlash(String composedPath) { + if (!composedPath.isEmpty() && composedPath.charAt(0) == '/') { + return composedPath.substring(1); + } + return composedPath; + }} --- a/subprojects/core/src/test/groovy/org/gradle/internal/resource/local/DefaultPathKeyFileStoreTest.groovy +++ b/subprojects/core/src/test/groovy/org/gradle/internal/resource/local/DefaultPathKeyFileStoreTest.groovy @@ -78,7 +78,8 @@ class DefaultPathKeyFileStoreTest extend def b = createFile("def") when: - store.move("a", a) + // leading slash does not mean absolute path + store.move("/a", a) store.move("b", b) then: --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/internal/resource/local/PathTraversalChecker.java @@ -0,0 +1,69 @@ +/* + * Copyright 2022 the original author or 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 org.gradle.wrapper; + +import org.gradle.api.NonNullApi; + +import java.io.File; +import java.util.Locale; + +import static java.lang.String.format; + +@NonNullApi +public class PathTraversalChecker { + + /** + * Checks the entry name for path traversal vulnerable sequences. + * + * This code is used for path traversal, ZipSlip and TarSlip detection. + * + * <b>IMPLEMENTATION NOTE</b> + * We do it this way instead of the way recommended in <a href="https://snyk.io/research/zip-slip-vulnerability"></a> + * for performance reasons, calling {@link File#getCanonicalPath()} is too expensive. + * + * @throws IllegalArgumentException if the entry contains vulnerable sequences + */ + public static String safePathName(String name) { + if (isUnsafePathName(name)) { + throw new IllegalArgumentException(format("'%s' is not a safe archive entry or path name.", name)); + } + return name; + } + + public static boolean isUnsafePathName(String name) { + return name.isEmpty() + || name.startsWith("/") + || name.startsWith("\\") + || containsDirectoryNavigation(name) + || (name.contains(":") && isWindows()); + } + + private static boolean containsDirectoryNavigation(String name) { + if (!name.contains("..")) { + return false; + } + // We have a .. but if not before a file separator or at the end, it is OK + return name.endsWith("\\..") + || name.contains("..\\") + || name.endsWith("/..") + || name.contains("../"); + } + + private static boolean isWindows() { + return System.getProperty("os.name").toLowerCase(Locale.US).contains("windows"); + } +}
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor