mirror of
https://github.com/corda/corda.git
synced 2025-01-01 18:56:44 +00:00
Some modifications to specify custom patching file and some work towards dynamic init with view to re-enabling tests
This commit is contained in:
parent
11aaa018c0
commit
e09c6473ad
@ -30,7 +30,7 @@ dependencies {
|
||||
testImplementation('log4j:apache-log4j-extras:1.2.17') {
|
||||
exclude group: 'log4j', module: 'log4j'
|
||||
}
|
||||
testImplementation group: 'com.ea.agentloader', name: 'ea-agent-loader', version: '1.0.3'
|
||||
// testImplementation group: 'com.ea.agentloader', name: 'ea-agent-loader', version: '1.0.3'
|
||||
testImplementation "com.google.guava:guava:$guava_version"
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,20 @@
|
||||
|
||||
package net.gredler.aegis4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -20,24 +29,48 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public final class AegisAgent {
|
||||
|
||||
private static Instrumentation instrumentation;
|
||||
|
||||
/**
|
||||
* Supports static attach (via -javaagent parameter at JVM startup).
|
||||
*
|
||||
* @param args agent arguments
|
||||
* @param args agent arguments
|
||||
* @param instr instrumentation services
|
||||
*/
|
||||
public static void premain(String args, Instrumentation instr) {
|
||||
Patcher.start(instr, toBlockList(args));
|
||||
instrumentation = instr;
|
||||
if(args.trim().equalsIgnoreCase("dynamic")) return;
|
||||
Path path = null;
|
||||
boolean started = false;
|
||||
for(String arg: args.split(";")) {
|
||||
if(started) throw new IllegalArgumentException("ERROR: argument ordering means patching already started");
|
||||
String normalisedaArg = arg.trim().toLowerCase();
|
||||
if(normalisedaArg.isEmpty() || normalisedaArg.startsWith("block=") || normalisedaArg.startsWith("unblock=")) {
|
||||
try {
|
||||
Patcher.start(instr, toBlockList(normalisedaArg, path), getModificationsInputStream(path));
|
||||
started = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if(normalisedaArg.startsWith("path=")) {
|
||||
path= Paths.get(arg.trim().substring(5));
|
||||
}
|
||||
}
|
||||
if(!started) throw new IllegalArgumentException("ERROR: patching not started");
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports dynamic attach (via the com.sun.tools.attach.* API).
|
||||
*
|
||||
* @param args agent arguments
|
||||
* @param args agent arguments
|
||||
* @param instr instrumentation services
|
||||
*/
|
||||
public static void agentmain(String args, Instrumentation instr) {
|
||||
Patcher.start(instr, toBlockList(args));
|
||||
premain(args, instr);
|
||||
}
|
||||
|
||||
static void dynamicLoad(String args) {
|
||||
agentmain(args, instrumentation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,9 +80,8 @@ public final class AegisAgent {
|
||||
* @param args agent arguments
|
||||
* @return the block list derived from the agent arguments
|
||||
*/
|
||||
protected static Set< String > toBlockList(String args) {
|
||||
|
||||
Set< String > all = new HashSet<String>(Arrays.<String>asList("jndi", "rmi", "process", "httpserver", "serialization", "unsafe", "scripting", "jshell"));
|
||||
protected static Set<String> toBlockList(String args, Path path) {
|
||||
Set<String> all = loadFeaturesFromModifications(path);
|
||||
if (args == null || args.trim().isEmpty()) {
|
||||
// no arguments provided by user
|
||||
return all;
|
||||
@ -70,8 +102,8 @@ public final class AegisAgent {
|
||||
return split(value, all);
|
||||
} else if ("unblock".equals(name)) {
|
||||
// user is modifying the default block list
|
||||
Set< String > block = new HashSet<>(all);
|
||||
Set< String > unblock = split(value, all);
|
||||
Set<String> block = new HashSet<>(all);
|
||||
Set<String> unblock = split(value, all);
|
||||
block.removeAll(unblock);
|
||||
return Collections.unmodifiableSet(block);
|
||||
} else {
|
||||
@ -84,16 +116,15 @@ public final class AegisAgent {
|
||||
* Splits the specified comma-delimited feature list, validating that all specified features are valid.
|
||||
*
|
||||
* @param values the comma-delimited feature list
|
||||
* @param all the list of valid features to validate against
|
||||
* @param all the list of valid features to validate against
|
||||
* @return the feature list, split into individual (validated) feature names
|
||||
* @throws IllegalArgumentException if any unrecognized feature names are included in the comma-delimited feature list
|
||||
*/
|
||||
private static Set< String > split(String values, Set< String > all) {
|
||||
|
||||
Set< String > features = Arrays.asList(values.split(","))
|
||||
.stream()
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toSet());
|
||||
private static Set<String> split(String values, Set<String> all) {
|
||||
Set<String> features = Arrays.asList(values.split(","))
|
||||
.stream()
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
for (String feature : features) {
|
||||
if (!all.contains(feature)) {
|
||||
@ -103,4 +134,25 @@ public final class AegisAgent {
|
||||
|
||||
return Collections.unmodifiableSet(features);
|
||||
}
|
||||
|
||||
private static Set<String> loadFeaturesFromModifications(Path path) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(getModificationsInputStream(path));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Set<String> features = new HashSet<String>();
|
||||
for (String key : props.stringPropertyNames()) {
|
||||
int first = key.indexOf('.');
|
||||
String feature = key.substring(0, first).toLowerCase();
|
||||
features.add(feature);
|
||||
}
|
||||
return Collections.unmodifiableSet(features);
|
||||
}
|
||||
|
||||
public static InputStream getModificationsInputStream(Path path) throws IOException {
|
||||
if(path != null) return path.toUri().toURL().openStream();
|
||||
return AegisAgent.class.getResourceAsStream("mods.properties");
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
package net.gredler.aegis4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.instrument.UnmodifiableClassException;
|
||||
@ -31,15 +32,15 @@ import javassist.NotFoundException;
|
||||
*/
|
||||
public final class Patcher implements ClassFileTransformer {
|
||||
|
||||
private final Map< String, List< Modification > > modifications; // class name -> modifications
|
||||
private final Map<String, List<Modification>> modifications; // class name -> modifications
|
||||
|
||||
/**
|
||||
* Creates a new class patcher which blocks the specified features.
|
||||
*
|
||||
* @param block the features to block
|
||||
*/
|
||||
public Patcher(Set< String > block) {
|
||||
modifications = loadModifications(block);
|
||||
public Patcher(Set<String> block, InputStream inputStream) {
|
||||
modifications = loadModifications(inputStream, block);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,16 +49,15 @@ public final class Patcher implements ClassFileTransformer {
|
||||
* @param instr the instrumentation instance to add a new patcher to
|
||||
* @param block the features to block
|
||||
*/
|
||||
public static void start(Instrumentation instr, Set< String > block) {
|
||||
|
||||
public static void start(Instrumentation instr, Set<String> block, InputStream inputStream) {
|
||||
System.out.println("Aegis4j patching starting");
|
||||
Patcher patcher = new Patcher(block);
|
||||
Patcher patcher = new Patcher(block ,inputStream);
|
||||
instr.addTransformer(patcher, true);
|
||||
|
||||
for (String className : patcher.modifications.keySet()) {
|
||||
try {
|
||||
System.out.println("Aegis4j patching " + className + "...");
|
||||
Class< ? > clazz = Class.forName(className);
|
||||
Class<?> clazz = Class.forName(className);
|
||||
instr.retransformClasses(clazz);
|
||||
} catch (ClassNotFoundException | UnmodifiableClassException e) {
|
||||
e.printStackTrace();
|
||||
@ -69,13 +69,12 @@ public final class Patcher implements ClassFileTransformer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(ClassLoader loader, String className, Class< ? > clazz, ProtectionDomain domain, byte[] classBytes) {
|
||||
public byte[] transform(ClassLoader loader, String className, Class<?> clazz, ProtectionDomain domain, byte[] classBytes) {
|
||||
return patch(className.replace('/', '.'), classBytes);
|
||||
}
|
||||
|
||||
private byte[] patch(String className, byte[] classBytes) {
|
||||
|
||||
List< Modification > mods = modifications.get(className);
|
||||
List<Modification> mods = modifications.get(className);
|
||||
if (mods == null || mods.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@ -109,16 +108,15 @@ public final class Patcher implements ClassFileTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private static Map< String, List< Modification > > loadModifications(Set< String > block) {
|
||||
|
||||
private static Map<String, List<Modification>> loadModifications(InputStream inputStream, Set<String> block) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(AegisAgent.class.getResourceAsStream("mods.properties"));
|
||||
props.load(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
List< Modification > mods = new ArrayList<>();
|
||||
List<Modification> mods = new ArrayList<>();
|
||||
for (String key : props.stringPropertyNames()) {
|
||||
int first = key.indexOf('.');
|
||||
int last = key.lastIndexOf('.');
|
||||
@ -133,7 +131,7 @@ public final class Patcher implements ClassFileTransformer {
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(new TreeMap<>(
|
||||
mods.stream().collect(Collectors.groupingBy(mod -> mod.className, Collectors.toList()))
|
||||
mods.stream().collect(Collectors.groupingBy(mod -> mod.className, Collectors.toList()))
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,8 @@ public class AegisAgentCommandLineTest {
|
||||
testStaticAttach(jar, "block=jndi", "");
|
||||
testStaticAttach(jar, "unblock=serialization", "");
|
||||
testStaticAttach(jar, "block=serialization", "Java serialization blocked by aegis4j");
|
||||
testStaticAttach(jar, "block=serialization;", "Java serialization blocked by aegis4j");
|
||||
testStaticAttach(jar, ";block=serialization", "ERROR: argument ordering means patching already started");
|
||||
}
|
||||
|
||||
private static void testStaticAttach(String jar, String config, String expectedErr) throws Exception {
|
||||
|
@ -20,7 +20,6 @@ import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import com.ea.agentloader.AgentLoader;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
@ -136,7 +135,8 @@ public final class TestUtils {
|
||||
jvm.loadAgent(createAgentJar(), options);
|
||||
jvm.detach();
|
||||
*/
|
||||
AgentLoader.loadAgentClass(AegisAgent.class.getName(), options);
|
||||
//AgentLoader.loadAgentClass(AegisAgent.class.getName(), options);
|
||||
AegisAgent.dynamicLoad(options);
|
||||
}
|
||||
|
||||
public static byte[] inputStreamReadAllBytes(InputStream stream) throws IOException {
|
||||
|
Loading…
Reference in New Issue
Block a user