From a9d0d2cbbeb8718194040ce2b9cc0f789bd3218b Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Mon, 5 Aug 2019 10:41:05 -0400 Subject: [PATCH] Use CodeSource instead of javaagent arg Check both TracingAgent.class and DatadogClassloader.class for code source --- .../trace/bootstrap/DatadogClassLoader.java | 14 ++- .../datadog/trace/agent/TracingAgent.java | 99 ++++--------------- 2 files changed, 26 insertions(+), 87 deletions(-) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java index c5717a82fa..3ba40d6e17 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java @@ -117,12 +117,16 @@ public class DatadogClassLoader extends URLClassLoader { } } - private static class InternalJarURLHandler extends URLStreamHandler { + protected static class InternalJarURLHandler extends URLStreamHandler { private final Map filenameToBytes = new HashMap<>(); public InternalJarURLHandler( final String internalJarFileName, final ClassLoader classloaderForJarResource) { + // "/" is used as the default url of the jar + // This is called by the SecureClassLoader trying to obtain permissions + filenameToBytes.put("/", new byte[] {}); + final InputStream jarStream = classloaderForJarResource.getResourceAsStream(internalJarFileName); @@ -146,12 +150,6 @@ public class DatadogClassLoader extends URLClassLoader { @Override protected URLConnection openConnection(final URL url) throws IOException { - if (url.getFile().equals("/")) { - // "/" is used as the default url of the jar - // This is called by the SecureClassLoader trying to obtain permissions - return new InternalJarURLConnection(url, new byte[] {}); - } - final byte[] bytes = filenameToBytes.get(url.getFile()); if (bytes == null) { @@ -162,7 +160,7 @@ public class DatadogClassLoader extends URLClassLoader { } } - private static class InternalJarURLConnection extends URLConnection { + protected static class InternalJarURLConnection extends URLConnection { private final byte[] bytes; private InternalJarURLConnection(final URL url, final byte[] bytes) { diff --git a/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java b/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java index 066b24d9c2..5aafaee767 100644 --- a/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java +++ b/dd-java-agent/src/main/java/datadog/trace/agent/TracingAgent.java @@ -5,20 +5,14 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.lang.instrument.Instrumentation; -import java.lang.management.ManagementFactory; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; +import java.security.CodeSource; import java.util.jar.JarFile; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** Entry point for initializing the agent. */ public class TracingAgent { @@ -157,86 +151,33 @@ public class TracingAgent { private static synchronized URL installBootstrapJar( final Instrumentation inst, final boolean usingCustomLogManager) - throws IOException, URISyntaxException { + throws IOException, URISyntaxException, ClassNotFoundException { URL bootstrapURL = null; - final List arguments; + File bootstrapFile = null; - // ManagementFactory indirectly references java.util.logging.LogManager - // - On Oracle-based JDKs after 1.8 - // - On IBM-based JDKs since at least 1.7 - // This prevents custom log managers from working correctly - // Use reflection to bypass the loading of the class - if (usingCustomLogManager) { - System.out.println("Custom log manager detected: getting vm args through reflection"); - arguments = getVMArgumentsThroughReflection(); - } else { - arguments = ManagementFactory.getRuntimeMXBean().getInputArguments(); + final CodeSource codeSource = TracingAgent.class.getProtectionDomain().getCodeSource(); + if (codeSource != null) { + bootstrapURL = codeSource.getLocation(); + + bootstrapFile = new File(bootstrapURL.toURI()); } - for (final String arg : arguments) { - if (arg.startsWith("-javaagent")) { - // argument is of the form -javaagent:/path/to/dd-java-agent.jar=optionalargumentstring - final Matcher matcher = Pattern.compile("-javaagent:([^=]+).*").matcher(arg); + if (bootstrapFile == null || bootstrapFile.isDirectory()) { + // At most one of ( DatadogClassLoader.class , TracingAgent.class ) has a CodeSource that + // doesn't lead to the agent jar - if (!matcher.matches()) { - throw new RuntimeException("Unable to parse javaagent parameter: " + arg); - } + bootstrapURL = + ClassLoader.getSystemClassLoader() + .loadClass("datadog.trace.bootstrap.DatadogClassLoader") + .getProtectionDomain() + .getCodeSource() + .getLocation(); - try { - bootstrapURL = new URL("file:" + matcher.group(1)); - - } catch (final MalformedURLException e) { - throw new RuntimeException("Malformed javaagent parameter: " + arg); - } - } + bootstrapFile = new File(bootstrapURL.toURI()); } - if (bootstrapURL != null) { - inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(bootstrapURL.toURI()))); - return bootstrapURL; - } else { - throw new RuntimeException( - "Unable to install bootstrap jar. -javaagent parameter not parsable"); - } - } - - private static List getVMArgumentsThroughReflection() { - try { - // Try Oracle-based - final Class managementFactoryHelperClass = - TracingAgent.class.getClassLoader().loadClass("sun.management.ManagementFactoryHelper"); - - final Class vmManagementClass = - TracingAgent.class.getClassLoader().loadClass("sun.management.VMManagement"); - - Object vmManagement; - - try { - vmManagement = - managementFactoryHelperClass.getDeclaredMethod("getVMManagement").invoke(null); - } catch (final NoSuchMethodException e) { - // Older vm before getVMManagement() existed - final Field field = managementFactoryHelperClass.getDeclaredField("jvm"); - field.setAccessible(true); - vmManagement = field.get(null); - field.setAccessible(false); - } - - return (List) vmManagementClass.getMethod("getVmArguments").invoke(vmManagement); - - } catch (final ReflectiveOperationException e) { - try { // Try IBM-based. - final Class VMClass = TracingAgent.class.getClassLoader().loadClass("com.ibm.oti.vm.VM"); - final String[] argArray = (String[]) VMClass.getMethod("getVMArgs").invoke(null); - return Arrays.asList(argArray); - } catch (final ReflectiveOperationException e1) { - // Fallback to default - System.out.println( - "WARNING: Unable to get VM args through reflection. A custom java.util.logging.LogManager may not work correctly"); - - return ManagementFactory.getRuntimeMXBean().getInputArguments(); - } - } + inst.appendToBootstrapClassLoaderSearch(new JarFile(bootstrapFile)); + return bootstrapURL; } /**