diff --git a/gradle-CVE-2019-15052.patch b/gradle-CVE-2019-15052.patch new file mode 100644 index 0000000000000000000000000000000000000000..6a720c3ea29f73794594b3c79785325fe50d5be4 --- /dev/null +++ b/gradle-CVE-2019-15052.patch @@ -0,0 +1,358 @@ +--- gradle-4.4.1/subprojects/build-cache-http/src/main/java/org/gradle/caching/http/internal/DefaultHttpBuildCacheServiceFactory.java 2024-03-26 07:40:41.413892314 +0100 ++++ gradle-4.4.1/subprojects/build-cache-http/src/main/java/org/gradle/caching/http/internal/DefaultHttpBuildCacheServiceFactory.java 2024-03-26 08:16:01.318058239 +0100 +@@ -64,6 +64,7 @@ + if (credentialsPresent(credentials)) { + DefaultBasicAuthentication basicAuthentication = new DefaultBasicAuthentication("basic"); + basicAuthentication.setCredentials(credentials); ++ basicAuthentication.addHost(url.getHost(), url.getPort()); + authentications = Collections.singleton(basicAuthentication); + } + +--- gradle-4.4.1/subprojects/core/src/main/java/org/gradle/internal/authentication/AbstractAuthentication.java 2024-03-26 07:40:40.987222689 +0100 ++++ gradle-4.4.1/subprojects/core/src/main/java/org/gradle/internal/authentication/AbstractAuthentication.java 2024-03-26 08:11:51.403094079 +0100 +@@ -16,25 +16,31 @@ + + package org.gradle.internal.authentication; + ++import com.google.common.collect.Sets; + import org.gradle.api.credentials.Credentials; + import org.gradle.authentication.Authentication; + ++import java.util.Collection; ++import java.util.Objects; ++import java.util.Set; ++ + public abstract class AbstractAuthentication implements AuthenticationInternal { + private final String name; + private final Class supportedCredentialType; + private final Class type; + private Credentials credentials; + ++ private final Set hosts; ++ + public AbstractAuthentication(String name, Class type) { +- this.name = name; +- this.supportedCredentialType = null; +- this.type = type; ++ this(name, type, null); + } + + public AbstractAuthentication(String name, Class type, Class supportedCredential) { + this.name = name; + this.supportedCredentialType = supportedCredential; + this.type = type; ++ this.hosts = Sets.newHashSet(); + } + + @Override +@@ -66,4 +72,54 @@ public abstract class AbstractAuthentication implements AuthenticationInternal { + public String toString() { + return String.format("'%s'(%s)", getName(), getType().getSimpleName()); + } ++ ++ ++ @Override ++ public Collection getHostsForAuthentication() { ++ return hosts; ++ } ++ ++ ++ @Override ++ public void addHost(String host, int port) { ++ hosts.add(new DefaultHostAndPort(host, port)); ++ } ++ ++ private static class DefaultHostAndPort implements HostAndPort { ++ private final String host; ++ private final int port; ++ ++ DefaultHostAndPort(String host, int port) { ++ this.host = host; ++ this.port = port; ++ } ++ ++ @Override ++ public String getHost() { ++ return host; ++ } ++ ++ @Override ++ public int getPort() { ++ return port; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) { ++ return true; ++ } ++ if (o == null || getClass() != o.getClass()) { ++ return false; ++ } ++ DefaultHostAndPort that = (DefaultHostAndPort) o; ++ return getPort() == that.getPort() && ++ Objects.equals(getHost(), that.getHost()); ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hash(getHost(), getPort()); ++ } ++ } + } +--- gradle-4.4.1/subprojects/core/src/main/java/org/gradle/internal/authentication/AuthenticationInternal.java 2024-03-26 07:40:40.987222689 +0100 ++++ gradle-4.4.1/subprojects/core/src/main/java/org/gradle/internal/authentication/AuthenticationInternal.java 2024-03-26 08:11:51.403094079 +0100 +@@ -20,6 +20,8 @@ + import org.gradle.api.credentials.Credentials; + import org.gradle.authentication.Authentication; + ++import java.util.Collection; ++ + @NonExtensible + public interface AuthenticationInternal extends Authentication { + boolean supports(Credentials credentials); +@@ -31,4 +33,25 @@ + Class getType(); + + boolean requiresCredentials(); ++ ++ void addHost(String host, int port); ++ ++ Collection getHostsForAuthentication(); ++ ++ interface HostAndPort { ++ ++ /** ++ * The hostname that the credentials are required for. ++ * ++ * null means "any host" ++ */ ++ String getHost(); ++ ++ /** ++ * The port that the credentials are required for ++ * ++ * -1 means "any port" ++ */ ++ int getPort(); ++ } + } +--- gradle-4.4.1/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepository.java 2024-03-26 07:40:40.453885657 +0100 ++++ gradle-4.4.1/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepository.java 2024-03-26 09:28:23.666252731 +0100 +@@ -21,10 +21,13 @@ + import org.gradle.api.credentials.Credentials; + import org.gradle.authentication.Authentication; + import org.gradle.internal.artifacts.repositories.AuthenticationSupportedInternal; ++import org.gradle.internal.authentication.AuthenticationInternal; + import org.gradle.internal.reflect.Instantiator; + + import javax.annotation.Nullable; ++import java.net.URI; + import java.util.Collection; ++import java.util.Collections; + + public abstract class AbstractAuthenticationSupportedRepository extends AbstractArtifactRepository implements AuthenticationSupportedInternal { + private final AuthenticationSupporter delegate; +@@ -76,6 +79,21 @@ + + @Override + public Collection getConfiguredAuthentication() { +- return delegate.getConfiguredAuthentication(); ++ Collection configuredAuthentication = delegate.getConfiguredAuthentication(); ++ ++ for (Authentication authentication : configuredAuthentication) { ++ AuthenticationInternal authenticationInternal = (AuthenticationInternal) authentication; ++ for (URI repositoryUrl : getRepositoryUrls()) { ++ // only care about HTTP hosts right now ++ if (repositoryUrl.getScheme().startsWith("http")) { ++ authenticationInternal.addHost(repositoryUrl.getHost(), repositoryUrl.getPort()); ++ } ++ } ++ } ++ return configuredAuthentication; ++ } ++ ++ protected Collection getRepositoryUrls() { ++ return Collections.emptyList(); + } + } +--- gradle-4.4.1/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepository.java 2024-03-26 07:40:40.453885657 +0100 ++++ gradle-4.4.1/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepository.java 2024-03-26 09:32:04.764408347 +0100 +@@ -15,6 +15,7 @@ + */ + package org.gradle.api.internal.artifacts.repositories; + ++import com.google.common.collect.ImmutableList; + import groovy.lang.Closure; + import org.gradle.api.Action; + import org.gradle.api.ActionConfiguration; +@@ -54,6 +55,7 @@ + import org.gradle.util.ConfigureUtil; + + import java.net.URI; ++import java.util.Collection; + import java.util.LinkedHashSet; + import java.util.Set; + +@@ -189,6 +191,31 @@ + return baseUrl == null ? null : fileResolver.resolveUri(baseUrl); + } + ++ ++ @Override ++ protected Collection getRepositoryUrls() { ++ // Ivy can resolve files from multiple hosts, so we need to look at all ++ // of the possible URLs used by the Ivy resolver to identify all of the repositories ++ ImmutableList.Builder builder = ImmutableList.builder(); ++ URI root = getUrl(); ++ if (root != null) { ++ builder.add(root); ++ } ++ for (String pattern : additionalPatternsLayout.artifactPatterns) { ++ URI baseUri = new ResolvedPattern(pattern, fileResolver).baseUri; ++ if (baseUri!=null) { ++ builder.add(baseUri); ++ } ++ } ++ for (String pattern : additionalPatternsLayout.ivyPatterns) { ++ URI baseUri = new ResolvedPattern(pattern, fileResolver).baseUri; ++ if (baseUri!=null) { ++ builder.add(baseUri); ++ } ++ } ++ return builder.build(); ++ } ++ + @Override + public void setUrl(URI url) { + baseUrl = url; +--- gradle-4.4.1/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepository.java 2024-03-26 07:40:40.453885657 +0100 ++++ gradle-4.4.1/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepository.java 2024-03-26 09:31:17.924088427 +0100 +@@ -15,12 +15,14 @@ + */ + package org.gradle.api.internal.artifacts.repositories; + ++import com.google.common.collect.ImmutableList; + import com.google.common.collect.Lists; + import org.gradle.api.InvalidUserDataException; + import org.gradle.api.Transformer; + import org.gradle.api.artifacts.repositories.AuthenticationContainer; + import org.gradle.api.artifacts.repositories.MavenArtifactRepository; + import org.gradle.api.internal.ExperimentalFeatures; ++import org.gradle.api.internal.InstantiatorFactory; + import org.gradle.api.internal.artifacts.ImmutableModuleIdentifierFactory; + import org.gradle.api.internal.artifacts.ModuleVersionPublisher; + import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository; +@@ -40,6 +42,7 @@ + + import java.net.URI; + import java.util.ArrayList; ++import java.util.Collection; + import java.util.LinkedHashSet; + import java.util.List; + import java.util.Set; +@@ -152,6 +155,18 @@ + return createRealResolver(); + } + ++ @Override ++ protected Collection getRepositoryUrls() { ++ // In a similar way to Ivy, Maven may use other hosts for additional artifacts, but not POMs ++ ImmutableList.Builder builder = ImmutableList.builder(); ++ URI root = getUrl(); ++ if (root != null) { ++ builder.add(root); ++ } ++ builder.addAll(getArtifactUrls()); ++ return builder.build(); ++ } ++ + protected MavenResolver createRealResolver() { + URI rootUri = getUrl(); + if (rootUri == null) { +--- gradle-4.4.1/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpClientConfigurer.java 2024-03-26 07:40:41.393892176 +0100 ++++ gradle-4.4.1/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpClientConfigurer.java 2024-03-26 09:15:06.421058834 +0100 +@@ -117,7 +117,7 @@ + + private void configureCredentials(HttpClientBuilder builder, CredentialsProvider credentialsProvider, Collection authentications) { + if(authentications.size() > 0) { +- useCredentials(credentialsProvider, AuthScope.ANY_HOST, AuthScope.ANY_PORT, authentications); ++ useCredentials(credentialsProvider, authentications); + + // Use preemptive authorisation if no other authorisation has been established + builder.addInterceptorFirst(new PreemptiveAuth(new BasicScheme(), isPreemptiveEnabled(authentications))); +@@ -131,31 +131,49 @@ + for (HttpProxySettings.HttpProxy proxy : Lists.newArrayList(httpProxy, httpsProxy)) { + if (proxy != null) { + if (proxy.credentials != null) { +- useCredentials(credentialsProvider, proxy.host, proxy.port, Collections.singleton(new AllSchemesAuthentication(proxy.credentials))); ++ AllSchemesAuthentication authentication = new AllSchemesAuthentication(proxy.credentials); ++ authentication.addHost(proxy.host, proxy.port); ++ useCredentials(credentialsProvider, Collections.singleton(authentication)); + } + } + } + builder.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault())); + } + +- private void useCredentials(CredentialsProvider credentialsProvider, String host, int port, Collection authentications) { +- Credentials httpCredentials; +- ++ private void useCredentials(CredentialsProvider credentialsProvider, Collection authentications) { + for (Authentication authentication : authentications) { ++ AuthenticationInternal authenticationInternal = (AuthenticationInternal) authentication; ++ + String scheme = getAuthScheme(authentication); +- PasswordCredentials credentials = getPasswordCredentials(authentication); ++ org.gradle.api.credentials.Credentials credentials = authenticationInternal.getCredentials(); ++ ++ Collection hostsForAuthentication = authenticationInternal.getHostsForAuthentication(); ++ assert !hostsForAuthentication.isEmpty() : "Credentials and authentication required for a HTTP repository, but no hosts were defined for the authentication?"; ++ ++ for (AuthenticationInternal.HostAndPort hostAndPort : hostsForAuthentication) { ++ String host = hostAndPort.getHost(); ++ int port = hostAndPort.getPort(); ++ ++ assert host != null : "HTTP credentials and authentication require a host scope to be defined as well"; ++ ++ if (credentials instanceof PasswordCredentials) { ++ PasswordCredentials passwordCredentials = (PasswordCredentials) credentials; + + if (authentication instanceof AllSchemesAuthentication) { +- NTLMCredentials ntlmCredentials = new NTLMCredentials(credentials); +- httpCredentials = new NTCredentials(ntlmCredentials.getUsername(), ntlmCredentials.getPassword(), ntlmCredentials.getWorkstation(), ntlmCredentials.getDomain()); ++ NTLMCredentials ntlmCredentials = new NTLMCredentials(passwordCredentials); ++ Credentials httpCredentials = new NTCredentials(ntlmCredentials.getUsername(), ntlmCredentials.getPassword(), ntlmCredentials.getWorkstation(), ntlmCredentials.getDomain()); + credentialsProvider.setCredentials(new AuthScope(host, port, AuthScope.ANY_REALM, AuthSchemes.NTLM), httpCredentials); + +- LOGGER.debug("Using {} and {} for authenticating against '{}:{}' using {}", credentials, ntlmCredentials, host, port, AuthSchemes.NTLM); ++ LOGGER.debug("Using {} and {} for authenticating against '{}:{}' using {}", passwordCredentials, ntlmCredentials, host, port, AuthSchemes.NTLM); + } + +- httpCredentials = new UsernamePasswordCredentials(credentials.getUsername(), credentials.getPassword()); ++ Credentials httpCredentials = new UsernamePasswordCredentials(passwordCredentials.getUsername(), passwordCredentials.getPassword()); + credentialsProvider.setCredentials(new AuthScope(host, port, AuthScope.ANY_REALM, scheme), httpCredentials); +- LOGGER.debug("Using {} for authenticating against '{}:{}' using {}", credentials, host, port, scheme); ++ LOGGER.debug("Using {} for authenticating against '{}:{}' using {}", passwordCredentials, host, port, scheme); ++ } else { ++ throw new IllegalArgumentException(String.format("Credentials must be an instance of: %s", PasswordCredentials.class.getCanonicalName())); ++ } ++ } + } + } + +@@ -256,11 +274,10 @@ + CredentialsProvider credentialsProvider = (CredentialsProvider) context.getAttribute(HttpClientContext.CREDS_PROVIDER); + HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); + Credentials credentials = credentialsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort())); +- if (credentials == null) { +- throw new HttpException("No credentials for preemptive authentication"); +- } ++ if (credentials != null) { + authState.update(authScheme, credentials); + } + } + } ++ } + } + diff --git a/gradle-CVE-2021-32751.patch b/gradle-CVE-2021-32751.patch new file mode 100644 index 0000000000000000000000000000000000000000..250b923dd5ee3475acae07052369bb37e9765e63 --- /dev/null +++ b/gradle-CVE-2021-32751.patch @@ -0,0 +1,30 @@ +Index: gradle-4.4.1/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +=================================================================== +--- gradle-4.4.1.orig/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt ++++ gradle-4.4.1/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +@@ -1,4 +1,4 @@ +-#!/usr/bin/env sh ++#!/usr/bin/env bash + + ############################################################################## + ## +@@ -161,12 +161,14 @@ save () { + } + APP_ARGS=\$(save "\$@") + +-# Collect all arguments for the java command, following the shell quoting and substitution rules +-eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-classpath "\"\$CLASSPATH\"" ${mainClassName} "\$APP_ARGS" +- + # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong + if [ "\$(uname)" = "Darwin" ] && [ "\$HOME" = "\$PWD" ]; then + cd "\$(dirname "\$0")" + fi + +-exec "\$JAVACMD" "\$@" ++IFS=\$'\n' read -rd '' -a DEFAULT_JVM_OPTS_ARR <<< "\$(echo \$DEFAULT_JVM_OPTS | xargs -n1)" ++IFS=\$'\n' read -rd '' -a JAVA_OPTS_ARR <<< "\$(echo \$JAVA_OPTS | xargs -n1)" ++IFS=\$'\n' read -rd '' -a ${optsEnvironmentVar}_ARR <<< "\$(echo \$${optsEnvironmentVar} | xargs -n1)" ++ ++exec "\$JAVACMD" "\${DEFAULT_JVM_OPTS_ARR[@]}" "\${JAVA_OPTS_ARR[@]}" "\${${optsEnvironmentVar}_ARR[@]}" <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-classpath "\$CLASSPATH" ${mainClassName} "\$@" ++ + diff --git a/gradle-CVE-2023-35946.patch b/gradle-CVE-2023-35946.patch new file mode 100644 index 0000000000000000000000000000000000000000..c78c400aac14ff8d2cf1b58854ecc9e92286ec29 --- /dev/null +++ b/gradle-CVE-2023-35946.patch @@ -0,0 +1,150 @@ +From 859eae2b2acf751ae7db3c9ffefe275aa5da0d5d Mon Sep 17 00:00:00 2001 +From: Louis Jacomet +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::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. ++ * ++ * IMPLEMENTATION NOTE ++ * We do it this way instead of the way recommended in ++ * 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"); ++ } ++} + diff --git a/gradle-CVE-2023-35947.patch b/gradle-CVE-2023-35947.patch new file mode 100644 index 0000000000000000000000000000000000000000..5fdb812426aeb3aba09d163f3996cd88db8a7dec --- /dev/null +++ b/gradle-CVE-2023-35947.patch @@ -0,0 +1,73 @@ +Patch for CVE-2023-35947 (bsc#1212931) gradle: unpacking Tar +archives could create files outside of the unpack location + +Derived from upstream commits +1096b309520a8c315e3b6109a6526de4eabcb879 and +2e5c34d57d0c0b7f0e8b039a192b91e5c8249d91 + +With this patch, Gradle will refuse to handle Tar archives which +contain path traversal elements in a Tar entry name. This resolves +CVE-2023-35947. + +--- +--- a/subprojects/core/src/main/java/org/gradle/api/internal/file/archive/TarFileTree.java ++++ b/subprojects/core/src/main/java/org/gradle/api/internal/file/archive/TarFileTree.java +@@ -231,6 +231,10 @@ public class TarFileTree implements Mini + public int getMode() { + return entry.getMode() & 0777; + } ++ ++ protected String getEntryName() { ++ return entry.getName(); ++ } + } + + private static class NoCloseTarInputStream extends TarInputStream { +--- a/subprojects/core/src/main/java/org/gradle/api/internal/file/archive/ZipFileTree.java ++++ b/subprojects/core/src/main/java/org/gradle/api/internal/file/archive/ZipFileTree.java +@@ -135,6 +135,10 @@ public class ZipFileTree implements Mini + return String.format("zip entry %s!%s", originalFile, entry.getName()); + } + ++ protected String getEntryName() { ++ return entry.getName(); ++ } ++ + public void stopVisiting() { + stopFlag.set(true); + } +--- a/subprojects/core/src/main/java/org/gradle/caching/internal/tasks/TarTaskOutputPacker.java ++++ b/subprojects/core/src/main/java/org/gradle/caching/internal/tasks/TarTaskOutputPacker.java +@@ -46,6 +46,7 @@ import org.gradle.caching.internal.tasks + import org.gradle.internal.hash.HashCode; + import org.gradle.internal.hash.StreamHasher; + import org.gradle.internal.nativeplatform.filesystem.FileSystem; ++import org.gradle.wrapper.PathTraversalChecker; + + import java.io.BufferedOutputStream; + import java.io.ByteArrayOutputStream; +@@ -258,7 +259,7 @@ public class TarTaskOutputPacker impleme + long entries = 0; + while ((tarEntry = tarInput.getNextTarEntry()) != null) { + ++entries; +- String name = tarEntry.getName(); ++ String name = safeEntryName(tarEntry); + + if (name.equals(METADATA_PATH)) { + // handle origin metadata +@@ -288,6 +289,14 @@ public class TarTaskOutputPacker impleme + return new UnpackResult(originMetadata, entries, propertyFileSnapshots.build()); + } + ++ /** ++ * Returns a safe name for the name of a tar archive entry. ++ * ++ */ ++ private static String safeEntryName(TarArchiveEntry tarEntry) { ++ return PathTraversalChecker.safePathName(tarEntry.getName()); ++ } ++ + private void unpackPropertyEntry(ResolvedTaskOutputFilePropertySpec propertySpec, InputStream input, TarArchiveEntry entry, String childPath, boolean missing, ImmutableMultimap.Builder fileSnapshots) throws IOException { + File propertyRoot = propertySpec.getOutputFile(); + String propertyName = propertySpec.getPropertyName(); + diff --git a/gradle.spec b/gradle.spec index 1936a4899d5455567b040e2203b2ffb3e07807f1..b69497859f576838a515627977399b4084ad3b4f 100644 --- a/gradle.spec +++ b/gradle.spec @@ -1,7 +1,7 @@ %bcond_with bootstrap Name: gradle Version: 4.4.1 -Release: 3 +Release: 4 Summary: Build automation tool License: ASL 2.0 URL: http://www.gradle.org/ @@ -41,6 +41,11 @@ Patch0016: 0016-Port-to-guava-20.0.patch Patch0017: 0017-Set-core-api-source-level-to-8.patch Patch0018: 0018-Use-HTTPS-for-GoogleAPIs-repository.patch Patch0019: CVE-2019-16370.patch +Patch0020: gradle-CVE-2019-15052.patch +Patch0021: gradle-CVE-2021-32751.patch +Patch0022: gradle-CVE-2023-35946.patch +Patch0023: gradle-CVE-2023-35947.patch + BuildRequires: git %if %{with bootstrap} BuildRequires: groovy >= 2.3 javapackages-local @@ -238,6 +243,9 @@ install -p -m 644 man/gradle.1 %{buildroot}%{_mandir}/man1/gradle.1 %license LICENSE NOTICE %changelog +* Tue Aug 12 2025 ShuKun Qu - 4.4.1-4 +- Fix CVE-2019-15052 CVE-2021-32751 CVE-2023-35946 CVE-2023-35947 + * Wed Nov 29 2023 liyanan - 4.4.1-3 - Rebuilt for openEuler-22.03-LTS-SP3