Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MNG-8176] Restrict classloader for Maven 4 plugins #1336

Merged
merged 1 commit into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
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.stream.Collectors;

import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.classrealm.ClassRealmRequest.RealmType;
Expand All @@ -57,6 +59,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.
Expand All @@ -78,12 +82,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<String> providedArtifacts;

private final Set<String> providedArtifactsV4;

@Inject
public DefaultClassRealmManager(
CoreRealm coreRealm, List<ClassRealmManagerDelegate> delegates, CoreExports exports) {
Expand All @@ -101,7 +109,16 @@ public DefaultClassRealmManager(
foreignImports,
null /* artifacts */);

Map<String, ClassLoader> apiV4Imports = new HashMap<>();
apiV4Imports.put("org.apache.maven.api", containerRealm);
apiV4Imports.put("org.slf4j", 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-"))
.collect(Collectors.toSet());
}

private ClassRealm newRealm(String id) {
Expand All @@ -128,6 +145,11 @@ public ClassRealm getMavenApiRealm() {
return mavenApiRealm;
}

@Override
public ClassRealm getMaven4ApiRealm() {
return maven4ApiRealm;
}

/**
* Creates a new class realm with the specified parent and imports.
*
Expand All @@ -150,8 +172,9 @@ private ClassRealm createRealm(
List<ClassRealmConstituent> 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));
Expand Down Expand Up @@ -211,8 +234,9 @@ public ClassRealm createExtensionRealm(Plugin plugin, List<Artifact> 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<String> provided = v4api ? providedArtifactsV4 : providedArtifacts;
return provided.contains(artifact.getGroupId() + ":" + artifact.getArtifactId());
}

public ClassRealm createPluginRealm(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ public void setupPluginRealm(
pluginDescriptor.setClassRealm(pluginRealm);
pluginDescriptor.setArtifacts(pluginArtifacts);
} else {
Map<String, ClassLoader> foreignImports = calcImports(project, parent, imports);
boolean v4api = pluginDescriptor.getMojos().stream().anyMatch(MojoDescriptor::isV4Api);
Map<String, ClassLoader> foreignImports = calcImports(project, parent, imports, v4api);

PluginRealmCache.Key cacheKey = pluginRealmCache.createKey(
plugin,
Expand Down Expand Up @@ -462,14 +463,16 @@ private List<Artifact> toMavenArtifacts(DependencyResult dependencyResult) {
return Collections.unmodifiableList(artifacts);
}

private Map<String, ClassLoader> calcImports(MavenProject project, ClassLoader parent, List<String> imports) {
private Map<String, ClassLoader> calcImports(
MavenProject project, ClassLoader parent, List<String> imports, boolean v4api) {
Map<String, ClassLoader> foreignImports = new HashMap<>();

ClassLoader projectRealm = project.getClassRealm();
if (projectRealm != null) {
foreignImports.put("", projectRealm);
} else {
foreignImports.put("", classRealmManager.getMavenApiRealm());
foreignImports.put(
"", v4api ? classRealmManager.getMaven4ApiRealm() : classRealmManager.getMavenApiRealm());
}

if (parent != null && imports != null) {
Expand Down