From 9955de3a30a4a9a8b9f39028d4b6d7f61488aa46 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 7 Dec 2023 09:24:53 +0100 Subject: [PATCH] Restrict classloader for Maven 4 plugins --- .../maven/classrealm/ClassRealmManager.java | 7 ++++ .../classrealm/DefaultClassRealmManager.java | 40 ++++++++++++++----- .../resources/META-INF/maven/extension.xml | 3 ++ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java index b0386f040ba2..689aa6200316 100644 --- a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java +++ b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java @@ -48,6 +48,13 @@ public interface ClassRealmManager { */ ClassRealm getMavenApiRealm(); + /** + * Gets the class realm exposing the Maven 4 API. This is basically a restricted view on the Maven core realm. + * + * @return The class realm exposing the Maven API, never {@code null}. + */ + ClassRealm getMaven4ApiRealm(); + /** * Creates a new class realm for the specified project and its build extensions. * diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java index 512e7cae8f51..5d31bc025bd8 100644 --- a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java +++ b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java @@ -24,14 +24,8 @@ import java.io.File; import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Random; -import java.util.Set; -import java.util.TreeMap; +import java.util.*; +import java.util.stream.Collectors; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.classrealm.ClassRealmRequest.RealmType; @@ -58,6 +52,8 @@ public class DefaultClassRealmManager implements ClassRealmManager { public static final String API_REALMID = "maven.api"; + public static final String API_V4_REALMID = "maven.api.v4"; + /** * During normal command line build, ClassWorld is loaded by jvm system classloader, which only includes * plexus-classworlds jar and possibly javaagent classes, see https://issues.apache.org/jira/browse/MNG-4747. @@ -79,12 +75,16 @@ public class DefaultClassRealmManager implements ClassRealmManager { private final ClassRealm mavenApiRealm; + private final ClassRealm maven4ApiRealm; + /** * Patterns of artifacts provided by maven core and exported via maven api realm. These artifacts are filtered from * plugin and build extensions realms to avoid presence of duplicate and possibly conflicting classes on classpath. */ private final Set providedArtifacts; + private final Set providedArtifactsV4; + @Inject public DefaultClassRealmManager( PlexusContainer container, List delegates, CoreExports exports) { @@ -102,7 +102,18 @@ public DefaultClassRealmManager( foreignImports, null /* artifacts */); + Map apiV4Imports = new HashMap<>(); + apiV4Imports.put("org.apache.maven.api", containerRealm); + apiV4Imports.put("org.slf4j", containerRealm); + apiV4Imports.put("jakarta.inject.*", containerRealm); + this.maven4ApiRealm = createRealm(API_V4_REALMID, RealmType.Core, null, null, apiV4Imports, null); + this.providedArtifacts = exports.getExportedArtifacts(); + + this.providedArtifactsV4 = providedArtifacts.stream() + .filter(ga -> + ga.startsWith("org.apache.maven:maven-api-") || ga.equals("jakarta.inject:jakarta.inject-api")) + .collect(Collectors.toSet()); } private ClassRealm newRealm(String id) { @@ -129,6 +140,11 @@ public ClassRealm getMavenApiRealm() { return mavenApiRealm; } + @Override + public ClassRealm getMaven4ApiRealm() { + return maven4ApiRealm; + } + /** * Creates a new class realm with the specified parent and imports. * @@ -151,8 +167,9 @@ private ClassRealm createRealm( List constituents = new ArrayList<>(artifacts == null ? 0 : artifacts.size()); if (artifacts != null && !artifacts.isEmpty()) { + boolean v4api = foreignImports != null && foreignImports.containsValue(maven4ApiRealm); for (Artifact artifact : artifacts) { - if (!isProvidedArtifact(artifact) && artifact.getFile() != null) { + if (!isProvidedArtifact(artifact, v4api) && artifact.getFile() != null) { constituents.add(new ArtifactClassRealmConstituent(artifact)); } else if (logger.isDebugEnabled()) { logger.debug(" Excluded: {}", getId(artifact)); @@ -212,8 +229,9 @@ public ClassRealm createExtensionRealm(Plugin plugin, List artifacts) getKey(plugin, true), RealmType.Extension, PARENT_CLASSLOADER, null, foreignImports, artifacts); } - private boolean isProvidedArtifact(Artifact artifact) { - return providedArtifacts.contains(artifact.getGroupId() + ":" + artifact.getArtifactId()); + private boolean isProvidedArtifact(Artifact artifact, boolean v4api) { + Set provided = v4api ? providedArtifactsV4 : providedArtifacts; + return provided.contains(artifact.getGroupId() + ":" + artifact.getArtifactId()); } public ClassRealm createPluginRealm( diff --git a/maven-core/src/main/resources/META-INF/maven/extension.xml b/maven-core/src/main/resources/META-INF/maven/extension.xml index 1823336d837c..2cb0bd188fd7 100644 --- a/maven-core/src/main/resources/META-INF/maven/extension.xml +++ b/maven-core/src/main/resources/META-INF/maven/extension.xml @@ -143,7 +143,9 @@ under the License. org.apache.maven:maven-api-core org.apache.maven:maven-api-meta org.apache.maven:maven-api-model + org.apache.maven:maven-api-plugin org.apache.maven:maven-api-settings + org.apache.maven:maven-api-spi org.apache.maven:maven-api-toolchain org.apache.maven:maven-api-xml @@ -187,6 +189,7 @@ under the License. org.apache.maven.resolver:maven-resolver-util org.apache.maven.resolver:maven-resolver-connector-basic + jakarta.inject:jakarta.inject-api javax.inject:javax.inject javax.annotation:javax.annotation-api org.slf4j:slf4j-api