From d4df2f6ed7564a44b0aca31463da6013e867bd29 Mon Sep 17 00:00:00 2001 From: ReaJason Date: Thu, 22 May 2025 22:03:47 +0800 Subject: [PATCH] feat: support AgentAttacher Packer --- generator/build.gradle | 3 + .../reajason/javaweb/memshell/Packers.java | 4 + .../jar/AgentJarWithJDKAttacherPacker.java | 189 ++ .../jar/AgentJarWithJREAttacherPacker.java | 209 ++ .../memshell/packer/jar/attach/Attacher.java | 942 ++++++ .../packer/jar/attach/VirtualMachine.java | 2888 +++++++++++++++++ .../javaweb/memshell/utils/CommonUtil.java | 4 + .../win32-x86-64/attach_hotspot_windows.dll | Bin 0 -> 301843 bytes .../win32-x86/attach_hotspot_windows.dll | Bin 0 -> 250930 bytes .../integration/ShellAssertionTool.java | 27 +- .../integration/TestCasesProvider.java | 29 +- .../memshell-agent-attacher/build.gradle | 33 + .../src/main/c/attach_hotspot_windows.c | 130 + .../src/main/java/Agent.java | 15 + .../src/main/java/Attacher.java | 931 ++++++ .../src/main/java/Main.java | 9 + .../src/main/java/VirtualMachine.java | 2888 +++++++++++++++++ .../win32-x86-64/attach_hotspot_windows.dll | Bin 0 -> 301843 bytes .../win32-x86/attach_hotspot_windows.dll | Bin 0 -> 250930 bytes memshell-party-bom/build.gradle | 3 + .../javaweb/buddy/ClassRenameUtils.java | 56 + settings.gradle | 4 +- web/src/i18n/en.json | 4 +- web/src/i18n/zh-CN.json | 4 +- 24 files changed, 8361 insertions(+), 11 deletions(-) create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJDKAttacherPacker.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJREAttacherPacker.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/Attacher.java create mode 100644 generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/VirtualMachine.java create mode 100755 generator/src/main/resources/win32-x86-64/attach_hotspot_windows.dll create mode 100755 generator/src/main/resources/win32-x86/attach_hotspot_windows.dll create mode 100644 memshell-agent/memshell-agent-attacher/build.gradle create mode 100644 memshell-agent/memshell-agent-attacher/src/main/c/attach_hotspot_windows.c create mode 100644 memshell-agent/memshell-agent-attacher/src/main/java/Agent.java create mode 100644 memshell-agent/memshell-agent-attacher/src/main/java/Attacher.java create mode 100644 memshell-agent/memshell-agent-attacher/src/main/java/Main.java create mode 100644 memshell-agent/memshell-agent-attacher/src/main/java/VirtualMachine.java create mode 100755 memshell-agent/memshell-agent-attacher/src/main/resources/win32-x86-64/attach_hotspot_windows.dll create mode 100755 memshell-agent/memshell-agent-attacher/src/main/resources/win32-x86/attach_hotspot_windows.dll create mode 100644 memshell-party-common/src/main/java/com/reajason/javaweb/buddy/ClassRenameUtils.java diff --git a/generator/build.gradle b/generator/build.gradle index fd4a580e..fcfd72d5 100644 --- a/generator/build.gradle +++ b/generator/build.gradle @@ -39,6 +39,9 @@ dependencies { implementation 'net.bytebuddy:byte-buddy' implementation 'org.ow2.asm:asm-commons' + implementation 'net.java.dev.jna:jna' + implementation 'net.java.dev.jna:jna-platform' + implementation 'javax.servlet:javax.servlet-api' implementation 'javax.websocket:javax.websocket-api' diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java b/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java index 2616c34f..b2861300 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/Packers.java @@ -19,6 +19,8 @@ import com.reajason.javaweb.memshell.packer.groovy.GroovyClassDefinerPacker; import com.reajason.javaweb.memshell.packer.groovy.GroovyPacker; import com.reajason.javaweb.memshell.packer.groovy.GroovyScriptEnginePacker; import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker; +import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJDKAttacherPacker; +import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJREAttacherPacker; import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker; import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker; import com.reajason.javaweb.memshell.packer.jinjava.JinJavaPacker; @@ -121,6 +123,8 @@ public enum Packers { HessianXSLTScriptEngine(new HessianXSLTScriptEnginePacker(), HessianPacker.class), AgentJar(new AgentJarPacker()), + AgentJarWithJDKAttacher(new AgentJarWithJDKAttacherPacker()), + AgentJarWithJREAttacher(new AgentJarWithJREAttacherPacker()), XxlJob(new XxlJobPacker()), ; diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJDKAttacherPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJDKAttacherPacker.java new file mode 100644 index 00000000..a36110ad --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJDKAttacherPacker.java @@ -0,0 +1,189 @@ +package com.reajason.javaweb.memshell.packer.jar; + +import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.jar.attach.Attacher; +import com.reajason.javaweb.memshell.packer.jar.attach.VirtualMachine; +import com.reajason.javaweb.memshell.utils.CommonUtil; +import lombok.SneakyThrows; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.objectweb.asm.Opcodes; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.*; + +/** + * @author ReaJason + * @since 2025/1/1 + */ +public class AgentJarWithJDKAttacherPacker implements JarPacker { + private static Path tempBootPath; + + @Override + @SneakyThrows + public byte[] packBytes(GenerateResult generateResult) { + String packageName = CommonUtil.getPackageName(generateResult.getInjectorClassName()); + String mainClassName = packageName + "." + Attacher.class.getSimpleName(); + Manifest manifest = createManifest(generateResult.getInjectorClassName(), mainClassName); + String relocatePrefix = "shade/"; + + Map classes = new HashMap<>(); + Map attacherClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(Attacher.class, packageName); + Map virtualMachineClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(VirtualMachine.class, packageName); + classes.putAll(attacherClasses); + classes.putAll(virtualMachineClasses); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) { + addDependencies(targetJar, relocatePrefix); + addClassesToJar(targetJar, generateResult, relocatePrefix); + for (Map.Entry entry : classes.entrySet()) { + String className = entry.getKey(); + byte[] bytes = entry.getValue(); + targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class")); + targetJar.write(bytes); + targetJar.closeEntry(); + } + } + return outputStream.toByteArray(); + } + + private Manifest createManifest(String agentClass, String mainClass) { + Manifest manifest = new Manifest(); + Attributes attributes = manifest.getMainAttributes(); + attributes.putValue("Manifest-Version", "1.0"); + attributes.putValue("Agent-Class", agentClass); + attributes.putValue("Premain-Class", agentClass); + attributes.putValue("Main-Class", mainClass); + attributes.putValue("Can-Redefine-Classes", "true"); + attributes.putValue("Can-Retransform-Classes", "true"); + return manifest; + } + + @SneakyThrows + private void addDependencies(JarOutputStream targetJar, String relocatePrefix) { + String baseName = Opcodes.class.getPackage().getName().replace('.', '/'); + addDependency(targetJar, Opcodes.class, baseName, relocatePrefix); + } + + @SneakyThrows + private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult, String relocatePrefix) { + String dependencyPackage = Opcodes.class.getPackage().getName(); + // Add injector class + addClassEntry(targetJar, + generateResult.getInjectorClassName(), + generateResult.getInjectorBytes(), + dependencyPackage, + relocatePrefix); + + // Add shell class + addClassEntry(targetJar, + generateResult.getShellClassName(), + generateResult.getShellBytes(), + dependencyPackage, + relocatePrefix); + + // Add inner classes + for (Map.Entry entry : generateResult.getInjectorInnerClassBytes().entrySet()) { + addClassEntry(targetJar, + entry.getKey(), + entry.getValue(), + dependencyPackage, + relocatePrefix); + } + } + + @SneakyThrows + private void addClassEntry(JarOutputStream targetJar, String className, byte[] classBytes, + String dependencyPackage, String relocatePrefix) { + targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class")); + byte[] processedBytes = ClassRenameUtils.relocateClass(classBytes, dependencyPackage, relocatePrefix + dependencyPackage); + targetJar.write(processedBytes); + targetJar.closeEntry(); + } + + @SneakyThrows + public static void addDependency(JarOutputStream targetJar, Class baseClass, String baseName, String relocatePrefix) { + URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation(); + String sourceUrlString = sourceUrl.toString(); + if (sourceUrlString.contains("!BOOT-INF")) { + String path = sourceUrlString.substring("jar:nested:".length()); + path = path.substring(0, path.indexOf("!/")); + String[] split = path.split("/!"); + String bootJarPath = split[0]; + String internalJarPath = split[1]; + if (tempBootPath == null) { + tempBootPath = Files.createTempDirectory("mem-shell-boot"); + unzip(bootJarPath, tempBootPath.toFile().getAbsolutePath()); + } + sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL(); + } + try (JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()))) { + Enumeration entries = sourceJar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + if (entryName.equals("META-INF/MANIFEST.MF") + || entryName.contains("module-info.class")) { + continue; + } + if (!entry.isDirectory()) { + try (InputStream entryStream = sourceJar.getInputStream(entry)) { + byte[] bytes = IOUtils.toByteArray(entryStream); + if (StringUtils.isNoneEmpty(relocatePrefix)) { + targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName)); + if (entryName.endsWith(".class")) { + if (bytes.length > 0) { + bytes = ClassRenameUtils.relocateClass(bytes, baseName, relocatePrefix + baseName); + } + } else { + targetJar.putNextEntry(entry); + } + } else { + targetJar.putNextEntry(entry); + } + targetJar.write(bytes); + } + } + targetJar.closeEntry(); + } + } + } + + /** + * Extracts a JAR file to a temporary directory + * + * @param jarPath Path to the source JAR file + * @param tempPath Path to the temporary directory + */ + @SneakyThrows + public static void unzip(String jarPath, String tempPath) { + try (JarFile jarFile = new JarFile(jarPath)) { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry jarEntry = entries.nextElement(); + File targetFile = new File(tempPath, jarEntry.getName()); + + if (jarEntry.isDirectory()) { + targetFile.mkdirs(); + continue; + } + + targetFile.getParentFile().mkdirs(); + try (InputStream inputStream = jarFile.getInputStream(jarEntry); + FileOutputStream outputStream = new FileOutputStream(targetFile)) { + IOUtils.copy(inputStream, outputStream); + } + } + } + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJREAttacherPacker.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJREAttacherPacker.java new file mode 100644 index 00000000..0c7cc65b --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarWithJREAttacherPacker.java @@ -0,0 +1,209 @@ +package com.reajason.javaweb.memshell.packer.jar; + +import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.memshell.config.GenerateResult; +import com.reajason.javaweb.memshell.packer.jar.attach.Attacher; +import com.reajason.javaweb.memshell.packer.jar.attach.VirtualMachine; +import com.reajason.javaweb.memshell.utils.CommonUtil; +import com.sun.jna.Platform; +import com.sun.jna.platform.DesktopWindow; +import lombok.SneakyThrows; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.objectweb.asm.Opcodes; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.*; + +/** + * @author ReaJason + * @since 2025/1/1 + */ +public class AgentJarWithJREAttacherPacker implements JarPacker { + private static Path tempBootPath; + + @Override + @SneakyThrows + public byte[] packBytes(GenerateResult generateResult) { + String packageName = CommonUtil.getPackageName(generateResult.getInjectorClassName()); + String mainClassName = packageName + "." + Attacher.class.getSimpleName(); + Manifest manifest = createManifest(generateResult.getInjectorClassName(), mainClassName); + String relocatePrefix = "shade/"; + + Map classes = new HashMap<>(); + Map attacherClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(Attacher.class, packageName); + Map virtualMachineClasses = com.reajason.javaweb.buddy.ClassRenameUtils.renamePackage(VirtualMachine.class, packageName); + classes.putAll(attacherClasses); + classes.putAll(virtualMachineClasses); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) { + addDependencies(targetJar, relocatePrefix); + addClassesToJar(targetJar, generateResult, relocatePrefix); + for (Map.Entry entry : classes.entrySet()) { + String className = entry.getKey(); + byte[] bytes = entry.getValue(); + targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class")); + targetJar.write(bytes); + targetJar.closeEntry(); + } + + String[] windowsDll = new String[]{ + "win32-x86/attach_hotspot_windows.dll", + "win32-x86-64/attach_hotspot_windows.dll" + }; + for (String dll : windowsDll) { + InputStream stream = this.getClass().getClassLoader().getResourceAsStream(dll); + if (stream != null) { + byte[] bytes = IOUtils.toByteArray(stream); + targetJar.putNextEntry(new JarEntry(dll)); + targetJar.write(bytes); + targetJar.closeEntry(); + } + } + } + return outputStream.toByteArray(); + } + + private Manifest createManifest(String agentClass, String mainClass) { + Manifest manifest = new Manifest(); + Attributes attributes = manifest.getMainAttributes(); + attributes.putValue("Manifest-Version", "1.0"); + attributes.putValue("Agent-Class", agentClass); + attributes.putValue("Premain-Class", agentClass); + attributes.putValue("Main-Class", mainClass); + attributes.putValue("Can-Redefine-Classes", "true"); + attributes.putValue("Can-Retransform-Classes", "true"); + return manifest; + } + + @SneakyThrows + private void addDependencies(JarOutputStream targetJar, String relocatePrefix) { + String baseName = Opcodes.class.getPackage().getName().replace('.', '/'); + addDependency(targetJar, Opcodes.class, baseName, relocatePrefix); + + String jnaBaseName = Platform.class.getPackage().getName().replace('.', '/'); + addDependency(targetJar, Platform.class, jnaBaseName, null); + addDependency(targetJar, DesktopWindow.class, jnaBaseName, null); + } + + @SneakyThrows + private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult, String relocatePrefix) { + String dependencyPackage = Opcodes.class.getPackage().getName(); + // Add injector class + addClassEntry(targetJar, + generateResult.getInjectorClassName(), + generateResult.getInjectorBytes(), + dependencyPackage, + relocatePrefix); + + // Add shell class + addClassEntry(targetJar, + generateResult.getShellClassName(), + generateResult.getShellBytes(), + dependencyPackage, + relocatePrefix); + + // Add inner classes + for (Map.Entry entry : generateResult.getInjectorInnerClassBytes().entrySet()) { + addClassEntry(targetJar, + entry.getKey(), + entry.getValue(), + dependencyPackage, + relocatePrefix); + } + } + + @SneakyThrows + private void addClassEntry(JarOutputStream targetJar, String className, byte[] classBytes, + String dependencyPackage, String relocatePrefix) { + targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class")); + byte[] processedBytes = ClassRenameUtils.relocateClass(classBytes, dependencyPackage, relocatePrefix + dependencyPackage); + targetJar.write(processedBytes); + targetJar.closeEntry(); + } + + @SneakyThrows + public static void addDependency(JarOutputStream targetJar, Class baseClass, String baseName, String relocatePrefix) { + URL sourceUrl = baseClass.getProtectionDomain().getCodeSource().getLocation(); + String sourceUrlString = sourceUrl.toString(); + if (sourceUrlString.contains("!BOOT-INF")) { + String path = sourceUrlString.substring("jar:nested:".length()); + path = path.substring(0, path.indexOf("!/")); + String[] split = path.split("/!"); + String bootJarPath = split[0]; + String internalJarPath = split[1]; + if (tempBootPath == null) { + tempBootPath = Files.createTempDirectory("mem-shell-boot"); + unzip(bootJarPath, tempBootPath.toFile().getAbsolutePath()); + } + sourceUrl = tempBootPath.resolve(internalJarPath).toUri().toURL(); + } + try (JarFile sourceJar = new JarFile(new File(sourceUrl.toURI()))) { + Enumeration entries = sourceJar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + if (entryName.startsWith("META-INF") + || entryName.contains("module-info.class")) { + continue; + } + if (!entry.isDirectory()) { + try (InputStream entryStream = sourceJar.getInputStream(entry)) { + byte[] bytes = IOUtils.toByteArray(entryStream); + if (StringUtils.isNoneEmpty(relocatePrefix)) { + targetJar.putNextEntry(new JarEntry(relocatePrefix + entryName)); + if (entryName.endsWith(".class")) { + if (bytes.length > 0) { + bytes = ClassRenameUtils.relocateClass(bytes, baseName, relocatePrefix + baseName); + } + } else { + targetJar.putNextEntry(entry); + } + } else { + targetJar.putNextEntry(entry); + } + targetJar.write(bytes); + } + } + targetJar.closeEntry(); + } + } + } + + /** + * Extracts a JAR file to a temporary directory + * + * @param jarPath Path to the source JAR file + * @param tempPath Path to the temporary directory + */ + @SneakyThrows + public static void unzip(String jarPath, String tempPath) { + try (JarFile jarFile = new JarFile(jarPath)) { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry jarEntry = entries.nextElement(); + File targetFile = new File(tempPath, jarEntry.getName()); + + if (jarEntry.isDirectory()) { + targetFile.mkdirs(); + continue; + } + + targetFile.getParentFile().mkdirs(); + try (InputStream inputStream = jarFile.getInputStream(jarEntry); + FileOutputStream outputStream = new FileOutputStream(targetFile)) { + IOUtils.copy(inputStream, outputStream); + } + } + } + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/Attacher.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/Attacher.java new file mode 100644 index 00000000..43b4447f --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/Attacher.java @@ -0,0 +1,942 @@ +package com.reajason.javaweb.memshell.packer.jar.attach;/* + * Copyright 2014 - Present Rafael Winterhalter + * + * 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. + */ + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.CodeSource; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Copy from Byte Buddy + */ +public class Attacher { + + /** + * Representation of the bootstrap {@link ClassLoader}. + */ + private static final ClassLoader BOOTSTRAP_CLASS_LOADER = null; + + /** + * The character that is used to mark the beginning of the argument to the agent. + */ + private static final String AGENT_ARGUMENT_SEPARATOR = "="; + + /** + * The agent provides only {@code static} utility methods and should not be instantiated. + */ + private Attacher() { + throw new UnsupportedOperationException("This class is a utility class and not supposed to be instantiated"); + } + + public static void main(String[] args) throws Exception { + try { + Attacher.attach(args[0]); + } catch (Exception e) { + if (!e.getMessage().equals("0")) { + throw e; + } + } + System.out.println("ok"); + } + + /** + *

+ * Attaches the given agent Jar on the target process which must be a virtual machine process. The default attachment provider + * is used for applying the attachment. This operation blocks until the attachment is complete. If the current VM does not supply + * any known form of attachment to a remote VM, an {@link IllegalStateException} is thrown. The agent is not provided an argument. + *

+ *

+ * Important: It is only possible to attach to processes that are executed by the same operating system user. + *

+ * + * @param agentJar The agent jar file. + * @param processId The target process id. + */ + public static void attach(File agentJar, String processId) { + attach(agentJar, processId, null); + } + + public static void attach(String processId) { + attach(trySelfResolve(), processId, null); + } + + /** + *

+ * Attaches the given agent Jar on the target process which must be a virtual machine process. The default attachment provider + * is used for applying the attachment. This operation blocks until the attachment is complete. If the current VM does not supply + * any known form of attachment to a remote VM, an {@link IllegalStateException} is thrown. + *

+ *

+ * Important: It is only possible to attach to processes that are executed by the same operating system user. + *

+ * + * @param agentJar The agent jar file. + * @param processId The target process id. + * @param argument The argument to provide to the agent. + */ + public static void attach(File agentJar, String processId, String argument) { + install(processId, argument, new AgentProvider.ForExistingAgent(agentJar)); + } + + /** + * Installs a Java agent on a target VM. + * + * @param processId The process id of the target JVM process. + * @param argument The argument to provide to the agent. + * @param agentProvider The agent provider for the agent jar or library. + */ + private static void install(String processId, String argument, AgentProvider agentProvider) { + AttachmentProvider.Accessor attachmentAccessor = AttachmentProvider.DEFAULT.attempt(); + if (!attachmentAccessor.isAvailable()) { + throw new IllegalStateException("No compatible attachment provider is available"); + } + try { + Class virtualMachineType = attachmentAccessor.getVirtualMachineType(); + String agent = agentProvider.resolve().getAbsolutePath(); + Object virtualMachineInstance = virtualMachineType + .getMethod("attach", String.class) + .invoke(null, processId); + try { + virtualMachineType + .getMethod("loadAgent", String.class, String.class) + .invoke(virtualMachineInstance, agent, argument); + } finally { + virtualMachineType + .getMethod("detach") + .invoke(virtualMachineInstance); + } + } catch (RuntimeException exception) { + throw exception; + } catch (Exception exception) { + throw new IllegalStateException("Error during attachment using: " + AttachmentProvider.DEFAULT, exception); + } + } + + /** + * Attempts to resolve the location of the {@link Attacher} class for a self-attachment. Doing so avoids the creation of a temporary jar file. + * + * @return The self-resolved jar file or {@code null} if the jar file cannot be located. + */ + private static File trySelfResolve() { + try { + ProtectionDomain protectionDomain = Attacher.class.getProtectionDomain(); + if (protectionDomain == null) { + return null; + } + CodeSource codeSource = protectionDomain.getCodeSource(); + if (codeSource == null) { + return null; + } + URL location = codeSource.getLocation(); + if (!location.getProtocol().equals("file")) { + return null; + } + try { + File file = new File(location.toURI()); + if (file.getPath().contains(AGENT_ARGUMENT_SEPARATOR)) { + return null; + } + return file; + } catch (URISyntaxException ignored) { + return new File(location.getPath()); + } + } catch (Exception ignored) { + return null; + } + } + + /** + * An attachment provider is responsible for making the Java attachment API available. + */ + public interface AttachmentProvider { + + /** + * The default attachment provider to be used. + */ + AttachmentProvider DEFAULT = new Compound(ForModularizedVm.INSTANCE, + ForJ9Vm.INSTANCE, + ForStandardToolsJarVm.JVM_ROOT, + ForStandardToolsJarVm.JDK_ROOT, + ForStandardToolsJarVm.MACINTOSH, + ForUserDefinedToolsJar.INSTANCE, + ForEmulatedAttachment.INSTANCE); + + /** + * Attempts the creation of an accessor for a specific JVM's attachment API. + * + * @return The accessor this attachment provider can supply for the currently running JVM. + */ + Accessor attempt(); + + /** + * An accessor for a JVM's attachment API. + */ + interface Accessor { + + /** + * The name of the {@code VirtualMachine} class on any OpenJDK or Oracle JDK implementation. + */ + String VIRTUAL_MACHINE_TYPE_NAME = "com.sun.tools.attach.VirtualMachine"; + + /** + * The name of the {@code VirtualMachine} class on IBM J9 VMs. + */ + String VIRTUAL_MACHINE_TYPE_NAME_J9 = "com.ibm.tools.attach.VirtualMachine"; + + /** + * Determines if this accessor is applicable for the currently running JVM. + * + * @return {@code true} if this accessor is available. + */ + boolean isAvailable(); + + /** + * Returns {@code true} if this accessor prohibits attachment to the same virtual machine in Java 9 and later. + * + * @return {@code true} if this accessor prohibits attachment to the same virtual machine in Java 9 and later. + */ + boolean isExternalAttachmentRequired(); + + /** + * Returns a {@code VirtualMachine} class. This method must only be called for available accessors. + * + * @return The virtual machine type. + */ + Class getVirtualMachineType(); + + /** + * Returns a description of a virtual machine class for an external attachment. + * + * @return A description of the external attachment. + */ + ExternalAttachment getExternalAttachment(); + + /** + * A canonical implementation of an unavailable accessor. + */ + enum Unavailable implements Accessor { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public boolean isAvailable() { + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isExternalAttachmentRequired() { + throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor"); + } + + /** + * {@inheritDoc} + */ + public Class getVirtualMachineType() { + throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor"); + } + + /** + * {@inheritDoc} + */ + public ExternalAttachment getExternalAttachment() { + throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor"); + } + } + + /** + * Describes an external attachment to a Java virtual machine. + */ + class ExternalAttachment { + + /** + * The fully-qualified binary name of the virtual machine type. + */ + private final String virtualMachineType; + + /** + * The class path elements required for loading the supplied virtual machine type. + */ + private final List classPath; + + /** + * Creates an external attachment. + * + * @param virtualMachineType The fully-qualified binary name of the virtual machine type. + * @param classPath The class path elements required for loading the supplied virtual machine type. + */ + public ExternalAttachment(String virtualMachineType, List classPath) { + this.virtualMachineType = virtualMachineType; + this.classPath = classPath; + } + + /** + * Returns the fully-qualified binary name of the virtual machine type. + * + * @return The fully-qualified binary name of the virtual machine type. + */ + public String getVirtualMachineType() { + return virtualMachineType; + } + + /** + * Returns the class path elements required for loading the supplied virtual machine type. + * + * @return The class path elements required for loading the supplied virtual machine type. + */ + public List getClassPath() { + return classPath; + } + } + + /** + * A simple implementation of an accessible accessor. + */ + abstract class Simple implements Accessor { + + /** + * A {@code VirtualMachine} class. + */ + protected final Class virtualMachineType; + + /** + * Creates a new simple accessor. + * + * @param virtualMachineType A {@code VirtualMachine} class. + */ + protected Simple(Class virtualMachineType) { + this.virtualMachineType = virtualMachineType; + } + + /** + *

+ * Creates an accessor by reading the process id from the JMX runtime bean and by attempting + * to load the {@code com.sun.tools.attach.VirtualMachine} class from the provided class loader. + *

+ *

+ * This accessor is supposed to work on any implementation of the OpenJDK or Oracle JDK. + *

+ * + * @param classLoader A class loader that is capable of loading the virtual machine type. + * @param classPath The class path required to load the virtual machine class. + * @return An appropriate accessor. + */ + public static Accessor of(ClassLoader classLoader, File... classPath) { + try { + return new WithExternalAttachment(Class.forName(VIRTUAL_MACHINE_TYPE_NAME, + false, + classLoader), Arrays.asList(classPath)); + } catch (ClassNotFoundException ignored) { + return Unavailable.INSTANCE; + } + } + + /** + *

+ * Creates an accessor by reading the process id from the JMX runtime bean and by attempting + * to load the {@code com.ibm.tools.attach.VirtualMachine} class from the provided class loader. + *

+ *

+ * This accessor is supposed to work on any implementation of IBM's J9. + *

+ * + * @return An appropriate accessor. + */ + public static Accessor ofJ9() { + try { + return new WithExternalAttachment(ClassLoader.getSystemClassLoader().loadClass(VIRTUAL_MACHINE_TYPE_NAME_J9), + Collections.emptyList()); + } catch (ClassNotFoundException ignored) { + return Unavailable.INSTANCE; + } + } + + /** + * {@inheritDoc} + */ + public boolean isAvailable() { + return true; + } + + /** + * {@inheritDoc} + */ + public Class getVirtualMachineType() { + return virtualMachineType; + } + + /** + * A simple implementation of an accessible accessor that allows for external attachment. + */ + protected static class WithExternalAttachment extends Simple { + + /** + * The class path required for loading the virtual machine type. + */ + private final List classPath; + + /** + * Creates a new simple accessor that allows for external attachment. + * + * @param virtualMachineType The {@code com.sun.tools.attach.VirtualMachine} class. + * @param classPath The class path required for loading the virtual machine type. + */ + public WithExternalAttachment(Class virtualMachineType, List classPath) { + super(virtualMachineType); + this.classPath = classPath; + } + + /** + * {@inheritDoc} + */ + public boolean isExternalAttachmentRequired() { + return true; + } + + /** + * {@inheritDoc} + */ + public ExternalAttachment getExternalAttachment() { + return new ExternalAttachment(virtualMachineType.getName(), classPath); + } + } + + /** + * A simple implementation of an accessible accessor that attaches using a virtual machine emulation that does not require external attachment. + */ + protected static class WithDirectAttachment extends Simple { + + /** + * Creates a new simple accessor that implements direct attachment. + * + * @param virtualMachineType A {@code VirtualMachine} class. + */ + public WithDirectAttachment(Class virtualMachineType) { + super(virtualMachineType); + } + + /** + * {@inheritDoc} + */ + public boolean isExternalAttachmentRequired() { + return false; + } + + /** + * {@inheritDoc} + */ + public ExternalAttachment getExternalAttachment() { + throw new IllegalStateException("Cannot apply external attachment"); + } + } + } + } + + /** + * An attachment provider that locates the attach API directly from the system class loader, as possible since + * introducing the Java module system via the {@code jdk.attach} module. + */ + enum ForModularizedVm implements AttachmentProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + return Accessor.Simple.of(ClassLoader.getSystemClassLoader()); + } + } + + /** + * An attachment provider that locates the attach API directly from the system class loader expecting + * an IBM J9 VM. + */ + enum ForJ9Vm implements AttachmentProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + return Accessor.Simple.ofJ9(); + } + } + + /** + * An attachment provider that is dependant on the existence of a tools.jar file on the local + * file system. + */ + enum ForStandardToolsJarVm implements AttachmentProvider { + + /** + * An attachment provider that locates the tools.jar from a Java home directory. + */ + JVM_ROOT("../lib/tools.jar"), + + /** + * An attachment provider that locates the tools.jar from a Java installation directory. + * In practice, several virtual machines do not return the JRE's location for the + * java.home property against the property's specification. + */ + JDK_ROOT("lib/tools.jar"), + + /** + * An attachment provider that locates the tools.jar as it is set for several JVM + * installations on Apple Macintosh computers. + */ + MACINTOSH("../Classes/classes.jar"); + + /** + * The Java home system property. + */ + private static final String JAVA_HOME_PROPERTY = "java.home"; + + /** + * The path to the tools.jar file, starting from the Java home directory. + */ + private final String toolsJarPath; + + /** + * Creates a new attachment provider that loads the virtual machine class from the tools.jar. + * + * @param toolsJarPath The path to the tools.jar file, starting from the Java home directory. + */ + ForStandardToolsJarVm(String toolsJarPath) { + this.toolsJarPath = toolsJarPath; + } + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + File toolsJar = new File(System.getProperty(JAVA_HOME_PROPERTY), toolsJarPath); + try { + return toolsJar.isFile() && toolsJar.canRead() + ? Accessor.Simple.of(new URLClassLoader(new URL[]{toolsJar.toURI().toURL()}, BOOTSTRAP_CLASS_LOADER), toolsJar) + : Accessor.Unavailable.INSTANCE; + } catch (MalformedURLException exception) { + throw new IllegalStateException("Could not represent " + toolsJar + " as URL"); + } + } + } + + /** + * An attachment provider that attempts to locate a {@code tools.jar} from a custom location set via a system property. + */ + enum ForUserDefinedToolsJar implements AttachmentProvider { + + /** + * The singelton instance. + */ + INSTANCE; + + /** + * The property being read for locating {@code tools.jar}. + */ + public static final String PROPERTY = "net.bytebuddy.agent.toolsjar"; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + String location = System.getProperty(PROPERTY); + if (location == null) { + return Accessor.Unavailable.INSTANCE; + } else { + File toolsJar = new File(location); + try { + return Accessor.Simple.of(new URLClassLoader(new URL[]{toolsJar.toURI().toURL()}, BOOTSTRAP_CLASS_LOADER), toolsJar); + } catch (MalformedURLException exception) { + throw new IllegalStateException("Could not represent " + toolsJar + " as URL"); + } + } + } + } + + /** + * An attachment provider that uses Byte Buddy's attachment API emulation. To use this feature, JNA is required. + */ + enum ForEmulatedAttachment implements AttachmentProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + try { + return new Accessor.Simple.WithDirectAttachment(VirtualMachine.Resolver.INSTANCE.get()); + } catch (Throwable ignored) { + return Accessor.Unavailable.INSTANCE; + } + } + } + + /** + * A compound attachment provider that attempts the attachment by delegation to other providers. If + * none of the providers of this compound provider is capable of providing a valid accessor, an + * non-available accessor is returned. + */ + class Compound implements AttachmentProvider { + + /** + * A list of attachment providers in the order of their application. + */ + private final List attachmentProviders; + + /** + * Creates a new compound attachment provider. + * + * @param attachmentProvider A list of attachment providers in the order of their application. + */ + public Compound(AttachmentProvider... attachmentProvider) { + this(Arrays.asList(attachmentProvider)); + } + + /** + * Creates a new compound attachment provider. + * + * @param attachmentProviders A list of attachment providers in the order of their application. + */ + public Compound(List attachmentProviders) { + this.attachmentProviders = new ArrayList(); + for (AttachmentProvider attachmentProvider : attachmentProviders) { + if (attachmentProvider instanceof Compound) { + this.attachmentProviders.addAll(((Compound) attachmentProvider).attachmentProviders); + } else { + this.attachmentProviders.add(attachmentProvider); + } + } + } + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + for (AttachmentProvider attachmentProvider : attachmentProviders) { + Accessor accessor = attachmentProvider.attempt(); + if (accessor.isAvailable()) { + return accessor; + } + } + return Accessor.Unavailable.INSTANCE; + } + } + } + + /** + * A process provider is responsible for providing the process id of the current VM. + */ + public interface ProcessProvider { + + /** + * Resolves a process id for the current JVM. + * + * @return The resolved process id. + */ + String resolve(); + + /** + * Supplies the current VM's process id. + */ + enum ForCurrentVm implements ProcessProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * The best process provider for the current VM. + */ + private final ProcessProvider dispatcher; + + /** + * Creates a process provider that supplies the current VM's process id. + */ + ForCurrentVm() { + dispatcher = ForJava9CapableVm.make(); + } + + /** + * {@inheritDoc} + */ + public String resolve() { + return dispatcher.resolve(); + } + + /** + * A process provider for a legacy VM that reads the process id from its JMX properties. This strategy + * is only used prior to Java 9 such that the java.management module never is resolved, even if + * the module system is used, as the module system was not available in any relevant JVM version. + */ + protected enum ForLegacyVm implements ProcessProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public String resolve() { + String runtimeName; + try { + Method method = Class.forName("java.lang.management.ManagementFactory").getMethod("getRuntimeMXBean"); + runtimeName = (String) method.getReturnType().getMethod("getName").invoke(method.invoke(null)); + } catch (Exception exception) { + throw new IllegalStateException("Failed to access VM name via management factory", exception); + } + int processIdIndex = runtimeName.indexOf('@'); + if (processIdIndex == -1) { + throw new IllegalStateException("Cannot extract process id from runtime management bean"); + } else { + return runtimeName.substring(0, processIdIndex); + } + } + } + + /** + * A process provider for a Java 9 capable VM with access to the introduced process API. + */ + protected static class ForJava9CapableVm implements ProcessProvider { + + /** + * The {@code java.lang.ProcessHandle#current()} method. + */ + private final Method current; + + /** + * The {@code java.lang.ProcessHandle#pid()} method. + */ + private final Method pid; + + /** + * Creates a new Java 9 capable dispatcher for reading the current process's id. + * + * @param current The {@code java.lang.ProcessHandle#current()} method. + * @param pid The {@code java.lang.ProcessHandle#pid()} method. + */ + protected ForJava9CapableVm(Method current, Method pid) { + this.current = current; + this.pid = pid; + } + + /** + * Attempts to create a dispatcher for a Java 9 VM and falls back to a legacy dispatcher + * if this is not possible. + * + * @return A dispatcher for the current VM. + */ + public static ProcessProvider make() { + try { + return new ForJava9CapableVm(Class.forName("java.lang.ProcessHandle").getMethod("current"), + Class.forName("java.lang.ProcessHandle").getMethod("pid")); + } catch (Exception ignored) { + return ForLegacyVm.INSTANCE; + } + } + + /** + * {@inheritDoc} + */ + public String resolve() { + try { + return pid.invoke(current.invoke(null)).toString(); + } catch (IllegalAccessException exception) { + throw new IllegalStateException("Cannot access Java 9 process API", exception); + } catch (InvocationTargetException exception) { + throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException()); + } + } + } + } + } + + /** + * An agent provider is responsible for handling and providing the jar file of an agent that is being attached. + */ + protected interface AgentProvider { + + /** + * Provides an agent jar file for attachment. + * + * @return The provided agent. + * @throws IOException If the agent cannot be written to disk. + */ + File resolve() throws IOException; + + /** + * An agent provider that supplies an existing agent that is not deleted after attachment. + */ + class ForExistingAgent implements AgentProvider { + + /** + * The supplied agent. + */ + private final File agent; + + /** + * Creates an agent provider for an existing agent. + * + * @param agent The supplied agent. + */ + protected ForExistingAgent(File agent) { + this.agent = agent; + } + + /** + * {@inheritDoc} + */ + public File resolve() { + return agent; + } + } + } + + /** + * An attachment evaluator is responsible for deciding if an agent can be attached from the current process. + */ + protected interface AttachmentTypeEvaluator { + + /** + * Checks if the current VM requires external attachment for the supplied process id. + * + * @param processId The process id of the process to which to attach. + * @return {@code true} if the current VM requires external attachment for the supplied process. + */ + boolean requiresExternalAttachment(String processId); + + /** + * An installation action for creating an attachment type evaluator. + */ + enum InstallationAction implements PrivilegedAction { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * The OpenJDK's property for specifying the legality of self-attachment. + */ + private static final String JDK_ALLOW_SELF_ATTACH = "jdk.attach.allowAttachSelf"; + + /** + * {@inheritDoc} + */ + public AttachmentTypeEvaluator run() { + try { + if (Boolean.getBoolean(JDK_ALLOW_SELF_ATTACH)) { + return Disabled.INSTANCE; + } else { + return new ForJava9CapableVm(Class.forName("java.lang.ProcessHandle").getMethod("current"), + Class.forName("java.lang.ProcessHandle").getMethod("pid")); + } + } catch (Exception ignored) { + return Disabled.INSTANCE; + } + } + } + + /** + * An attachment type evaluator that never requires external attachment. + */ + enum Disabled implements AttachmentTypeEvaluator { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public boolean requiresExternalAttachment(String processId) { + return false; + } + } + + /** + * An attachment type evaluator that checks a process id against the current process id. + */ + class ForJava9CapableVm implements AttachmentTypeEvaluator { + + /** + * The {@code java.lang.ProcessHandle#current()} method. + */ + private final Method current; + + /** + * The {@code java.lang.ProcessHandle#pid()} method. + */ + private final Method pid; + + /** + * Creates a new attachment type evaluator. + * + * @param current The {@code java.lang.ProcessHandle#current()} method. + * @param pid The {@code java.lang.ProcessHandle#pid()} method. + */ + protected ForJava9CapableVm(Method current, Method pid) { + this.current = current; + this.pid = pid; + } + + /** + * {@inheritDoc} + */ + public boolean requiresExternalAttachment(String processId) { + try { + return pid.invoke(current.invoke(null)).toString().equals(processId); + } catch (IllegalAccessException exception) { + throw new IllegalStateException("Cannot access Java 9 process API", exception); + } catch (InvocationTargetException exception) { + throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException()); + } + } + } + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/VirtualMachine.java b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/VirtualMachine.java new file mode 100644 index 00000000..c7a80da3 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/attach/VirtualMachine.java @@ -0,0 +1,2888 @@ +package com.reajason.javaweb.memshell.packer.jar.attach;/* + * Copyright 2014 - Present Rafael Winterhalter + * + * 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. + */ + +import com.sun.jna.*; +import com.sun.jna.platform.win32.*; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.win32.StdCallLibrary; +import com.sun.jna.win32.W32APIOptions; + +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.FileLock; +import java.security.PrivilegedAction; +import java.security.SecureRandom; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

+ * An implementation for attachment on a virtual machine. This interface mimics the tooling API's virtual + * machine interface to allow for similar usage by where all calls are made via + * reflection such that this structural typing suffices for interoperability. + *

+ *

+ * Note: Implementations are required to declare a static method {@code attach(String)} returning an + * instance of a class that declares the methods defined by {@link VirtualMachine}. + *

+ */ +public interface VirtualMachine { + + /** + * Loads the target VMs system properties. + * + * @return The target VM properties. + * @throws IOException If an I/O exception occurs. + */ + Properties getSystemProperties() throws IOException; + + /** + * Loads the target VMs agent properties. + * + * @return The target VM properties. + * @throws IOException If an I/O exception occurs. + */ + Properties getAgentProperties() throws IOException; + + /** + * Loads an agent into the represented virtual machine. + * + * @param jarFile The jar file to attach. + * @throws IOException If an I/O exception occurs. + */ + void loadAgent(String jarFile) throws IOException; + + /** + * Loads an agent into the represented virtual machine. + * + * @param jarFile The jar file to attach. + * @param argument The argument to provide or {@code null} if no argument should be provided. + * @throws IOException If an I/O exception occurs. + */ + void loadAgent(String jarFile, String argument) throws IOException; + + /** + * Loads a native agent into the represented virtual machine. + * + * @param path The agent path. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentPath(String path) throws IOException; + + /** + * Loads a native agent into the represented virtual machine. + * + * @param path The agent path. + * @param argument The argument to provide or {@code null} if no argument should be provided. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentPath(String path, String argument) throws IOException; + + /** + * Loads a native agent library into the represented virtual machine. + * + * @param library The agent library. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentLibrary(String library) throws IOException; + + /** + * Loads a native agent library into the represented virtual machine. + * + * @param library The agent library. + * @param argument The argument to provide or {@code null} if no argument should be provided. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentLibrary(String library, String argument) throws IOException; + + /** + * Starts a JMX management agent. + * + * @param properties The properties to transfer to the JMX agent. + * @throws IOException If an I/O error occurs. + */ + void startManagementAgent(Properties properties) throws IOException; + + /** + * Starts a local management agent. + * + * @return The local connector address. + * @throws IOException If an I/O error occurs. + */ + String startLocalManagementAgent() throws IOException; + + /** + * Detaches this virtual machine representation. + * + * @throws IOException If an I/O exception occurs. + */ + void detach() throws IOException; + + /** + * A resolver for the current VM's virtual machine attachment emulation. + */ + enum Resolver { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Class get() { + try { + Class.forName("com.sun.jna.Platform"); + } catch (ClassNotFoundException exception) { + throw new IllegalStateException("Optional JNA dependency is not available", exception); + } + return System.getProperty("java.vm.name", "").toUpperCase(Locale.US).contains("J9") + ? ForOpenJ9.class + : ForHotSpot.class; + + } + } + + /** + * An abstract base implementation for a virtual machine. + */ + abstract class AbstractBase implements VirtualMachine { + + /** + * {@inheritDoc} + */ + public void loadAgent(String jarFile) throws IOException { + loadAgent(jarFile, null); + } + + /** + * {@inheritDoc} + */ + public void loadAgentPath(String path) throws IOException { + loadAgentPath(path, null); + } + + /** + * {@inheritDoc} + */ + public void loadAgentLibrary(String library) throws IOException { + loadAgentLibrary(library, null); + } + } + + /** + * A virtual machine attachment implementation for a HotSpot VM or any compatible JVM. + */ + class ForHotSpot extends AbstractBase { + + /** + * The protocol version to use for communication. + */ + private static final String PROTOCOL_VERSION = "1"; + + /** + * The {@code load} command. + */ + private static final String LOAD_COMMAND = "load"; + + /** + * The {@code instrument} command. + */ + private static final String INSTRUMENT_COMMAND = "instrument"; + + /** + * A delimiter to be used for attachment. + */ + private static final String ARGUMENT_DELIMITER = "="; + + /** + * The virtual machine connection. + */ + private final Connection connection; + + /** + * Creates a new virtual machine connection for HotSpot. + * + * @param connection The virtual machine connection. + */ + protected ForHotSpot(Connection connection) { + this.connection = connection; + } + + /** + * Attaches to the supplied process id using the default JNA implementation. + * + * @param processId The process id. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId) throws IOException { + if (Platform.isWindows()) { + return attach(processId, new Connection.ForJnaWindowsNamedPipe.Factory()); + } else if (Platform.isSolaris()) { + return attach(processId, new Connection.ForJnaSolarisDoor.Factory(15, 100, TimeUnit.MILLISECONDS)); + } else { + return attach(processId, Connection.ForJnaPosixSocket.Factory.withDefaultTemporaryFolder(15, 100, TimeUnit.MILLISECONDS)); + } + } + + /** + * Attaches to the supplied process id using the supplied connection factory. + * + * @param processId The process id. + * @param connectionFactory The connection factory to use. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId, Connection.Factory connectionFactory) throws IOException { + return new ForHotSpot(connectionFactory.connect(processId)); + } + + /** + * Checks the header of a response. + * + * @param response The response to check the header for. + * @throws IOException If an I/O exception occurs. + */ + private static void checkHeader(Connection.Response response) throws IOException { + byte[] buffer = new byte[1]; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int length; + while ((length = response.read(buffer)) != -1) { + if (length > 0) { + if (buffer[0] == '\n') { + break; + } + outputStream.write(buffer[0]); + } + } + switch (Integer.parseInt(outputStream.toString("UTF-8"))) { + case 0: + return; + case 101: + throw new IOException("Protocol mismatch with target VM"); + default: + buffer = new byte[1024]; + outputStream = new ByteArrayOutputStream(); + while ((length = response.read(buffer)) != -1) { + outputStream.write(buffer, 0, length); + } + throw new IllegalStateException(outputStream.toString("UTF-8")); + } + } + + /** + * {@inheritDoc} + */ + public Properties getSystemProperties() throws IOException { + return getProperties("properties"); + } + + /** + * {@inheritDoc} + */ + public Properties getAgentProperties() throws IOException { + return getProperties("agentProperties"); + } + + /** + * Loads properties of the target VM. + * + * @param command The command for fetching properties. + * @return The read properties. + * @throws IOException If an I/O exception occurs. + */ + private Properties getProperties(String command) throws IOException { + Connection.Response response = connection.execute(PROTOCOL_VERSION, command, null, null, null); + try { + checkHeader(response); + byte[] buffer = new byte[1024]; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int length; + while ((length = response.read(buffer)) != -1) { + outputStream.write(buffer, 0, length); + } + Properties properties = new Properties(); + properties.load(new ByteArrayInputStream(outputStream.toByteArray())); + return properties; + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public void loadAgent(String jarFile, String argument) throws IOException { + load(jarFile, false, argument); + } + + /** + * {@inheritDoc} + */ + public void loadAgentPath(String path, String argument) throws IOException { + load(path, true, argument); + } + + /** + * {@inheritDoc} + */ + public void loadAgentLibrary(String library, String argument) throws IOException { + load(library, false, argument); + } + + /** + * Loads an agent by the given command. + * + * @param file The Java agent or library to be loaded. + * @param absolute {@code true} if the agent location is absolute. + * @param argument The argument to the agent or {@code null} if no argument is given. + * @throws IOException If an I/O exception occurs. + */ + protected void load(String file, boolean absolute, String argument) throws IOException { + Connection.Response response = connection.execute(PROTOCOL_VERSION, LOAD_COMMAND, INSTRUMENT_COMMAND, Boolean.toString(absolute), (argument == null + ? file + : file + ARGUMENT_DELIMITER + argument)); + try { + checkHeader(response); + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public void startManagementAgent(Properties properties) throws IOException { + StringBuilder stringBuilder = new StringBuilder("ManagementAgent.start "); + boolean first = true; + for (Map.Entry entry : properties.entrySet()) { + if (!(entry.getKey() instanceof String) || !((String) entry.getKey()).startsWith("com.sun.management.")) { + throw new IllegalArgumentException("Illegal property name: " + entry.getKey()); + } else if (first) { + first = false; + } else { + stringBuilder.append(' '); + } + stringBuilder.append(((String) entry.getKey()).substring("com.sun.management.".length())).append('='); + String value = entry.getValue().toString(); + if (value.contains(" ")) { + stringBuilder.append('\'').append(value).append('\''); + } else { + stringBuilder.append(value); + } + } + Connection.Response response = connection.execute(PROTOCOL_VERSION, "jcmd", stringBuilder.toString(), null, null); + try { + checkHeader(response); + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public String startLocalManagementAgent() throws IOException { + Connection.Response response = connection.execute(PROTOCOL_VERSION, "jcmd", "ManagementAgent.start_local", null, null); + try { + checkHeader(response); + return getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public void detach() throws IOException { + connection.close(); + } + + /** + * Represents a connection to a virtual machine. + */ + public interface Connection extends Closeable { + + /** + * Executes a command on the current connection. + * + * @param protocol The target VMs protocol version for the attach API. + * @param argument The arguments to send to the target VM. + * @return The response of the target JVM. + * @throws IOException If an I/O error occurred. + */ + Response execute(String protocol, String... argument) throws IOException; + + /** + * A response to an execution command to a VM. + */ + interface Response extends Closeable { + + /** + * Reads a buffer from the target VM. + * + * @param buffer The buffer to read to. + * @return The bytes read or {@code -1} if no more bytes could be read. + * @throws IOException If an I/O exception occurred. + */ + int read(byte[] buffer) throws IOException; + } + + /** + * A factory for creating connections to virtual machines. + */ + interface Factory { + + /** + * Connects to the supplied process. + * + * @param processId The process id. + * @return The connection to the virtual machine with the supplied process id. + * @throws IOException If an I/O exception occurs during connecting to the targeted VM. + */ + Connection connect(String processId) throws IOException; + + /** + * A factory for attaching via a socket file. + */ + abstract class ForSocketFile implements Factory { + + /** + * The name prefix for a socket. + */ + private static final String SOCKET_FILE_PREFIX = ".java_pid"; + + /** + * The name prefix for an attachment file indicator. + */ + private static final String ATTACH_FILE_PREFIX = ".attach_pid"; + + /** + * The temporary directory to use. + */ + private final String temporaryDirectory; + + /** + * The maximum amount of attempts for checking the establishment of a socket connection. + */ + private final int attempts; + + /** + * The pause between two checks for an established socket connection. + */ + private final long pause; + + /** + * The time unit of the pause time. + */ + private final TimeUnit timeUnit; + + /** + * Creates a connection factory for creating a socket connection via a file. + * + * @param temporaryDirectory The temporary directory to use. + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + */ + protected ForSocketFile(String temporaryDirectory, int attempts, long pause, TimeUnit timeUnit) { + this.temporaryDirectory = temporaryDirectory; + this.attempts = attempts; + this.pause = pause; + this.timeUnit = timeUnit; + } + + /** + * {@inheritDoc} + */ + public Connection connect(String processId) throws IOException { + File socket = new File(temporaryDirectory, SOCKET_FILE_PREFIX + processId); + if (!socket.exists()) { + String target = ATTACH_FILE_PREFIX + processId, path = "/proc/" + processId + "/cwd/" + target; + File attachFile = new File(path); + try { + if (!attachFile.createNewFile() && !attachFile.isFile()) { + throw new IllegalStateException("Could not create attach file: " + attachFile); + } + } catch (IOException ignored) { + attachFile = new File(temporaryDirectory, target); + if (!attachFile.createNewFile() && !attachFile.isFile()) { + throw new IllegalStateException("Could not create attach file: " + attachFile); + } + } + try { + kill(processId, 3); + int attempts = this.attempts; + while (!socket.exists() && attempts-- > 0) { + timeUnit.sleep(pause); + } + if (!socket.exists()) { + throw new IllegalStateException("Target VM did not respond: " + processId); + } + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(exception); + } finally { + if (!attachFile.delete()) { + attachFile.deleteOnExit(); + } + } + } + return doConnect(socket); + } + + /** + * Sends a kill signal to the target process. + * + * @param processId The process id. + * @param signal The signal to send. + */ + protected abstract void kill(String processId, int signal); + + /** + * Connects to the supplied POSIX socket. + * + * @param socket The socket to connect to. + * @return An active connection to the supplied socket. + * @throws IOException If an error occurs during connection. + */ + protected abstract Connection doConnect(File socket) throws IOException; + } + } + + /** + * A connection that is represented by a byte channel that is persistent during communication. + * + * @param The connection representation. + */ + abstract class OnPersistentByteChannel implements Connection { + + /** + * A blank line argument. + */ + private static final byte[] BLANK = new byte[]{0}; + + /** + * {@inheritDoc} + */ + public Connection.Response execute(String protocol, String... argument) throws IOException { + T connection = connect(); + try { + write(connection, protocol.getBytes("UTF-8")); + write(connection, BLANK); + for (String anArgument : argument) { + if (anArgument != null) { + write(connection, anArgument.getBytes("UTF-8")); + } + write(connection, BLANK); + } + return new Response(connection); + } catch (Throwable throwable) { + close(connection); + if (throwable instanceof RuntimeException) { + throw (RuntimeException) throwable; + } else if (throwable instanceof IOException) { + throw (IOException) throwable; + } else { + throw new IllegalStateException(throwable); + } + } + } + + /** + * A response of a persistent byte channel. + */ + private class Response implements Connection.Response { + + /** + * The connection representing this response. + */ + private final T connection; + + /** + * Creates a new response for a persistent byte channel. + * + * @param connection The connection representing this response. + */ + private Response(T connection) { + this.connection = connection; + } + + /** + * {@inheritDoc} + */ + public int read(byte[] buffer) throws IOException { + return OnPersistentByteChannel.this.read(connection, buffer); + } + + /** + * {@inheritDoc} + */ + public void close() throws IOException { + OnPersistentByteChannel.this.close(connection); + } + } + + /** + * Creates a new connection to the target VM. + * + * @return Returns a new connection to the target VM. + * @throws IOException If an I/O exception occurs. + */ + protected abstract T connect() throws IOException; + + /** + * Closes the connection to the target VM. + * + * @param connection The connection to close. + * @throws IOException If an I/O exception occurs. + */ + protected abstract void close(T connection) throws IOException; + + /** + * Writes to the target VM. + * + * @param connection The connection to write to. + * @param buffer The buffer to write to. + * @throws IOException If an I/O exception occurs during writing. + */ + protected abstract void write(T connection, byte[] buffer) throws IOException; + + /** + * Reads from the target VM. + * + * @param connection The connection to read from. + * @param buffer The buffer to store the result in. + * @return The number of byte that were read. + * @throws IOException If an I/O exception occurs. + */ + protected abstract int read(T connection, byte[] buffer) throws IOException; + } + + /** + * Implements a connection for a POSIX socket in JNA. + */ + class ForJnaPosixSocket extends OnPersistentByteChannel { + + /** + * The JNA library to use. + */ + private final PosixLibrary library; + + /** + * The POSIX socket. + */ + private final File socket; + + /** + * Creates a connection for a virtual POSIX socket implemented in JNA. + * + * @param library The JNA library to use. + * @param socket The POSIX socket. + */ + protected ForJnaPosixSocket(PosixLibrary library, File socket) { + this.library = library; + this.socket = socket; + } + + @Override + protected Integer connect() { + int handle = library.socket(1, 1, 0); + try { + PosixLibrary.SocketAddress address = new PosixLibrary.SocketAddress(); + try { + address.setPath(socket.getAbsolutePath()); + library.connect(handle, address, address.size()); + return handle; + } finally { + address = null; + } + } catch (RuntimeException exception) { + library.close(handle); + throw exception; + } + } + + @Override + protected int read(Integer handle, byte[] buffer) { + int read = library.read(handle, ByteBuffer.wrap(buffer), buffer.length); + return read == 0 ? -1 : read; + } + + @Override + protected void write(Integer handle, byte[] buffer) { + library.write(handle, ByteBuffer.wrap(buffer), buffer.length); + } + + @Override + protected void close(Integer handle) { + library.close(handle); + } + + /** + * {@inheritDoc} + */ + public void close() { + /* do nothing */ + } + + /** + * A JNA library binding for POSIX sockets. + */ + protected interface PosixLibrary extends Library { + + /** + * Sends a kill command. + * + * @param processId The process id to kill. + * @param signal The signal to send. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int kill(int processId, int signal) throws LastErrorException; + + /** + * Creates a POSIX socket connection. + * + * @param domain The socket's domain. + * @param type The socket's type. + * @param protocol The protocol version. + * @return A handle to the socket that was created or {@code 0} if no socket could be created. + * @throws LastErrorException If an error occurs. + */ + int socket(int domain, int type, int protocol) throws LastErrorException; + + /** + * Connects a socket connection. + * + * @param handle The socket's handle. + * @param address The address of the POSIX socket. + * @param length The length of the socket value. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int connect(int handle, SocketAddress address, int length) throws LastErrorException; + + /** + * Reads from a POSIX socket. + * + * @param handle The socket's handle. + * @param buffer The buffer to read from. + * @param count The bytes being read. + * @return The amount of bytes that could be read. + * @throws LastErrorException If an error occurs. + */ + int read(int handle, ByteBuffer buffer, int count) throws LastErrorException; + + /** + * Writes to a POSIX socket. + * + * @param handle The socket's handle. + * @param buffer The buffer to write to. + * @param count The bytes being written. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int write(int handle, ByteBuffer buffer, int count) throws LastErrorException; + + /** + * Closes the socket connection. + * + * @param handle The handle of the connection. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int close(int handle) throws LastErrorException; + + /** + * Represents an address for a POSIX socket. + */ + class SocketAddress extends Structure { + + /** + * The socket family. + */ + @SuppressWarnings("unused") + public short family = 1; + + /** + * The socket path. + */ + public byte[] path = new byte[100]; + + /** + * Sets the socket path. + * + * @param path The socket path. + */ + protected void setPath(String path) { + try { + System.arraycopy(path.getBytes("UTF-8"), 0, this.path, 0, path.length()); + System.arraycopy(new byte[]{0}, 0, this.path, path.length(), 1); + } catch (UnsupportedEncodingException exception) { + throw new IllegalStateException(exception); + } + } + + @Override + protected List getFieldOrder() { + return Arrays.asList("family", "path"); + } + } + } + + /** + * A factory for a POSIX socket connection to a JVM using JNA. + */ + public static class Factory extends Connection.Factory.ForSocketFile { + + /** + * The socket library API. + */ + private final PosixLibrary library; + + /** + * Creates a connection factory for a POSIX socket using JNA. + * + * @param temporaryDirectory The temporary directory to use. + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + */ + @SuppressWarnings("deprecation") + public Factory(String temporaryDirectory, int attempts, long pause, TimeUnit timeUnit) { + super(temporaryDirectory, attempts, pause, timeUnit); + library = Native.loadLibrary("c", PosixLibrary.class); + } + + /** + * Creates a connection factory for a POSIX socket using JNA while locating the default temporary directory used on the + * current platform. + * + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + * @return An appropriate connection factory. + */ + @SuppressWarnings("deprecation") + public static Connection.Factory withDefaultTemporaryFolder(int attempts, long pause, TimeUnit timeUnit) { + String temporaryDirectory; + if (Platform.isMac()) { + MacLibrary library = Native.loadLibrary("c", MacLibrary.class); + Memory memory = new Memory(4096); + try { + long length = library.confstr(MacLibrary.CS_DARWIN_USER_TEMP_DIR, memory, memory.size()); + if (length == 0 || length > 4096) { + temporaryDirectory = "/tmp"; + } else { + temporaryDirectory = memory.getString(0); + } + } finally { + memory = null; + } + } else { + temporaryDirectory = "/tmp"; + } + return new Factory(temporaryDirectory, attempts, pause, timeUnit); + } + + @Override + protected void kill(String processId, int signal) { + library.kill(Integer.parseInt(processId), signal); + } + + @Override + public Connection doConnect(File socket) { + return new Connection.ForJnaPosixSocket(library, socket); + } + + /** + * A library for reading a Mac user's temporary directory. + */ + public interface MacLibrary extends Library { + + /** + * The temporary directory. + */ + int CS_DARWIN_USER_TEMP_DIR = 65537; + + /** + * Reads a configuration dependant variable into a memory segment. + * + * @param name The name of the variable. + * @param buffer The buffer to read the variable into. + * @param length The length of the buffer. + * @return The amount of bytes written to the buffer. + */ + long confstr(int name, Pointer buffer, long length); + } + } + } + + /** + * Implements a connection for a Windows named pipe in JNA. + */ + class ForJnaWindowsNamedPipe implements Connection { + + /** + * Indicates a memory release. + */ + private static final int MEM_RELEASE = 0x8000; + + /** + * The library to use for communicating with Windows native functions. + */ + private final WindowsLibrary library; + + /** + * The library to use for communicating with Windows attachment extension that is included as a DLL. + */ + private final WindowsAttachLibrary attachLibrary; + + /** + * The handle of the target VM's process. + */ + private final WinNT.HANDLE process; + + /** + * A pointer to the code that was injected into the target process. + */ + private final WinDef.LPVOID code; + + /** + * A source of random values being used for generating pipe names. + */ + private final SecureRandom random; + + /** + * Creates a new connection via a named pipe. + * + * @param library The library to use for communicating with Windows native functions. + * @param attachLibrary The library to use for communicating with Windows attachment extension that is included as a DLL. + * @param process The handle of the target VM's process. + * @param code A pointer to the code that was injected into the target process. + */ + protected ForJnaWindowsNamedPipe(WindowsLibrary library, + WindowsAttachLibrary attachLibrary, + WinNT.HANDLE process, + WinDef.LPVOID code) { + this.library = library; + this.attachLibrary = attachLibrary; + this.process = process; + this.code = code; + random = new SecureRandom(); + } + + /** + * {@inheritDoc} + */ + public Response execute(String protocol, String... argument) { + if (!"1".equals(protocol)) { + throw new IllegalArgumentException("Unknown protocol version: " + protocol); + } else if (argument.length > 4) { + throw new IllegalArgumentException("Cannot supply more then four arguments to Windows attach mechanism: " + Arrays.asList(argument)); + } + String name = "\\\\.\\pipe\\javatool" + Math.abs(random.nextInt() + 1); + + WinBase.SECURITY_ATTRIBUTES sa = createSecurityAttributesToAllowMediumIntegrity(); + + WinNT.HANDLE pipe = Kernel32.INSTANCE.CreateNamedPipe(name, + WinBase.PIPE_ACCESS_INBOUND, + WinBase.PIPE_TYPE_BYTE | WinBase.PIPE_READMODE_BYTE | WinBase.PIPE_WAIT, + 1, + 4096, + 8192, + WinBase.NMPWAIT_USE_DEFAULT_WAIT, + sa); + if (pipe == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + WinDef.LPVOID data = attachLibrary.allocate_remote_argument(process, + name, + argument.length < 1 ? null : argument[0], + argument.length < 2 ? null : argument[1], + argument.length < 3 ? null : argument[2], + argument.length < 4 ? null : argument[3]); + if (data == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + WinNT.HANDLE thread = library.CreateRemoteThread(process, null, 0, code.getPointer(), data.getPointer(), null, null); + if (thread == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + int result = Kernel32.INSTANCE.WaitForSingleObject(thread, WinBase.INFINITE); + if (result != 0) { + throw new Win32Exception(result); + } + IntByReference exitCode = new IntByReference(); + if (!library.GetExitCodeThread(thread, exitCode)) { + throw new Win32Exception(Native.getLastError()); + } else if (exitCode.getValue() != 0) { + throw new IllegalStateException("Target VM could not dispatch command successfully: " + exitCode.getValue()); + } + if (!Kernel32.INSTANCE.ConnectNamedPipe(pipe, null)) { + int code = Native.getLastError(); + if (code != WinError.ERROR_PIPE_CONNECTED) { + throw new Win32Exception(code); + } + } + return new NamedPipeResponse(pipe); + } finally { + if (!Kernel32.INSTANCE.CloseHandle(thread)) { + throw new Win32Exception(Native.getLastError()); + } + } + } finally { + if (!library.VirtualFreeEx(process, data.getPointer(), 0, MEM_RELEASE)) { + throw new Win32Exception(Native.getLastError()); + } + } + } catch (Throwable throwable) { + if (!Kernel32.INSTANCE.CloseHandle(pipe)) { + throw new Win32Exception(Native.getLastError()); + } else if (throwable instanceof RuntimeException) { + throw (RuntimeException) throwable; + } else { + throw new IllegalStateException(throwable); + } + } + } + + /** + * Custom {@link WinBase.SECURITY_ATTRIBUTES} is required here to "get" Medium Integrity Level. + * In order to allow Medium Integrity Level clients to open + * and use a NamedPipe created by an High Integrity Level process. + * + * @return A security attributes object that gives everyone read and write access. + */ + private WinBase.SECURITY_ATTRIBUTES createSecurityAttributesToAllowMediumIntegrity() { + // Allow read/write to Everybody + WinNT.PSID pSidEverybody = new WinNT.PSID(WinNT.SECURITY_MAX_SID_SIZE); + if (!Advapi32.INSTANCE.CreateWellKnownSid(WinNT.WELL_KNOWN_SID_TYPE.WinWorldSid, null, pSidEverybody, new IntByReference(WinNT.SECURITY_MAX_SID_SIZE))) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + // Allow full control to System + WinNT.PSID pSidSystem = new WinNT.PSID(WinNT.SECURITY_MAX_SID_SIZE); + if (!Advapi32.INSTANCE.CreateWellKnownSid(WinNT.WELL_KNOWN_SID_TYPE.WinBuiltinSystemOperatorsSid, null, pSidSystem, new IntByReference(WinNT.SECURITY_MAX_SID_SIZE))) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + // Allow full control to Administrators + WinNT.PSID pSidAdmin = new WinNT.PSID(WinNT.SECURITY_MAX_SID_SIZE); + if (!Advapi32.INSTANCE.CreateWellKnownSid(WinNT.WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, null, pSidAdmin, new IntByReference(WinNT.SECURITY_MAX_SID_SIZE))) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + + // Prepare ACL + int cbAcl = Native.getNativeSize(WinNT.ACL.class, null); + cbAcl += Native.getNativeSize(WinNT.ACCESS_ALLOWED_ACE.class, null) * 3; + cbAcl += (Advapi32.INSTANCE.GetLengthSid(pSidEverybody) - WinDef.DWORD.SIZE); + cbAcl += (Advapi32.INSTANCE.GetLengthSid(pSidSystem) - WinDef.DWORD.SIZE); + cbAcl += (Advapi32.INSTANCE.GetLengthSid(pSidAdmin) - WinDef.DWORD.SIZE); + cbAcl = Advapi32Util.alignOnDWORD(cbAcl); + WinNT.ACL pAcl = new WinNT.ACL(cbAcl); + if (!Advapi32.INSTANCE.InitializeAcl(pAcl, cbAcl, WinNT.ACL_REVISION)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_READ | WinNT.GENERIC_WRITE, pSidEverybody)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_ALL, pSidSystem)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_ALL, pSidAdmin)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WinNT.SECURITY_DESCRIPTOR sd = new WinNT.SECURITY_DESCRIPTOR(64 * 1024); + if (!Advapi32.INSTANCE.InitializeSecurityDescriptor(sd, WinNT.SECURITY_DESCRIPTOR_REVISION)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.SetSecurityDescriptorDacl(sd, true, pAcl, false)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WinBase.SECURITY_ATTRIBUTES sa = new WinBase.SECURITY_ATTRIBUTES(); + sa.dwLength = new WinDef.DWORD(sa.size()); + sa.lpSecurityDescriptor = sd.getPointer(); + return sa; + } + + /** + * {@inheritDoc} + */ + public void close() { + try { + if (!library.VirtualFreeEx(process, code.getPointer(), 0, MEM_RELEASE)) { + throw new Win32Exception(Native.getLastError()); + } + } finally { + if (!Kernel32.INSTANCE.CloseHandle(process)) { + throw new Win32Exception(Native.getLastError()); + } + } + } + + /** + * A library for interacting with Windows. + */ + protected interface WindowsLibrary extends StdCallLibrary { + + /** + * Changes the state of memory in a given process. + * + * @param process The process in which to change the memory. + * @param address The address of the memory to allocate. + * @param size The size of the allocated region. + * @param allocationType The allocation type. + * @param protect The memory protection. + * @return A pointer to the allocated memory. + */ + @SuppressWarnings({"unused", "checkstyle:methodname"}) + Pointer VirtualAllocEx(WinNT.HANDLE process, Pointer address, int size, int allocationType, int protect); + + /** + * Frees memory in the given process. + * + * @param process The process in which to change the memory. + * @param address The address of the memory to free. + * @param size The size of the freed region. + * @param freeType The freeing type. + * @return {@code true} if the operation succeeded. + */ + @SuppressWarnings("checkstyle:methodname") + boolean VirtualFreeEx(WinNT.HANDLE process, Pointer address, int size, int freeType); + + /** + * An alternative implementation of + * {@link Kernel32#CreateRemoteThread(WinNT.HANDLE, WinBase.SECURITY_ATTRIBUTES, int, WinBase.FOREIGN_THREAD_START_ROUTINE, Pointer, WinDef.DWORD, Pointer)} + * that uses a pointer as the {@code code} argument rather then a structure to avoid accessing foreign memory. + * + * @param process A handle of the target process. + * @param securityAttributes The security attributes to use or {@code null} if no attributes are provided. + * @param stackSize The stack size or {@code 0} for using the system default. + * @param code A pointer to the code to execute. + * @param argument A pointer to the argument to provide to the code being executed. + * @param creationFlags The creation flags or {@code null} if no flags are set. + * @param threadId A pointer to the thread id or {@code null} if no thread reference is set. + * @return A handle to the created remote thread or {@code null} if the creation failed. + */ + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE CreateRemoteThread(WinNT.HANDLE process, + WinBase.SECURITY_ATTRIBUTES securityAttributes, + int stackSize, + Pointer code, + Pointer argument, + WinDef.DWORD creationFlags, + Pointer threadId); + + /** + * Receives the exit code of a given thread. + * + * @param thread A handle to the targeted thread. + * @param exitCode A reference to the exit code value. + * @return {@code true} if the exit code retrieval succeeded. + */ + @SuppressWarnings("checkstyle:methodname") + boolean GetExitCodeThread(WinNT.HANDLE thread, IntByReference exitCode); + } + + /** + * A library for interacting with Windows. + */ + protected interface WindowsAttachLibrary extends StdCallLibrary { + + /** + * Allocates the code to invoke on the remote VM. + * + * @param process A handle to the target process. + * @return A pointer to the allocated code or {@code null} if the code could not be allocated. + */ + + @SuppressWarnings("checkstyle:methodname") + WinDef.LPVOID allocate_remote_code(WinNT.HANDLE process); + + /** + * Allocates the remote argument to supply to the remote code upon execution. + * + * @param process A handle to the target process. + * @param pipe The name of the pipe used for supplying an answer. + * @param argument0 The first argument or {@code null} if no such argument is provided. + * @param argument1 The second argument or {@code null} if no such argument is provided. + * @param argument2 The third argument or {@code null} if no such argument is provided. + * @param argument3 The forth argument or {@code null} if no such argument is provided. + * @return A pointer to the allocated argument or {@code null} if the argument could not be allocated. + */ + + @SuppressWarnings("checkstyle:methodname") + WinDef.LPVOID allocate_remote_argument(WinNT.HANDLE process, + String pipe, + String argument0, + String argument1, + String argument2, + String argument3); + } + + /** + * A response that is sent via a named pipe. + */ + protected static class NamedPipeResponse implements Response { + + /** + * A handle of the named pipe. + */ + private final WinNT.HANDLE pipe; + + /** + * Creates a new response via a named pipe. + * + * @param pipe The handle of the named pipe. + */ + protected NamedPipeResponse(WinNT.HANDLE pipe) { + this.pipe = pipe; + } + + /** + * {@inheritDoc} + */ + public int read(byte[] buffer) { + IntByReference read = new IntByReference(); + if (!Kernel32.INSTANCE.ReadFile(pipe, buffer, buffer.length, read, null)) { + int code = Native.getLastError(); + if (code == WinError.ERROR_BROKEN_PIPE) { + return -1; + } else { + throw new Win32Exception(code); + } + } + return read.getValue(); + } + + /** + * {@inheritDoc} + */ + public void close() { + try { + if (!Kernel32.INSTANCE.DisconnectNamedPipe(pipe)) { + throw new Win32Exception(Native.getLastError()); + } + } finally { + if (!Kernel32.INSTANCE.CloseHandle(pipe)) { + throw new Win32Exception(Native.getLastError()); + } + } + } + } + + /** + * A factory for establishing a connection to a JVM using a named pipe in JNA. + */ + public static class Factory implements Connection.Factory { + + /** + * The name of the native code library that is included in this artifact to support Windows attachment. + * This property can be set by other libraries that shade Byte Buddy agent and relocates the library. + */ + public static final String LIBRARY_NAME = "net.bytebuddy.library.name"; + + /** + * The library to use for communicating with Windows native functions. + */ + private final WindowsLibrary library; + + /** + * The library to use for communicating with Windows attachment extension that is included as a DLL. + */ + private final WindowsAttachLibrary attachLibrary; + + /** + * Creates a new connection factory for Windows using JNA. + */ + @SuppressWarnings("deprecation") + public Factory() { + library = Native.loadLibrary("kernel32", WindowsLibrary.class, W32APIOptions.DEFAULT_OPTIONS); + attachLibrary = Native.loadLibrary(System.getProperty(LIBRARY_NAME, "attach_hotspot_windows"), WindowsAttachLibrary.class); + } + + /** + * {@inheritDoc} + */ + public Connection connect(String processId) { + WinNT.HANDLE process = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_ALL_ACCESS, false, Integer.parseInt(processId)); + if (process == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + WinDef.LPVOID code = attachLibrary.allocate_remote_code(process); + if (code == null) { + throw new Win32Exception(Native.getLastError()); + } + return new ForJnaWindowsNamedPipe(library, attachLibrary, process, code); + } catch (Throwable throwable) { + if (!Kernel32.INSTANCE.CloseHandle(process)) { + throw new Win32Exception(Native.getLastError()); + } else if (throwable instanceof RuntimeException) { + throw (RuntimeException) throwable; + } else { + throw new IllegalStateException(throwable); + } + } + } + } + } + + /** + * A connection to a VM using a Solaris door. + */ + class ForJnaSolarisDoor implements Connection { + + /** + * The library to use for interacting with Solaris. + */ + private final SolarisLibrary library; + + /** + * The socket used for communication. + */ + private final File socket; + + /** + * Creates a new connection using a Solaris door. + * + * @param library The library to use for interacting with Solaris. + * @param socket The socket used for communication. + */ + protected ForJnaSolarisDoor(SolarisLibrary library, File socket) { + this.library = library; + this.socket = socket; + } + + /** + * {@inheritDoc} + */ + public Connection.Response execute(String protocol, String... argument) throws IOException { + int handle = library.open(socket.getAbsolutePath(), 2); + try { + SolarisLibrary.DoorArgument door = new SolarisLibrary.DoorArgument(); + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write(protocol.getBytes("UTF-8")); + outputStream.write(0); + for (String anArgument : argument) { + if (anArgument != null) { + outputStream.write(anArgument.getBytes("UTF-8")); + } + outputStream.write(0); + } + door.dataSize = outputStream.size(); + Memory dataPointer = new Memory(outputStream.size()); + try { + dataPointer.write(0, outputStream.toByteArray(), 0, outputStream.size()); + door.dataPointer = dataPointer; + Memory result = new Memory(128); + try { + door.resultPointer = result; + door.resultSize = (int) result.size(); + if (library.door_call(handle, door) != 0) { + throw new IllegalStateException("Door call to target VM failed"); + } else if (door.resultSize < 4 || door.resultPointer.getInt(0) != 0) { + throw new IllegalStateException("Target VM could not execute door call"); + } else if (door.descriptorCount != 1 || door.descriptorPointer == null) { + throw new IllegalStateException("Did not receive communication descriptor from target VM"); + } else { + return new Response(library, door.descriptorPointer.getInt(4)); + } + } finally { + result = null; + } + } finally { + dataPointer = null; + } + } finally { + door = null; + } + } finally { + library.close(handle); + } + } + + /** + * {@inheritDoc} + */ + public void close() { + /* do nothing */ + } + + /** + * A library for interacting with Solaris. + */ + protected interface SolarisLibrary extends Library { + + /** + * Sends a kill signal to the target VM. + * + * @param processId The target process's id. + * @param signal The signal to send. + * @return The return code. + * @throws LastErrorException If an error occurred while sending the signal. + */ + int kill(int processId, int signal) throws LastErrorException; + + /** + * Opens a file. + * + * @param file The file name. + * @param flags the flags for opening. + * @return The file descriptor. + * @throws LastErrorException If the file could not be opened. + */ + int open(String file, int flags) throws LastErrorException; + + /** + * Reads from a handle. + * + * @param handle The handle representing the source being read. + * @param buffer The buffer to read to. + * @param length The buffer length. + * @return The amount of bytes being read. + * @throws LastErrorException If a read operation failed. + */ + int read(int handle, ByteBuffer buffer, int length) throws LastErrorException; + + /** + * Releases a descriptor. + * + * @param descriptor The descriptor to release. + * @return The return code. + * @throws LastErrorException If the descriptor could not be closed. + */ + int close(int descriptor) throws LastErrorException; + + /** + * Executes a door call. + * + * @param descriptor The door's descriptor. + * @param argument A pointer to the argument. + * @return The door's handle. + * @throws LastErrorException If the door call failed. + */ + @SuppressWarnings("checkstyle:methodname") + int door_call(int descriptor, DoorArgument argument) throws LastErrorException; + + /** + * A structure representing the argument to a Solaris door operation. + */ + class DoorArgument extends Structure { + + /** + * A pointer to the operation argument. + */ + + public Pointer dataPointer; + + /** + * The size of the argument being pointed to. + */ + public int dataSize; + + /** + * A pointer to the operation descriptor. + */ + + public Pointer descriptorPointer; + + /** + * The size of the operation argument. + */ + public int descriptorCount; + + /** + * A pointer to the operation result. + */ + public Pointer resultPointer; + + /** + * The size of the operation argument. + */ + public int resultSize; + + @Override + protected List getFieldOrder() { + return Arrays.asList("dataPointer", "dataSize", "descriptorPointer", "descriptorCount", "resultPointer", "resultSize"); + } + } + } + + /** + * A response from a VM using a Solaris door. + */ + protected static class Response implements Connection.Response { + + /** + * The Solaris library to use. + */ + private final SolarisLibrary library; + + /** + * The door handle. + */ + private final int handle; + + /** + * Creates a response from a VM using a Solaris door. + * + * @param library The Solaris library to use. + * @param handle The door handle. + */ + protected Response(SolarisLibrary library, int handle) { + this.library = library; + this.handle = handle; + } + + /** + * {@inheritDoc} + */ + public int read(byte[] buffer) { + int read = library.read(handle, ByteBuffer.wrap(buffer), buffer.length); + return read == 0 ? -1 : read; + } + + /** + * {@inheritDoc} + */ + public void close() { + library.close(handle); + } + } + + /** + * A factory for establishing a connection to a JVM using a Solaris door in JNA. + */ + public static class Factory extends Connection.Factory.ForSocketFile { + + /** + * The library to use for interacting with Solaris. + */ + private final SolarisLibrary library; + + /** + * Creates a new connection factory for a Solaris VM. + * + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + */ + @SuppressWarnings("deprecation") + public Factory(int attempts, long pause, TimeUnit timeUnit) { + super("/tmp", attempts, pause, timeUnit); + library = Native.loadLibrary("c", SolarisLibrary.class); + } + + /** + * {@inheritDoc} + */ + protected void kill(String processId, int signal) { + library.kill(Integer.parseInt(processId), signal); + } + + /** + * {@inheritDoc} + */ + protected Connection doConnect(File socket) { + return new ForJnaSolarisDoor(library, socket); + } + } + } + } + } + + /** + * A virtual machine attachment implementation for OpenJ9 or any compatible JVM. + */ + class ForOpenJ9 extends AbstractBase { + + /** + * The temporary folder for attachment files for OpenJ9 VMs. + */ + private static final String IBM_TEMPORARY_FOLDER = "com.ibm.tools.attach.directory"; + + /** + * A secure random for generating randomized ids. + */ + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + + /** + * The socket on which this VM and the target VM communicate. + */ + private final Socket socket; + + /** + * Creates a new virtual machine connection for OpenJ9. + * + * @param socket The socket on which this VM and the target VM communicate. + */ + protected ForOpenJ9(Socket socket) { + this.socket = socket; + } + + /** + * Attaches to the supplied process id using the default JNA implementation. This method will not consider + * attaching to VMs owned by different users than the current user. + * + * @param processId The process id. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId) throws IOException { + return attach(processId, 5000, Platform.isWindows() + ? new Dispatcher.ForJnaWindowsEnvironment() + : new Dispatcher.ForJnaPosixEnvironment(15, 100, TimeUnit.MILLISECONDS)); + } + + /** + * Attaches to the supplied process id. + * + * @param processId The process id. + * @param timeout The timeout for establishing the socket connection. + * @param dispatcher The connector to use to communicate with the target VM. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId, int timeout, Dispatcher dispatcher) throws IOException { + String temporary = System.getProperty(IBM_TEMPORARY_FOLDER); + File directory = temporary == null + ? new File(dispatcher.getTemporaryFolder(processId), ".com_ibm_tools_attach") + : new File(temporary); + long userId = dispatcher.userId(); + RandomAccessFile attachLock = new RandomAccessFile(new File(directory, "_attachlock"), "rw"); + try { + FileLock attachLockLock = attachLock.getChannel().lock(); + try { + List virtualMachines; + RandomAccessFile master = new RandomAccessFile(new File(directory, "_master"), "rw"); + try { + FileLock masterLock = master.getChannel().lock(); + try { + File[] vmFolder = directory.listFiles(); + if (vmFolder == null) { + throw new IllegalStateException("No descriptor files found in " + directory); + } + virtualMachines = new ArrayList(); + for (File aVmFolder : vmFolder) { + if (aVmFolder.isDirectory() && (userId == 0L || dispatcher.getOwnerIdOf(aVmFolder) == userId)) { + File attachInfo = new File(aVmFolder, "attachInfo"); + if (attachInfo.isFile()) { + Properties virtualMachine = new Properties(); + FileInputStream inputStream = new FileInputStream(attachInfo); + try { + virtualMachine.load(inputStream); + } finally { + inputStream.close(); + } + int targetProcessId = Integer.parseInt(virtualMachine.getProperty("processId")); + long targetUserId; + try { + targetUserId = Long.parseLong(virtualMachine.getProperty("userUid")); + } catch (NumberFormatException ignored) { + targetUserId = 0L; + } + if (userId != 0L && targetUserId == 0L) { + targetUserId = dispatcher.getOwnerIdOf(attachInfo); + } + if (targetProcessId == 0L || dispatcher.isExistingProcess(targetProcessId)) { + virtualMachines.add(virtualMachine); + } else if (userId == 0L || targetUserId == userId) { + File[] vmFile = aVmFolder.listFiles(); + if (vmFile != null) { + for (File aVmFile : vmFile) { + if (!aVmFile.delete()) { + aVmFile.deleteOnExit(); + } + } + } + if (!aVmFolder.delete()) { + aVmFolder.deleteOnExit(); + } + } + } + } + } + } finally { + masterLock.release(); + } + } finally { + master.close(); + } + Properties target = null; + for (Properties virtualMachine : virtualMachines) { + if (virtualMachine.getProperty("processId").equalsIgnoreCase(processId)) { + target = virtualMachine; + break; + } + } + if (target == null) { + throw new IllegalStateException("Could not locate target process info in " + directory); + } + ServerSocket serverSocket = new ServerSocket(0); + try { + serverSocket.setSoTimeout(timeout); + File receiver = new File(directory, target.getProperty("vmId")); + String key; + synchronized (SECURE_RANDOM) { + key = Long.toHexString(SECURE_RANDOM.nextLong()); + } + File reply = new File(receiver, "replyInfo"); + long targetUserId; + try { + targetUserId = Long.parseLong(target.getProperty("userUid")); + } catch (NumberFormatException ignored) { + targetUserId = 0L; + } + try { + if (reply.createNewFile()) { + dispatcher.setPermissions(reply, 0600); + } + if (userId == 0L && targetUserId != 0L) { + dispatcher.chownFileToUser(reply, targetUserId); + } + FileOutputStream outputStream = new FileOutputStream(reply); + try { + outputStream.write(key.getBytes("UTF-8")); + outputStream.write("\n".getBytes("UTF-8")); + outputStream.write(Long.toString(serverSocket.getLocalPort()).getBytes("UTF-8")); + outputStream.write("\n".getBytes("UTF-8")); + } finally { + outputStream.close(); + } + Map locks = new HashMap(); + try { + String pid = Long.toString(dispatcher.pid()); + for (Properties virtualMachine : virtualMachines) { + if (!virtualMachine.getProperty("processId").equalsIgnoreCase(pid)) { + String attachNotificationSync = virtualMachine.getProperty("attachNotificationSync"); + RandomAccessFile syncFile = new RandomAccessFile(attachNotificationSync == null + ? new File(directory, "attachNotificationSync") + : new File(attachNotificationSync), "rw"); + try { + locks.put(syncFile, syncFile.getChannel().lock()); + } catch (IOException ignored) { + syncFile.close(); + } + } + } + int notifications = 0; + File[] item = directory.listFiles(); + if (item != null) { + for (File anItem : item) { + String name = anItem.getName(); + if (!name.startsWith(".trash_") + && !name.equalsIgnoreCase("_attachlock") + && !name.equalsIgnoreCase("_master") + && !name.equalsIgnoreCase("_notifier")) { + notifications += 1; + } + } + } + boolean global = Boolean.parseBoolean(target.getProperty("globalSemaphore")); + dispatcher.incrementSemaphore(directory, "_notifier", global, notifications); + try { + Socket socket = serverSocket.accept(); + String answer = new String(read(socket), "UTF-8"); + if (answer.contains(' ' + key + ' ')) { + return new ForOpenJ9(socket); + } else { + socket.close(); + throw new IllegalStateException("Unexpected answered to attachment: " + answer); + } + } finally { + dispatcher.decrementSemaphore(directory, "_notifier", global, notifications); + } + } finally { + for (Map.Entry entry : locks.entrySet()) { + try { + try { + entry.getValue().release(); + } finally { + entry.getKey().close(); + } + } catch (Throwable ignored) { + /* do nothing */ + } + } + } + } finally { + if (!reply.delete()) { + reply.deleteOnExit(); + } + } + } finally { + serverSocket.close(); + } + } finally { + attachLockLock.release(); + } + } finally { + attachLock.close(); + } + } + + /** + * {@inheritDoc} + */ + public Properties getSystemProperties() throws IOException { + write(socket, "ATTACH_GETSYSTEMPROPERTIES".getBytes("UTF-8")); + Properties properties = new Properties(); + properties.load(new ByteArrayInputStream(read(socket))); + return properties; + } + + /** + * {@inheritDoc} + */ + public Properties getAgentProperties() throws IOException { + write(socket, "ATTACH_GETAGENTPROPERTIES".getBytes("UTF-8")); + Properties properties = new Properties(); + properties.load(new ByteArrayInputStream(read(socket))); + return properties; + } + + /** + * {@inheritDoc} + */ + public void loadAgent(String jarFile, String argument) throws IOException { + write(socket, ("ATTACH_LOADAGENT(instrument," + jarFile + '=' + (argument == null ? "" : argument) + ')').getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM failed loading agent: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void loadAgentPath(String path, String argument) throws IOException { + write(socket, ("ATTACH_LOADAGENTPATH(" + path + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM failed loading native agent: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void loadAgentLibrary(String library, String argument) throws IOException { + write(socket, ("ATTACH_LOADAGENTLIBRARY(" + library + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM failed loading native library: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void startManagementAgent(Properties properties) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + properties.store(outputStream, null); + write(socket, "ATTACH_START_MANAGEMENT_AGENT".getBytes("UTF-8")); + write(socket, outputStream.toByteArray()); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM could not start management agent: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public String startLocalManagementAgent() throws IOException { + write(socket, "ATTACH_START_LOCAL_MANAGEMENT_AGENT".getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM could not start management agent: " + answer); + } else if (answer.startsWith("ATTACH_ACK")) { + return answer.substring("ATTACH_ACK".length()); + } else if (answer.startsWith("ATTACH_RESULT=")) { + return answer.substring("ATTACH_RESULT=".length()); + } else { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void detach() throws IOException { + try { + write(socket, "ATTACH_DETACH".getBytes("UTF-8")); + read(socket); // The answer is intentionally ignored. + } finally { + socket.close(); + } + } + + /** + * Writes the supplied value to the target socket. + * + * @param socket The socket to write to. + * @param value The value being written. + * @throws IOException If an I/O exception occurs. + */ + private static void write(Socket socket, byte[] value) throws IOException { + socket.getOutputStream().write(value); + socket.getOutputStream().write(0); + socket.getOutputStream().flush(); + } + + /** + * Reads a {@code '\0'}-terminated value from the target socket. + * + * @param socket The socket to read from. + * @return The value that was read. + * @throws IOException If an I/O exception occurs. + */ + private static byte[] read(Socket socket) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = socket.getInputStream().read(buffer)) != -1) { + if (length > 0 && buffer[length - 1] == 0) { + outputStream.write(buffer, 0, length - 1); + break; + } else { + outputStream.write(buffer, 0, length); + } + } + return outputStream.toByteArray(); + } + + /** + * A dispatcher for native operations being used for communication with an OpenJ9 virtual machine. + */ + public interface Dispatcher { + + /** + * Returns this machine's temporary folder. + * + * @param processId The target process's id. + * @return The temporary folder. + */ + String getTemporaryFolder(String processId); + + /** + * Returns the process id of this process. + * + * @return The process id of this process. + */ + int pid(); + + /** + * Returns the user id of this process. + * + * @return The user id of this process + */ + int userId(); + + /** + * Returns {@code true} if the supplied process id is a running process. + * + * @param processId The process id to evaluate. + * @return {@code true} if the supplied process id is currently running. + */ + boolean isExistingProcess(int processId); + + /** + * Returns the user id of the owner of the supplied file. + * + * @param file The file for which to locate the owner. + * @return The owner id of the supplied file. + */ + int getOwnerIdOf(File file); + + /** + * Sets permissions for the supplied file. + * + * @param file The file for which to set the permissions. + * @param permissions The permission bits to set. + */ + void setPermissions(File file, int permissions); + + /** + * Increments a semaphore. + * + * @param directory The sempahore's control directory. + * @param name The semaphore's name. + * @param global {@code true} if the semaphore is in the global namespace (only applicable on Windows). + * @param count The amount of increments. + */ + void incrementSemaphore(File directory, String name, boolean global, int count); + + /** + * Decrements a semaphore. + * + * @param directory The sempahore's control directory. + * @param name The semaphore's name. + * @param global {@code true} if the semaphore is in the global namespace (only applicable on Windows). + * @param count The amount of decrements. + */ + void decrementSemaphore(File directory, String name, boolean global, int count); + + /** + * Changes the ownership of a file. Can be called only if this process is owned by root. + * + * @param file The path of the file to change ownership of. + * @param userId The user that should own the file. + */ + void chownFileToUser(File file, long userId); + + /** + * A connector implementation for a POSIX environment using JNA. + */ + class ForJnaPosixEnvironment implements Dispatcher { + + /** + * The JNA library to use. + */ + private final PosixLibrary library; + + /** + * The POSIX owner provider to use. + */ + private final PosixOwnerProvider provider; + + /** + * Creates a new connector for a POSIX environment using JNA. + * + * @param attempts The maximum amount of attempts for checking the result of a foreign process. + * @param pause The pause between two checks for another process to return. + * @param timeUnit The time unit of the pause time. + */ + @SuppressWarnings("deprecation") + public ForJnaPosixEnvironment(int attempts, long pause, TimeUnit timeUnit) { + provider = Platform.isAIX() + ? new PosixOwnerProvider.UsingIStat(attempts, pause, timeUnit) + : new PosixOwnerProvider.UsingStat(attempts, pause, timeUnit); + library = Native.loadLibrary("c", PosixLibrary.class); + } + + /** + * {@inheritDoc} + */ + public String getTemporaryFolder(String processId) { + if (Platform.isLinux()) { + File file = new File("/proc/" + processId + "/root/tmp"); + if (file.isDirectory() && file.canRead()) { + return file.getAbsolutePath(); + } + } + String temporaryFolder = System.getenv("TMPDIR"); + return temporaryFolder == null ? "/tmp" : temporaryFolder; + } + + /** + * {@inheritDoc} + */ + public int pid() { + return library.getpid(); + } + + /** + * {@inheritDoc} + */ + public int userId() { + return library.getuid(); + } + + /** + * {@inheritDoc} + */ + public boolean isExistingProcess(int processId) { + return library.kill(processId, PosixLibrary.NULL_SIGNAL) != PosixLibrary.ESRCH; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + return provider.getOwnerIdOf(file); + } + + /** + * {@inheritDoc} + */ + public void setPermissions(File file, int permissions) { + library.chmod(file.getAbsolutePath(), permissions); + } + + /** + * {@inheritDoc} + */ + public void incrementSemaphore(File directory, String name, boolean global, int count) { + notifySemaphore(directory, name, count, (short) 1, (short) 0, false); + } + + /** + * {@inheritDoc} + */ + public void decrementSemaphore(File directory, String name, boolean global, int count) { + notifySemaphore(directory, name, count, (short) -1, (short) (PosixLibrary.SEM_UNDO | PosixLibrary.IPC_NOWAIT), true); + } + + /** + * {@inheritDoc} + */ + public void chownFileToUser(File file, long userId) { + library.chown(file.getAbsolutePath(), userId); + } + + /** + * Notifies a POSIX semaphore. + * + * @param directory The semaphore's directory. + * @param name The semaphore's name. + * @param count The amount of notifications to send. + * @param operation The operation to apply. + * @param flags The flags to set. + * @param acceptUnavailable {@code true} if a {@code EAGAIN} code should be accepted. + */ + private void notifySemaphore(File directory, String name, int count, short operation, short flags, boolean acceptUnavailable) { + int semaphore = library.semget(library.ftok(new File(directory, name).getAbsolutePath(), 0xA1), 2, 0666); + PosixLibrary.SemaphoreOperation target = new PosixLibrary.SemaphoreOperation(); + target.operation = operation; + target.flags = flags; + while (count-- > 0) { + try { + library.semop(semaphore, target, 1); + } catch (LastErrorException exception) { + if (acceptUnavailable && (Native.getLastError() == PosixLibrary.EAGAIN + || Native.getLastError() == PosixLibrary.EDEADLK)) { + break; + } else { + throw exception; + } + } + } + } + + /** + * An API for interaction with POSIX systems. + */ + protected interface PosixLibrary extends Library { + + /** + * A null signal. + */ + int NULL_SIGNAL = 0; + + /** + * Indicates that a process does not exist. + */ + int ESRCH = 3; + + /** + * Indicates that a request timed out. + */ + int EAGAIN = 11; + + /** + * Indicates a dead lock on a resource. + */ + int EDEADLK = 35; + + /** + * Indicates that a semaphore's operations should be undone at process shutdown. + */ + short SEM_UNDO = 0x1000; + + /** + * Indicates that one should not wait for the release of a semaphore if it is not currently available. + */ + short IPC_NOWAIT = 04000; + + /** + * Runs the {@code getpid} command. + * + * @return The command's return value. + * @throws LastErrorException If an error occurred. + */ + int getpid() throws LastErrorException; + + /** + * Runs the {@code getuid} command. + * + * @return The command's return value. + * @throws LastErrorException If an error occurred. + */ + int getuid() throws LastErrorException; + + /** + * Runs the {@code kill} command. + * + * @param processId The target process id. + * @param signal The signal to send. + * @return The command's return value. + * @throws LastErrorException If an error occurred. + */ + int kill(int processId, int signal) throws LastErrorException; + + /** + * Runs the {@code chmod} command. + * + * @param path The file path. + * @param mode The mode to set. + * @return The return code. + * @throws LastErrorException If an error occurred. + */ + int chmod(String path, int mode) throws LastErrorException; + + /** + * Runs the {@code chown} command. + * + * @param path The file path. + * @param userId The user id to set. + * @return The return code. + * @throws LastErrorException If an error occurred. + */ + int chown(String path, long userId) throws LastErrorException; + + /** + * Runs the {@code ftok} command. + * + * @param path The file path. + * @param id The id being used for creating the generated key. + * @return The generated key. + * @throws LastErrorException If an error occurred. + */ + int ftok(String path, int id) throws LastErrorException; + + /** + * Runs the {@code semget} command. + * + * @param key The key of the semaphore. + * @param count The initial count of the semaphore. + * @param flags The flags to set. + * @return The id of the semaphore. + * @throws LastErrorException If an error occurred. + */ + int semget(int key, int count, int flags) throws LastErrorException; + + /** + * Runs the {@code semop} command. + * + * @param id The id of the semaphore. + * @param operation The initial count of the semaphore. + * @param flags The flags to set. + * @return The return code. + * @throws LastErrorException If the operation was not successful. + */ + int semop(int id, SemaphoreOperation operation, int flags) throws LastErrorException; + + /** + * A structure to represent a semaphore operation for {@code semop}. + */ + class SemaphoreOperation extends Structure { + + /** + * The semaphore number. + */ + @SuppressWarnings("unused") + public short number; + + /** + * The operation to execute. + */ + public short operation; + + /** + * The flags being set for the operation. + */ + public short flags; + + @Override + protected List getFieldOrder() { + return Arrays.asList("number", "operation", "flags"); + } + } + } + + /** + * Represents a system that supports POSIX ownership. + */ + protected interface PosixOwnerProvider { + + /** + * Returns the user id of the owner of the supplied file. + * + * @param file The file for which to locate the owner. + * @return The owner id of the supplied file. + */ + int getOwnerIdOf(File file); + + /** + * An implementation of reading POSIX ownership using {@code stat}. + */ + class UsingStat implements PosixOwnerProvider { + + /** + * The maximum amount of attempts for checking the result of a foreign process. + */ + private final int attempts; + + /** + * The pause between two checks for another process to return. + */ + private final long pause; + + /** + * The time unit of the pause time. + */ + private final TimeUnit timeUnit; + + /** + * Creates a new provider where an owner is derived using the {@code stat} command. + * + * @param attempts The maximum amount of attempts for checking the result of a foreign process. + * @param pause The pause between two checks for another process to return. + * @param timeUnit The time unit of the pause time. + */ + public UsingStat(int attempts, long pause, TimeUnit timeUnit) { + this.attempts = attempts; + this.pause = pause; + this.timeUnit = timeUnit; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + try { + // The binding for 'stat' is very platform dependant. To avoid the complexity of binding the correct method, + // stat is called as a separate command. This is less efficient but more portable. + Process process = Runtime.getRuntime().exec(new String[]{"stat", + Platform.isMac() ? "-f" : "-c", + "%u", + file.getAbsolutePath()}); + int attempts = this.attempts; + String line = null; + do { + try { + if (process.exitValue() != 0) { + throw new IllegalStateException("Error while executing stat"); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); + try { + line = reader.readLine(); + } finally { + reader.close(); + } + break; + } catch (IllegalThreadStateException ignored) { + try { + Thread.sleep(timeUnit.toMillis(pause)); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(exception); + } + } + } while (--attempts > 0); + if (line == null) { + process.destroy(); + throw new IllegalStateException("Command for stat did not exit in time"); + } + return Integer.parseInt(line); + } catch (IOException exception) { + throw new IllegalStateException("Unable to execute stat command", exception); + } + } + } + + /** + * An implementation for reading a POSIX owner using {@code istat}. + */ + class UsingIStat implements PosixOwnerProvider { + + /** + * A pattern to represent the owner on the console output. + */ + private static final Pattern AIX_OWNER_PATTERN = Pattern.compile("Owner: (\\d+)\\("); + + /** + * The maximum amount of attempts for checking the result of a foreign process. + */ + private final int attempts; + + /** + * The pause between two checks for another process to return. + */ + private final long pause; + + /** + * The time unit of the pause time. + */ + private final TimeUnit timeUnit; + + /** + * Creates a new provider for reading a POSIX owner using {@code istat}. + * + * @param attempts The maximum amount of attempts for checking the result of a foreign process. + * @param pause The pause between two checks for another process to return. + * @param timeUnit The time unit of the pause time. + */ + public UsingIStat(int attempts, long pause, TimeUnit timeUnit) { + this.attempts = attempts; + this.pause = pause; + this.timeUnit = timeUnit; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + try { + Process process = Runtime.getRuntime().exec(new String[]{"istat", file.getAbsolutePath()}); + int attempts = this.attempts; + String lines = null; + do { + try { + if (process.exitValue() != 0) { + throw new IllegalStateException("Error while executing istat"); + } + StringBuilder output = new StringBuilder(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); + try { + String line; + while ((line = reader.readLine()) != null) { + output.append(line).append("\n"); + } + } finally { + reader.close(); + } + lines = output.toString(); + break; + } catch (IllegalThreadStateException ignored) { + try { + Thread.sleep(timeUnit.toMillis(pause)); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(exception); + } + } + } while (--attempts > 0); + if (lines == null) { + process.destroy(); + throw new IllegalStateException("Command for istat did not exit in time"); + } + Matcher matcher = AIX_OWNER_PATTERN.matcher(lines); + if (matcher.find()) { + return Integer.parseInt(matcher.group(1)); + } else { + throw new IllegalStateException("Unable to parse response from istat command: " + lines); + } + } catch (IOException exception) { + throw new IllegalStateException("Unable to execute istat command", exception); + } + } + } + } + } + + /** + * A connector implementation for a Windows environment using JNA. + */ + class ForJnaWindowsEnvironment implements Dispatcher { + + /** + * Indicates a missing user id what is not supported on Windows. + */ + private static final int NO_USER_ID = 0; + + /** + * The name of the creation mutex. + */ + private static final String CREATION_MUTEX_NAME = "j9shsemcreationMutex"; + + /** + * A library to use for interacting with Windows. + */ + private final WindowsLibrary library; + + /** + * Creates a new connector for a Windows environment using JNA. + */ + @SuppressWarnings("deprecation") + public ForJnaWindowsEnvironment() { + library = Native.loadLibrary("kernel32", WindowsLibrary.class, W32APIOptions.DEFAULT_OPTIONS); + } + + /** + * {@inheritDoc} + */ + public String getTemporaryFolder(String processId) { + WinDef.DWORD length = new WinDef.DWORD(WinDef.MAX_PATH); + char[] path = new char[length.intValue()]; + if (Kernel32.INSTANCE.GetTempPath(length, path).intValue() == 0) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return Native.toString(path); + } + + /** + * {@inheritDoc} + */ + public int pid() { + return Kernel32.INSTANCE.GetCurrentProcessId(); + } + + /** + * {@inheritDoc} + */ + public int userId() { + return NO_USER_ID; + } + + /** + * {@inheritDoc} + */ + public boolean isExistingProcess(int processId) { + WinNT.HANDLE handle = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION, false, processId); + if (handle == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + IntByReference exists = new IntByReference(); + if (!Kernel32.INSTANCE.GetExitCodeProcess(handle, exists)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return exists.getValue() == WinBase.STILL_ACTIVE; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + return NO_USER_ID; + } + + /** + * {@inheritDoc} + */ + public void setPermissions(File file, int permissions) { + /* do nothing */ + } + + /** + * {@inheritDoc} + */ + public void incrementSemaphore(File directory, String name, boolean global, int count) { + AttachmentHandle handle = openSemaphore(directory, name, global); + try { + while (count-- > 0) { + if (!library.ReleaseSemaphore(handle.getHandle(), 1, null)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } + } finally { + handle.close(); + } + } + + /** + * {@inheritDoc} + */ + public void decrementSemaphore(File directory, String name, boolean global, int count) { + AttachmentHandle handle = openSemaphore(directory, name, global); + try { + while (count-- > 0) { + int result = Kernel32.INSTANCE.WaitForSingleObject(handle.getHandle(), 0); + switch (result) { + case WinBase.WAIT_ABANDONED: + case WinBase.WAIT_OBJECT_0: + break; + case WinError.WAIT_TIMEOUT: + return; + default: + throw new Win32Exception(result); + } + } + } finally { + handle.close(); + } + } + + /** + * {@inheritDoc} + */ + public void chownFileToUser(File file, long userId) { + /* do nothing */ + } + + /** + * Opens a semaphore for signaling another process that an attachment is performed. + * + * @param directory The control directory. + * @param name The semaphore's name. + * @param global {@code true} if the semaphore is in the global namespace. + * @return A handle for signaling an attachment to the target process. + */ + private AttachmentHandle openSemaphore(File directory, String name, boolean global) { + WinNT.SECURITY_DESCRIPTOR securityDescriptor = new WinNT.SECURITY_DESCRIPTOR(64 * 1024); + try { + if (!Advapi32.INSTANCE.InitializeSecurityDescriptor(securityDescriptor, WinNT.SECURITY_DESCRIPTOR_REVISION)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.SetSecurityDescriptorDacl(securityDescriptor, true, null, true)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WindowsLibrary.SecurityAttributes securityAttributes = new WindowsLibrary.SecurityAttributes(); + try { + securityAttributes.length = new WinDef.DWORD(securityAttributes.size()); + securityAttributes.securityDescriptor = securityDescriptor.getPointer(); + WinNT.HANDLE mutex = library.CreateMutex(securityAttributes, false, CREATION_MUTEX_NAME); + if (mutex == null) { + int lastError = Kernel32.INSTANCE.GetLastError(); + if (lastError == WinError.ERROR_ALREADY_EXISTS) { + mutex = library.OpenMutex(WinNT.STANDARD_RIGHTS_REQUIRED | WinNT.SYNCHRONIZE | 0x0001, false, CREATION_MUTEX_NAME); + if (mutex == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } else { + throw new Win32Exception(lastError); + } + } + int result = Kernel32.INSTANCE.WaitForSingleObject(mutex, 2000); + switch (result) { + case WinBase.WAIT_FAILED: + case WinError.WAIT_TIMEOUT: + throw new Win32Exception(result); + default: + try { + String target = (global ? "Global\\" : "") + + (directory.getAbsolutePath() + '_' + name).replaceAll("[^a-zA-Z0-9_]", "") + + "_semaphore"; + WinNT.HANDLE parent = library.OpenSemaphoreW(WindowsLibrary.SEMAPHORE_ALL_ACCESS, false, target); + if (parent == null) { + parent = library.CreateSemaphoreW(null, 0, Integer.MAX_VALUE, target); + if (parent == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WinNT.HANDLE child = library.CreateSemaphoreW(null, 0, Integer.MAX_VALUE, target + "_set0"); + if (child == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return new AttachmentHandle(parent, child); + } else { + WinNT.HANDLE child = library.OpenSemaphoreW(WindowsLibrary.SEMAPHORE_ALL_ACCESS, false, target + "_set0"); + if (child == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return new AttachmentHandle(parent, child); + } + } finally { + if (!library.ReleaseMutex(mutex)) { + throw new Win32Exception(Native.getLastError()); + } + } + } + } finally { + securityAttributes = null; + } + } finally { + securityDescriptor = null; + } + } + + /** + * A library for interacting with Windows. + */ + protected interface WindowsLibrary extends StdCallLibrary { + + /** + * Indicates that a semaphore requires all access rights. + */ + int SEMAPHORE_ALL_ACCESS = 0x1F0003; + + /** + * Opens an existing semaphore. + * + * @param access The access rights. + * @param inheritHandle {@code true} if the handle is inherited. + * @param name The semaphore's name. + * @return The handle or {@code null} if the handle could not be created. + */ + + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE OpenSemaphoreW(int access, boolean inheritHandle, String name); + + /** + * Creates a new semaphore. + * + * @param securityAttributes The security attributes for the created semaphore. + * @param count The initial count for the semaphore. + * @param maximumCount The maximum count for the semaphore. + * @param name The semaphore's name. + * @return The handle or {@code null} if the handle could not be created. + */ + + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE CreateSemaphoreW(WinBase.SECURITY_ATTRIBUTES securityAttributes, + long count, + long maximumCount, + String name); + + /** + * Releases the semaphore. + * + * @param handle The semaphore's handle. + * @param count The amount with which to increase the semaphore. + * @param previousCount The previous count of the semaphore or {@code null}. + * @return {@code true} if the semaphore was successfully released. + */ + @SuppressWarnings("checkstyle:methodname") + boolean ReleaseSemaphore(WinNT.HANDLE handle, long count, Long previousCount); + + /** + * Create or opens a mutex. + * + * @param attributes The mutex's security attributes. + * @param owner {@code true} if the caller is supposed to be the initial owner. + * @param name The mutex name. + * @return The handle to the mutex or {@code null} if the mutex could not be created. + */ + + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE CreateMutex(SecurityAttributes attributes, boolean owner, String name); + + /** + * Opens an existing object. + * + * @param access The required access privileges. + * @param inherit {@code true} if the mutex should be inherited. + * @param name The mutex's name. + * @return The handle or {@code null} if the mutex could not be opened. + */ + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE OpenMutex(int access, boolean inherit, String name); + + /** + * Releases the supplied mutex. + * + * @param handle The handle to the mutex. + * @return {@code true} if the handle was successfully released. + */ + @SuppressWarnings("checkstyle:methodname") + boolean ReleaseMutex(WinNT.HANDLE handle); + + /** + * A structure representing a mutex's security attributes. + */ + class SecurityAttributes extends Structure { + + /** + * The descriptor's length. + */ + + public WinDef.DWORD length; + + /** + * A pointer to the descriptor. + */ + + public Pointer securityDescriptor; + + /** + * {@code true} if the attributes are inherited. + */ + @SuppressWarnings("unused") + public boolean inherit; + + @Override + protected List getFieldOrder() { + return Arrays.asList("length", "securityDescriptor", "inherit"); + } + } + } + + /** + * A handle for an attachment which is represented by a pair of handles. + */ + protected static class AttachmentHandle implements Closeable { + + /** + * The parent handle. + */ + private final WinNT.HANDLE parent; + + /** + * The child handle. + */ + private final WinNT.HANDLE child; + + /** + * Creates a new attachment handle. + * + * @param parent The parent handle. + * @param child The child handle. + */ + protected AttachmentHandle(WinNT.HANDLE parent, WinNT.HANDLE child) { + this.parent = parent; + this.child = child; + } + + /** + * Returns the handle on which signals are to be sent. + * + * @return The handle on which signals are to be sent. + */ + protected WinNT.HANDLE getHandle() { + return child; + } + + /** + * {@inheritDoc} + */ + public void close() { + boolean closed; + try { + if (!Kernel32.INSTANCE.CloseHandle(child)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } finally { + closed = Kernel32.INSTANCE.CloseHandle(parent); + } + if (!closed) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/utils/CommonUtil.java b/generator/src/main/java/com/reajason/javaweb/memshell/utils/CommonUtil.java index 8406b02e..d70ff7df 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/utils/CommonUtil.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/utils/CommonUtil.java @@ -91,6 +91,10 @@ public class CommonUtil { return PACKAGE_NAMES[new Random().nextInt(PACKAGE_NAMES.length)] + "." + getRandomString(5); } + public static String getPackageName(String className) { + return className.substring(0, className.lastIndexOf(".")); + } + public static String generateShellClassName() { return getRandomPackageName() + ".ErrorHandler"; } diff --git a/generator/src/main/resources/win32-x86-64/attach_hotspot_windows.dll b/generator/src/main/resources/win32-x86-64/attach_hotspot_windows.dll new file mode 100755 index 0000000000000000000000000000000000000000..6748a72a0a7c2cad795fa3d29b24bbd6ffafcf58 GIT binary patch literal 301843 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 KoEY>Sfd2!&?XZ&o literal 0 HcmV?d00001 diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java index ed16d308..b30b7d28 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertionTool.java @@ -5,6 +5,8 @@ import com.reajason.javaweb.behinder.BehinderManager; import com.reajason.javaweb.godzilla.GodzillaManager; import com.reajason.javaweb.memshell.*; import com.reajason.javaweb.memshell.config.*; +import com.reajason.javaweb.memshell.packer.jar.AgentJarPacker; +import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJREAttacherPacker; import com.reajason.javaweb.memshell.packer.jar.JarPacker; import com.reajason.javaweb.suo5.Suo5Manager; import lombok.SneakyThrows; @@ -16,6 +18,7 @@ import okhttp3.Request; import okhttp3.Response; import org.java_websocket.client.WebSocketClient; import org.java_websocket.handshake.ServerHandshake; +import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; import org.testcontainers.shaded.org.apache.commons.io.FileUtils; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; @@ -92,13 +95,12 @@ public class ShellAssertionTool { @SneakyThrows public static void packerResultAndInject(GenerateResult generateResult, String url, ShellTool shellTool, String shellType, Packers packer, GenericContainer appContainer) { String content = null; - if (packer.getInstance() instanceof JarPacker) { + if (packer.getInstance() instanceof AgentJarPacker) { byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult); Path tempJar = Files.createTempFile("temp", "jar"); Files.write(tempJar, bytes); String jarPath = "/" + shellTool + shellType + packer.name() + ".jar"; appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath); -// Files.copy(tempJar, Paths.get("target.jar")); FileUtils.deleteQuietly(tempJar.toFile()); String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout(); assertDoesNotThrow(() -> Long.parseLong(pidInContainer)); @@ -108,6 +110,27 @@ public class ShellAssertionTool { containsString("ATTACH_ACK"), containsString("JVM response code = 0") )); + } else if (packer.getInstance() instanceof AgentJarWithJREAttacherPacker) { + byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult); + Path tempJar = Files.createTempFile("temp", "jar"); + Files.write(tempJar, bytes); + String jarPath = "/" + shellTool + shellType + packer.name() + ".jar"; + appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath); + FileUtils.deleteQuietly(tempJar.toFile()); + String pidInContainer = appContainer.execInContainer("bash", "/fetch_pid.sh").getStdout(); + assertDoesNotThrow(() -> Long.parseLong(pidInContainer)); + Container.ExecResult execResult = appContainer.execInContainer("java", "-jar", jarPath, pidInContainer); + String stdout = execResult.getStdout(); + if (stdout.contains("executable file not found")) { + execResult = appContainer.execInContainer("/opt/IBM/WebSphere/AppServer/java/bin/java", "-jar", jarPath, pidInContainer); + } + stdout = execResult.getStdout(); + System.out.println(stdout); + System.out.println(execResult.getStderr()); + log.info("attach result: {}", stdout); + assertThat(stdout, anyOf( + containsString("ok") + )); } else { content = packer.getInstance().pack(generateResult); assertInjectIsOk(url, shellType, shellTool, content, packer, appContainer); diff --git a/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java b/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java index 01620f97..2f94a6a9 100644 --- a/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java +++ b/integration-test/src/test/java/com/reajason/javaweb/integration/TestCasesProvider.java @@ -19,16 +19,30 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; */ public class TestCasesProvider { - public static Stream getTestCases(String imageName, Server server, List testShellTypes, List testPackers, List> unSupportedCases) { + public static Stream getTestCases(String imageName, + Server server, + List testShellTypes, + List testPackers, + List> unSupportedCases) { return getTestCases(imageName, server, testShellTypes, testPackers, unSupportedCases, null); } - public static Stream getTestCases(String imageName, Server server, List testShellTypes, List testPackers, List> unSupportedCases, List unSupportedShellTools) { + public static Stream getTestCases(String imageName, + Server server, + List testShellTypes, + List testPackers, + List> unSupportedCases, + List unSupportedShellTools) { Set supportedShellTools = new TreeSet<>(server.getShell().getSupportedShellTools()); if (unSupportedShellTools != null) { unSupportedShellTools.forEach(supportedShellTools::remove); } - Set unSupported = unSupportedCases == null ? Collections.emptySet() : unSupportedCases.stream().map(i -> i.getLeft() + i.getMiddle() + i.getRight()).collect(Collectors.toSet()); + Set unSupported = unSupportedCases == null ? + Collections.emptySet() : + unSupportedCases + .stream() + .map(i -> i.getLeft() + i.getMiddle() + i.getRight()) + .collect(Collectors.toSet()); return supportedShellTools.stream() .flatMap(supportedShellTool -> { List toolSupportedShellTypes = new ArrayList<>(); @@ -41,7 +55,9 @@ public class TestCasesProvider { return toolSupportedShellTypes.stream().flatMap(supportedShellType -> { if (supportedShellType.startsWith(ShellType.AGENT)) { if (!unSupported.contains(supportedShellType + supportedShellTool + Packers.AgentJar)) { - return Stream.of(arguments(imageName, supportedShellType, supportedShellTool, Packers.AgentJar)); + return Stream.of( + arguments(imageName, supportedShellType, supportedShellTool, Packers.AgentJar) + ); } return Stream.empty(); } else { @@ -58,7 +74,10 @@ public class TestCasesProvider { }); } - public static Stream getTestCases(String imageName, Server server, List testShellTypes, List testPackers) { + public static Stream getTestCases(String imageName, + Server server, + List testShellTypes, + List testPackers) { return getTestCases(imageName, server, testShellTypes, testPackers, null); } } diff --git a/memshell-agent/memshell-agent-attacher/build.gradle b/memshell-agent/memshell-agent-attacher/build.gradle new file mode 100644 index 00000000..b85d1c11 --- /dev/null +++ b/memshell-agent/memshell-agent-attacher/build.gradle @@ -0,0 +1,33 @@ +plugins { + id 'java' + id "com.gradleup.shadow" version "8.3.6" +} + +group = 'com.reajason.javaweb' +version = '1.0.0' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } + sourceCompatibility = JavaVersion.VERSION_1_6 + targetCompatibility = JavaVersion.VERSION_1_6 +} + +dependencies { + implementation 'net.java.dev.jna:jna:5.17.0' + implementation 'net.java.dev.jna:jna-platform:5.17.0' +} + +jar { + manifest { + attributes 'Premain-Class': 'Agent' + attributes 'Agent-Class': 'Agent' + attributes 'Main-Class': "Main" + attributes 'Can-Redefine-Classes': true + attributes 'Can-Retransform-Classes': true + attributes 'Can-Set-Native-Method-Prefix': true + } +} + +jar.finalizedBy shadowJar diff --git a/memshell-agent/memshell-agent-attacher/src/main/c/attach_hotspot_windows.c b/memshell-agent/memshell-agent-attacher/src/main/c/attach_hotspot_windows.c new file mode 100644 index 00000000..4072ca3c --- /dev/null +++ b/memshell-agent/memshell-agent-attacher/src/main/c/attach_hotspot_windows.c @@ -0,0 +1,130 @@ +/** + * Copyright 2014 - Present Rafael Winterhalter + * + * 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. + */ +#include + +#define OPEN_JVM_ERROR 200 +#define GET_ENQUEUE_FUNCTION_ERROR 201 +#define CODE_SIZE (SIZE_T) 1024 +#define MAX_ARGUMENT 1024 + +typedef HMODULE (WINAPI *GetModuleHandle_t)(LPCTSTR); +typedef FARPROC (WINAPI *GetProcAddress_t)(HMODULE, LPCSTR); +typedef int (__stdcall *JVM_EnqueueOperation_t)(char *, char *, char *, char *, char *); + +typedef struct { + GetModuleHandle_t GetModuleHandleA; + GetProcAddress_t GetProcAddress; + char library[32]; + char command[32]; + char commandFallback[32]; + char pipe[MAX_PATH]; + char argument[4][MAX_ARGUMENT]; +} EnqueueOperation; + +#pragma check_stack(off) + +/** + * Executes the attachment on the remote thread. This method is executed on the target JVM and must not reference any addresses unknown to that address. + * + * @param argument The argument provided by the JVM executing the attachment. + * @return The result of the attachment. + */ +DWORD WINAPI execute_remote_attach + (LPVOID argument) +{ + EnqueueOperation *operation = (EnqueueOperation *) argument; + HMODULE library = operation->GetModuleHandleA(operation->library); + if (library == NULL) { + return OPEN_JVM_ERROR; + } + JVM_EnqueueOperation_t JVM_EnqueueOperation = (JVM_EnqueueOperation_t) operation->GetProcAddress(library, operation->command); + if (JVM_EnqueueOperation == NULL) { + JVM_EnqueueOperation = (JVM_EnqueueOperation_t) operation->GetProcAddress(library, operation->commandFallback); + } + if (JVM_EnqueueOperation == NULL) { + return GET_ENQUEUE_FUNCTION_ERROR; + } + return (DWORD) JVM_EnqueueOperation(operation->argument[0], + operation->argument[1], + operation->argument[2], + operation->argument[3], + operation->pipe); +} + +#pragma check_stack + +/** + * Allocates the code to execute on the remote machine. + * + * @param process The process handle of the remote process to which to attach. + * @return A pointer to the allocated code or {@code NULL} if the allocation failed. + */ +LPVOID allocate_remote_code + (HANDLE process) +{ + LPVOID code = VirtualAllocEx(process, NULL, CODE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (code == NULL) { + return NULL; + } else if (!WriteProcessMemory(process, code, execute_remote_attach, CODE_SIZE, NULL)) { + VirtualFreeEx(process, code, 0, MEM_RELEASE); + return NULL; + } else { + return code; + } +} + +/** + * Allocates the argument to the remote execution. + * + * @param process A handle to the remote process to which to attach. + * @param pipe The name of the pipe to which the attachment result is written + * @param argument0 The first argument to provide to the {@code JVM_EnqueueOperation}. + * @param argument1 The second argument to provide to the {@code JVM_EnqueueOperation}. + * @param argument2 The third argument to provide to the {@code JVM_EnqueueOperation}. + * @param argument3 The forth argument to provide to the {@code JVM_EnqueueOperation}. + * @return A pointer to the allocated argument or {@code NULL} if the allocation was not possible. + */ +LPVOID allocate_remote_argument + (HANDLE process, LPCSTR pipe, LPCSTR argument0, LPCSTR argument1, LPCSTR argument2, LPCSTR argument3) +{ + if (strlen(pipe) >= MAX_PATH + || argument0 != NULL && strlen(argument0) >= MAX_ARGUMENT + || argument1 != NULL && strlen(argument1) >= MAX_ARGUMENT + || argument2 != NULL && strlen(argument2) >= MAX_ARGUMENT + || argument3 != NULL && strlen(argument3) >= MAX_ARGUMENT) { + return NULL; + } + EnqueueOperation operation; + operation.GetModuleHandleA = GetModuleHandleA; + operation.GetProcAddress = GetProcAddress; + strcpy(operation.library, "jvm"); + strcpy(operation.command, "JVM_EnqueueOperation"); + strcpy(operation.commandFallback, "_JVM_EnqueueOperation@20"); + strcpy(operation.pipe, pipe); + strcpy(operation.argument[0], argument0 == NULL ? "" : argument0); + strcpy(operation.argument[1], argument1 == NULL ? "" : argument1); + strcpy(operation.argument[2], argument2 == NULL ? "" : argument2); + strcpy(operation.argument[3], argument3 == NULL ? "" : argument3); + LPVOID allocation = VirtualAllocEx(process, NULL, sizeof(EnqueueOperation), MEM_COMMIT, PAGE_READWRITE); + if (allocation == NULL) { + return NULL; + } else if (!WriteProcessMemory(process, allocation, &operation, sizeof(operation), NULL)) { + VirtualFreeEx(process, allocation, 0, MEM_RELEASE); + return NULL; + } else { + return allocation; + } +} diff --git a/memshell-agent/memshell-agent-attacher/src/main/java/Agent.java b/memshell-agent/memshell-agent-attacher/src/main/java/Agent.java new file mode 100644 index 00000000..54372ce3 --- /dev/null +++ b/memshell-agent/memshell-agent-attacher/src/main/java/Agent.java @@ -0,0 +1,15 @@ +import java.lang.instrument.Instrumentation; + +/** + * @author ReaJason + * @since 2025/5/22 + */ +public class Agent { + public static void premain(String args, Instrumentation inst) { + System.out.println("hello premain"); + } + + public static void agentmain(String args, Instrumentation inst) { + System.out.println("hello agentmain"); + } +} diff --git a/memshell-agent/memshell-agent-attacher/src/main/java/Attacher.java b/memshell-agent/memshell-agent-attacher/src/main/java/Attacher.java new file mode 100644 index 00000000..e9af79c5 --- /dev/null +++ b/memshell-agent/memshell-agent-attacher/src/main/java/Attacher.java @@ -0,0 +1,931 @@ +/* + * Copyright 2014 - Present Rafael Winterhalter + * + * 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. + */ + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.CodeSource; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Copy from Byte Buddy + */ +public class Attacher { + + /** + * Representation of the bootstrap {@link java.lang.ClassLoader}. + */ + private static final ClassLoader BOOTSTRAP_CLASS_LOADER = null; + + /** + * The character that is used to mark the beginning of the argument to the agent. + */ + private static final String AGENT_ARGUMENT_SEPARATOR = "="; + + /** + * The agent provides only {@code static} utility methods and should not be instantiated. + */ + private Attacher() { + throw new UnsupportedOperationException("This class is a utility class and not supposed to be instantiated"); + } + + /** + *

+ * Attaches the given agent Jar on the target process which must be a virtual machine process. The default attachment provider + * is used for applying the attachment. This operation blocks until the attachment is complete. If the current VM does not supply + * any known form of attachment to a remote VM, an {@link IllegalStateException} is thrown. The agent is not provided an argument. + *

+ *

+ * Important: It is only possible to attach to processes that are executed by the same operating system user. + *

+ * + * @param agentJar The agent jar file. + * @param processId The target process id. + */ + public static void attach(File agentJar, String processId) { + attach(agentJar, processId, null); + } + + public static void attach(String processId) { + attach(trySelfResolve(), processId, null); + } + + /** + *

+ * Attaches the given agent Jar on the target process which must be a virtual machine process. The default attachment provider + * is used for applying the attachment. This operation blocks until the attachment is complete. If the current VM does not supply + * any known form of attachment to a remote VM, an {@link IllegalStateException} is thrown. + *

+ *

+ * Important: It is only possible to attach to processes that are executed by the same operating system user. + *

+ * + * @param agentJar The agent jar file. + * @param processId The target process id. + * @param argument The argument to provide to the agent. + */ + public static void attach(File agentJar, String processId, String argument) { + install(processId, argument, new AgentProvider.ForExistingAgent(agentJar)); + } + + /** + * Installs a Java agent on a target VM. + * + * @param processId The process id of the target JVM process. + * @param argument The argument to provide to the agent. + * @param agentProvider The agent provider for the agent jar or library. + */ + private static void install(String processId, String argument, AgentProvider agentProvider) { + AttachmentProvider.Accessor attachmentAccessor = AttachmentProvider.DEFAULT.attempt(); + if (!attachmentAccessor.isAvailable()) { + throw new IllegalStateException("No compatible attachment provider is available"); + } + try { + Class virtualMachineType = attachmentAccessor.getVirtualMachineType(); + String agent = agentProvider.resolve().getAbsolutePath(); + Object virtualMachineInstance = virtualMachineType + .getMethod("attach", String.class) + .invoke(null, processId); + try { + virtualMachineType + .getMethod("loadAgent", String.class, String.class) + .invoke(virtualMachineInstance, agent, argument); + } finally { + virtualMachineType + .getMethod("detach") + .invoke(virtualMachineInstance); + } + } catch (RuntimeException exception) { + throw exception; + } catch (Exception exception) { + throw new IllegalStateException("Error during attachment using: " + AttachmentProvider.DEFAULT, exception); + } + } + + /** + * Attempts to resolve the location of the {@link Attacher} class for a self-attachment. Doing so avoids the creation of a temporary jar file. + * + * @return The self-resolved jar file or {@code null} if the jar file cannot be located. + */ + private static File trySelfResolve() { + try { + ProtectionDomain protectionDomain = Attacher.class.getProtectionDomain(); + if (protectionDomain == null) { + return null; + } + CodeSource codeSource = protectionDomain.getCodeSource(); + if (codeSource == null) { + return null; + } + URL location = codeSource.getLocation(); + if (!location.getProtocol().equals("file")) { + return null; + } + try { + File file = new File(location.toURI()); + if (file.getPath().contains(AGENT_ARGUMENT_SEPARATOR)) { + return null; + } + return file; + } catch (URISyntaxException ignored) { + return new File(location.getPath()); + } + } catch (Exception ignored) { + return null; + } + } + + /** + * An attachment provider is responsible for making the Java attachment API available. + */ + public interface AttachmentProvider { + + /** + * The default attachment provider to be used. + */ + AttachmentProvider DEFAULT = new Compound(ForModularizedVm.INSTANCE, + ForJ9Vm.INSTANCE, + ForStandardToolsJarVm.JVM_ROOT, + ForStandardToolsJarVm.JDK_ROOT, + ForStandardToolsJarVm.MACINTOSH, + ForUserDefinedToolsJar.INSTANCE, + ForEmulatedAttachment.INSTANCE); + + /** + * Attempts the creation of an accessor for a specific JVM's attachment API. + * + * @return The accessor this attachment provider can supply for the currently running JVM. + */ + Accessor attempt(); + + /** + * An accessor for a JVM's attachment API. + */ + interface Accessor { + + /** + * The name of the {@code VirtualMachine} class on any OpenJDK or Oracle JDK implementation. + */ + String VIRTUAL_MACHINE_TYPE_NAME = "com.sun.tools.attach.VirtualMachine"; + + /** + * The name of the {@code VirtualMachine} class on IBM J9 VMs. + */ + String VIRTUAL_MACHINE_TYPE_NAME_J9 = "com.ibm.tools.attach.VirtualMachine"; + + /** + * Determines if this accessor is applicable for the currently running JVM. + * + * @return {@code true} if this accessor is available. + */ + boolean isAvailable(); + + /** + * Returns {@code true} if this accessor prohibits attachment to the same virtual machine in Java 9 and later. + * + * @return {@code true} if this accessor prohibits attachment to the same virtual machine in Java 9 and later. + */ + boolean isExternalAttachmentRequired(); + + /** + * Returns a {@code VirtualMachine} class. This method must only be called for available accessors. + * + * @return The virtual machine type. + */ + Class getVirtualMachineType(); + + /** + * Returns a description of a virtual machine class for an external attachment. + * + * @return A description of the external attachment. + */ + ExternalAttachment getExternalAttachment(); + + /** + * A canonical implementation of an unavailable accessor. + */ + enum Unavailable implements Accessor { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public boolean isAvailable() { + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isExternalAttachmentRequired() { + throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor"); + } + + /** + * {@inheritDoc} + */ + public Class getVirtualMachineType() { + throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor"); + } + + /** + * {@inheritDoc} + */ + public ExternalAttachment getExternalAttachment() { + throw new IllegalStateException("Cannot read the virtual machine type for an unavailable accessor"); + } + } + + /** + * Describes an external attachment to a Java virtual machine. + */ + class ExternalAttachment { + + /** + * The fully-qualified binary name of the virtual machine type. + */ + private final String virtualMachineType; + + /** + * The class path elements required for loading the supplied virtual machine type. + */ + private final List classPath; + + /** + * Creates an external attachment. + * + * @param virtualMachineType The fully-qualified binary name of the virtual machine type. + * @param classPath The class path elements required for loading the supplied virtual machine type. + */ + public ExternalAttachment(String virtualMachineType, List classPath) { + this.virtualMachineType = virtualMachineType; + this.classPath = classPath; + } + + /** + * Returns the fully-qualified binary name of the virtual machine type. + * + * @return The fully-qualified binary name of the virtual machine type. + */ + public String getVirtualMachineType() { + return virtualMachineType; + } + + /** + * Returns the class path elements required for loading the supplied virtual machine type. + * + * @return The class path elements required for loading the supplied virtual machine type. + */ + public List getClassPath() { + return classPath; + } + } + + /** + * A simple implementation of an accessible accessor. + */ + abstract class Simple implements Accessor { + + /** + * A {@code VirtualMachine} class. + */ + protected final Class virtualMachineType; + + /** + * Creates a new simple accessor. + * + * @param virtualMachineType A {@code VirtualMachine} class. + */ + protected Simple(Class virtualMachineType) { + this.virtualMachineType = virtualMachineType; + } + + /** + *

+ * Creates an accessor by reading the process id from the JMX runtime bean and by attempting + * to load the {@code com.sun.tools.attach.VirtualMachine} class from the provided class loader. + *

+ *

+ * This accessor is supposed to work on any implementation of the OpenJDK or Oracle JDK. + *

+ * + * @param classLoader A class loader that is capable of loading the virtual machine type. + * @param classPath The class path required to load the virtual machine class. + * @return An appropriate accessor. + */ + public static Accessor of(ClassLoader classLoader, File... classPath) { + try { + return new Simple.WithExternalAttachment(Class.forName(VIRTUAL_MACHINE_TYPE_NAME, + false, + classLoader), Arrays.asList(classPath)); + } catch (ClassNotFoundException ignored) { + return Unavailable.INSTANCE; + } + } + + /** + *

+ * Creates an accessor by reading the process id from the JMX runtime bean and by attempting + * to load the {@code com.ibm.tools.attach.VirtualMachine} class from the provided class loader. + *

+ *

+ * This accessor is supposed to work on any implementation of IBM's J9. + *

+ * + * @return An appropriate accessor. + */ + public static Accessor ofJ9() { + try { + return new Simple.WithExternalAttachment(ClassLoader.getSystemClassLoader().loadClass(VIRTUAL_MACHINE_TYPE_NAME_J9), + Collections.emptyList()); + } catch (ClassNotFoundException ignored) { + return Unavailable.INSTANCE; + } + } + + /** + * {@inheritDoc} + */ + public boolean isAvailable() { + return true; + } + + /** + * {@inheritDoc} + */ + public Class getVirtualMachineType() { + return virtualMachineType; + } + + /** + * A simple implementation of an accessible accessor that allows for external attachment. + */ + protected static class WithExternalAttachment extends Simple { + + /** + * The class path required for loading the virtual machine type. + */ + private final List classPath; + + /** + * Creates a new simple accessor that allows for external attachment. + * + * @param virtualMachineType The {@code com.sun.tools.attach.VirtualMachine} class. + * @param classPath The class path required for loading the virtual machine type. + */ + public WithExternalAttachment(Class virtualMachineType, List classPath) { + super(virtualMachineType); + this.classPath = classPath; + } + + /** + * {@inheritDoc} + */ + public boolean isExternalAttachmentRequired() { + return true; + } + + /** + * {@inheritDoc} + */ + public ExternalAttachment getExternalAttachment() { + return new ExternalAttachment(virtualMachineType.getName(), classPath); + } + } + + /** + * A simple implementation of an accessible accessor that attaches using a virtual machine emulation that does not require external attachment. + */ + protected static class WithDirectAttachment extends Simple { + + /** + * Creates a new simple accessor that implements direct attachment. + * + * @param virtualMachineType A {@code VirtualMachine} class. + */ + public WithDirectAttachment(Class virtualMachineType) { + super(virtualMachineType); + } + + /** + * {@inheritDoc} + */ + public boolean isExternalAttachmentRequired() { + return false; + } + + /** + * {@inheritDoc} + */ + public ExternalAttachment getExternalAttachment() { + throw new IllegalStateException("Cannot apply external attachment"); + } + } + } + } + + /** + * An attachment provider that locates the attach API directly from the system class loader, as possible since + * introducing the Java module system via the {@code jdk.attach} module. + */ + enum ForModularizedVm implements AttachmentProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + return Accessor.Simple.of(ClassLoader.getSystemClassLoader()); + } + } + + /** + * An attachment provider that locates the attach API directly from the system class loader expecting + * an IBM J9 VM. + */ + enum ForJ9Vm implements AttachmentProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + return Accessor.Simple.ofJ9(); + } + } + + /** + * An attachment provider that is dependant on the existence of a tools.jar file on the local + * file system. + */ + enum ForStandardToolsJarVm implements AttachmentProvider { + + /** + * An attachment provider that locates the tools.jar from a Java home directory. + */ + JVM_ROOT("../lib/tools.jar"), + + /** + * An attachment provider that locates the tools.jar from a Java installation directory. + * In practice, several virtual machines do not return the JRE's location for the + * java.home property against the property's specification. + */ + JDK_ROOT("lib/tools.jar"), + + /** + * An attachment provider that locates the tools.jar as it is set for several JVM + * installations on Apple Macintosh computers. + */ + MACINTOSH("../Classes/classes.jar"); + + /** + * The Java home system property. + */ + private static final String JAVA_HOME_PROPERTY = "java.home"; + + /** + * The path to the tools.jar file, starting from the Java home directory. + */ + private final String toolsJarPath; + + /** + * Creates a new attachment provider that loads the virtual machine class from the tools.jar. + * + * @param toolsJarPath The path to the tools.jar file, starting from the Java home directory. + */ + ForStandardToolsJarVm(String toolsJarPath) { + this.toolsJarPath = toolsJarPath; + } + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + File toolsJar = new File(System.getProperty(JAVA_HOME_PROPERTY), toolsJarPath); + try { + return toolsJar.isFile() && toolsJar.canRead() + ? Accessor.Simple.of(new URLClassLoader(new URL[]{toolsJar.toURI().toURL()}, BOOTSTRAP_CLASS_LOADER), toolsJar) + : Accessor.Unavailable.INSTANCE; + } catch (MalformedURLException exception) { + throw new IllegalStateException("Could not represent " + toolsJar + " as URL"); + } + } + } + + /** + * An attachment provider that attempts to locate a {@code tools.jar} from a custom location set via a system property. + */ + enum ForUserDefinedToolsJar implements AttachmentProvider { + + /** + * The singelton instance. + */ + INSTANCE; + + /** + * The property being read for locating {@code tools.jar}. + */ + public static final String PROPERTY = "net.bytebuddy.agent.toolsjar"; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + String location = System.getProperty(PROPERTY); + if (location == null) { + return Accessor.Unavailable.INSTANCE; + } else { + File toolsJar = new File(location); + try { + return Accessor.Simple.of(new URLClassLoader(new URL[]{toolsJar.toURI().toURL()}, BOOTSTRAP_CLASS_LOADER), toolsJar); + } catch (MalformedURLException exception) { + throw new IllegalStateException("Could not represent " + toolsJar + " as URL"); + } + } + } + } + + /** + * An attachment provider that uses Byte Buddy's attachment API emulation. To use this feature, JNA is required. + */ + enum ForEmulatedAttachment implements AttachmentProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + try { + return new Accessor.Simple.WithDirectAttachment(VirtualMachine.Resolver.INSTANCE.get()); + } catch (Throwable ignored) { + return Accessor.Unavailable.INSTANCE; + } + } + } + + /** + * A compound attachment provider that attempts the attachment by delegation to other providers. If + * none of the providers of this compound provider is capable of providing a valid accessor, an + * non-available accessor is returned. + */ + class Compound implements AttachmentProvider { + + /** + * A list of attachment providers in the order of their application. + */ + private final List attachmentProviders; + + /** + * Creates a new compound attachment provider. + * + * @param attachmentProvider A list of attachment providers in the order of their application. + */ + public Compound(AttachmentProvider... attachmentProvider) { + this(Arrays.asList(attachmentProvider)); + } + + /** + * Creates a new compound attachment provider. + * + * @param attachmentProviders A list of attachment providers in the order of their application. + */ + public Compound(List attachmentProviders) { + this.attachmentProviders = new ArrayList(); + for (AttachmentProvider attachmentProvider : attachmentProviders) { + if (attachmentProvider instanceof Compound) { + this.attachmentProviders.addAll(((Compound) attachmentProvider).attachmentProviders); + } else { + this.attachmentProviders.add(attachmentProvider); + } + } + } + + /** + * {@inheritDoc} + */ + public Accessor attempt() { + for (AttachmentProvider attachmentProvider : attachmentProviders) { + Accessor accessor = attachmentProvider.attempt(); + if (accessor.isAvailable()) { + return accessor; + } + } + return Accessor.Unavailable.INSTANCE; + } + } + } + + /** + * A process provider is responsible for providing the process id of the current VM. + */ + public interface ProcessProvider { + + /** + * Resolves a process id for the current JVM. + * + * @return The resolved process id. + */ + String resolve(); + + /** + * Supplies the current VM's process id. + */ + enum ForCurrentVm implements ProcessProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * The best process provider for the current VM. + */ + private final ProcessProvider dispatcher; + + /** + * Creates a process provider that supplies the current VM's process id. + */ + ForCurrentVm() { + dispatcher = ForJava9CapableVm.make(); + } + + /** + * {@inheritDoc} + */ + public String resolve() { + return dispatcher.resolve(); + } + + /** + * A process provider for a legacy VM that reads the process id from its JMX properties. This strategy + * is only used prior to Java 9 such that the java.management module never is resolved, even if + * the module system is used, as the module system was not available in any relevant JVM version. + */ + protected enum ForLegacyVm implements ProcessProvider { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public String resolve() { + String runtimeName; + try { + Method method = Class.forName("java.lang.management.ManagementFactory").getMethod("getRuntimeMXBean"); + runtimeName = (String) method.getReturnType().getMethod("getName").invoke(method.invoke(null)); + } catch (Exception exception) { + throw new IllegalStateException("Failed to access VM name via management factory", exception); + } + int processIdIndex = runtimeName.indexOf('@'); + if (processIdIndex == -1) { + throw new IllegalStateException("Cannot extract process id from runtime management bean"); + } else { + return runtimeName.substring(0, processIdIndex); + } + } + } + + /** + * A process provider for a Java 9 capable VM with access to the introduced process API. + */ + protected static class ForJava9CapableVm implements ProcessProvider { + + /** + * The {@code java.lang.ProcessHandle#current()} method. + */ + private final Method current; + + /** + * The {@code java.lang.ProcessHandle#pid()} method. + */ + private final Method pid; + + /** + * Creates a new Java 9 capable dispatcher for reading the current process's id. + * + * @param current The {@code java.lang.ProcessHandle#current()} method. + * @param pid The {@code java.lang.ProcessHandle#pid()} method. + */ + protected ForJava9CapableVm(Method current, Method pid) { + this.current = current; + this.pid = pid; + } + + /** + * Attempts to create a dispatcher for a Java 9 VM and falls back to a legacy dispatcher + * if this is not possible. + * + * @return A dispatcher for the current VM. + */ + public static ProcessProvider make() { + try { + return new ForJava9CapableVm(Class.forName("java.lang.ProcessHandle").getMethod("current"), + Class.forName("java.lang.ProcessHandle").getMethod("pid")); + } catch (Exception ignored) { + return ForLegacyVm.INSTANCE; + } + } + + /** + * {@inheritDoc} + */ + public String resolve() { + try { + return pid.invoke(current.invoke(null)).toString(); + } catch (IllegalAccessException exception) { + throw new IllegalStateException("Cannot access Java 9 process API", exception); + } catch (InvocationTargetException exception) { + throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException()); + } + } + } + } + } + + /** + * An agent provider is responsible for handling and providing the jar file of an agent that is being attached. + */ + protected interface AgentProvider { + + /** + * Provides an agent jar file for attachment. + * + * @return The provided agent. + * @throws IOException If the agent cannot be written to disk. + */ + File resolve() throws IOException; + + /** + * An agent provider that supplies an existing agent that is not deleted after attachment. + */ + class ForExistingAgent implements AgentProvider { + + /** + * The supplied agent. + */ + private final File agent; + + /** + * Creates an agent provider for an existing agent. + * + * @param agent The supplied agent. + */ + protected ForExistingAgent(File agent) { + this.agent = agent; + } + + /** + * {@inheritDoc} + */ + public File resolve() { + return agent; + } + } + } + + /** + * An attachment evaluator is responsible for deciding if an agent can be attached from the current process. + */ + protected interface AttachmentTypeEvaluator { + + /** + * Checks if the current VM requires external attachment for the supplied process id. + * + * @param processId The process id of the process to which to attach. + * @return {@code true} if the current VM requires external attachment for the supplied process. + */ + boolean requiresExternalAttachment(String processId); + + /** + * An installation action for creating an attachment type evaluator. + */ + enum InstallationAction implements PrivilegedAction { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * The OpenJDK's property for specifying the legality of self-attachment. + */ + private static final String JDK_ALLOW_SELF_ATTACH = "jdk.attach.allowAttachSelf"; + + /** + * {@inheritDoc} + */ + public AttachmentTypeEvaluator run() { + try { + if (Boolean.getBoolean(JDK_ALLOW_SELF_ATTACH)) { + return Disabled.INSTANCE; + } else { + return new ForJava9CapableVm(Class.forName("java.lang.ProcessHandle").getMethod("current"), + Class.forName("java.lang.ProcessHandle").getMethod("pid")); + } + } catch (Exception ignored) { + return Disabled.INSTANCE; + } + } + } + + /** + * An attachment type evaluator that never requires external attachment. + */ + enum Disabled implements AttachmentTypeEvaluator { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public boolean requiresExternalAttachment(String processId) { + return false; + } + } + + /** + * An attachment type evaluator that checks a process id against the current process id. + */ + class ForJava9CapableVm implements AttachmentTypeEvaluator { + + /** + * The {@code java.lang.ProcessHandle#current()} method. + */ + private final Method current; + + /** + * The {@code java.lang.ProcessHandle#pid()} method. + */ + private final Method pid; + + /** + * Creates a new attachment type evaluator. + * + * @param current The {@code java.lang.ProcessHandle#current()} method. + * @param pid The {@code java.lang.ProcessHandle#pid()} method. + */ + protected ForJava9CapableVm(Method current, Method pid) { + this.current = current; + this.pid = pid; + } + + /** + * {@inheritDoc} + */ + public boolean requiresExternalAttachment(String processId) { + try { + return pid.invoke(current.invoke(null)).toString().equals(processId); + } catch (IllegalAccessException exception) { + throw new IllegalStateException("Cannot access Java 9 process API", exception); + } catch (InvocationTargetException exception) { + throw new IllegalStateException("Error when accessing Java 9 process API", exception.getTargetException()); + } + } + } + } +} diff --git a/memshell-agent/memshell-agent-attacher/src/main/java/Main.java b/memshell-agent/memshell-agent-attacher/src/main/java/Main.java new file mode 100644 index 00000000..e25bf1b5 --- /dev/null +++ b/memshell-agent/memshell-agent-attacher/src/main/java/Main.java @@ -0,0 +1,9 @@ +/** + * @author ReaJason + * @since 2025/5/16 + */ +public class Main { + public static void main(String[] args) throws Exception { + Attacher.attach(args[0]); + } +} diff --git a/memshell-agent/memshell-agent-attacher/src/main/java/VirtualMachine.java b/memshell-agent/memshell-agent-attacher/src/main/java/VirtualMachine.java new file mode 100644 index 00000000..91935b1c --- /dev/null +++ b/memshell-agent/memshell-agent-attacher/src/main/java/VirtualMachine.java @@ -0,0 +1,2888 @@ +/* + * Copyright 2014 - Present Rafael Winterhalter + * + * 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. + */ + +import com.sun.jna.*; +import com.sun.jna.platform.win32.*; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.win32.StdCallLibrary; +import com.sun.jna.win32.W32APIOptions; + +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.FileLock; +import java.security.PrivilegedAction; +import java.security.SecureRandom; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

+ * An implementation for attachment on a virtual machine. This interface mimics the tooling API's virtual + * machine interface to allow for similar usage by where all calls are made via + * reflection such that this structural typing suffices for interoperability. + *

+ *

+ * Note: Implementations are required to declare a static method {@code attach(String)} returning an + * instance of a class that declares the methods defined by {@link VirtualMachine}. + *

+ */ +public interface VirtualMachine { + + /** + * Loads the target VMs system properties. + * + * @return The target VM properties. + * @throws IOException If an I/O exception occurs. + */ + Properties getSystemProperties() throws IOException; + + /** + * Loads the target VMs agent properties. + * + * @return The target VM properties. + * @throws IOException If an I/O exception occurs. + */ + Properties getAgentProperties() throws IOException; + + /** + * Loads an agent into the represented virtual machine. + * + * @param jarFile The jar file to attach. + * @throws IOException If an I/O exception occurs. + */ + void loadAgent(String jarFile) throws IOException; + + /** + * Loads an agent into the represented virtual machine. + * + * @param jarFile The jar file to attach. + * @param argument The argument to provide or {@code null} if no argument should be provided. + * @throws IOException If an I/O exception occurs. + */ + void loadAgent(String jarFile, String argument) throws IOException; + + /** + * Loads a native agent into the represented virtual machine. + * + * @param path The agent path. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentPath(String path) throws IOException; + + /** + * Loads a native agent into the represented virtual machine. + * + * @param path The agent path. + * @param argument The argument to provide or {@code null} if no argument should be provided. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentPath(String path, String argument) throws IOException; + + /** + * Loads a native agent library into the represented virtual machine. + * + * @param library The agent library. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentLibrary(String library) throws IOException; + + /** + * Loads a native agent library into the represented virtual machine. + * + * @param library The agent library. + * @param argument The argument to provide or {@code null} if no argument should be provided. + * @throws IOException If an I/O exception occurs. + */ + void loadAgentLibrary(String library, String argument) throws IOException; + + /** + * Starts a JMX management agent. + * + * @param properties The properties to transfer to the JMX agent. + * @throws IOException If an I/O error occurs. + */ + void startManagementAgent(Properties properties) throws IOException; + + /** + * Starts a local management agent. + * + * @return The local connector address. + * @throws IOException If an I/O error occurs. + */ + String startLocalManagementAgent() throws IOException; + + /** + * Detaches this virtual machine representation. + * + * @throws IOException If an I/O exception occurs. + */ + void detach() throws IOException; + + /** + * A resolver for the current VM's virtual machine attachment emulation. + */ + enum Resolver { + + /** + * The singleton instance. + */ + INSTANCE; + + /** + * {@inheritDoc} + */ + public Class get() { + try { + Class.forName("com.sun.jna.Platform"); + } catch (ClassNotFoundException exception) { + throw new IllegalStateException("Optional JNA dependency is not available", exception); + } + return System.getProperty("java.vm.name", "").toUpperCase(Locale.US).contains("J9") + ? ForOpenJ9.class + : ForHotSpot.class; + + } + } + + /** + * An abstract base implementation for a virtual machine. + */ + abstract class AbstractBase implements VirtualMachine { + + /** + * {@inheritDoc} + */ + public void loadAgent(String jarFile) throws IOException { + loadAgent(jarFile, null); + } + + /** + * {@inheritDoc} + */ + public void loadAgentPath(String path) throws IOException { + loadAgentPath(path, null); + } + + /** + * {@inheritDoc} + */ + public void loadAgentLibrary(String library) throws IOException { + loadAgentLibrary(library, null); + } + } + + /** + * A virtual machine attachment implementation for a HotSpot VM or any compatible JVM. + */ + class ForHotSpot extends AbstractBase { + + /** + * The protocol version to use for communication. + */ + private static final String PROTOCOL_VERSION = "1"; + + /** + * The {@code load} command. + */ + private static final String LOAD_COMMAND = "load"; + + /** + * The {@code instrument} command. + */ + private static final String INSTRUMENT_COMMAND = "instrument"; + + /** + * A delimiter to be used for attachment. + */ + private static final String ARGUMENT_DELIMITER = "="; + + /** + * The virtual machine connection. + */ + private final Connection connection; + + /** + * Creates a new virtual machine connection for HotSpot. + * + * @param connection The virtual machine connection. + */ + protected ForHotSpot(Connection connection) { + this.connection = connection; + } + + /** + * Attaches to the supplied process id using the default JNA implementation. + * + * @param processId The process id. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId) throws IOException { + if (Platform.isWindows()) { + return attach(processId, new Connection.ForJnaWindowsNamedPipe.Factory()); + } else if (Platform.isSolaris()) { + return attach(processId, new Connection.ForJnaSolarisDoor.Factory(15, 100, TimeUnit.MILLISECONDS)); + } else { + return attach(processId, Connection.ForJnaPosixSocket.Factory.withDefaultTemporaryFolder(15, 100, TimeUnit.MILLISECONDS)); + } + } + + /** + * Attaches to the supplied process id using the supplied connection factory. + * + * @param processId The process id. + * @param connectionFactory The connection factory to use. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId, Connection.Factory connectionFactory) throws IOException { + return new ForHotSpot(connectionFactory.connect(processId)); + } + + /** + * Checks the header of a response. + * + * @param response The response to check the header for. + * @throws IOException If an I/O exception occurs. + */ + private static void checkHeader(Connection.Response response) throws IOException { + byte[] buffer = new byte[1]; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int length; + while ((length = response.read(buffer)) != -1) { + if (length > 0) { + if (buffer[0] == '\n') { + break; + } + outputStream.write(buffer[0]); + } + } + switch (Integer.parseInt(outputStream.toString("UTF-8"))) { + case 0: + return; + case 101: + throw new IOException("Protocol mismatch with target VM"); + default: + buffer = new byte[1024]; + outputStream = new ByteArrayOutputStream(); + while ((length = response.read(buffer)) != -1) { + outputStream.write(buffer, 0, length); + } + throw new IllegalStateException(outputStream.toString("UTF-8")); + } + } + + /** + * {@inheritDoc} + */ + public Properties getSystemProperties() throws IOException { + return getProperties("properties"); + } + + /** + * {@inheritDoc} + */ + public Properties getAgentProperties() throws IOException { + return getProperties("agentProperties"); + } + + /** + * Loads properties of the target VM. + * + * @param command The command for fetching properties. + * @return The read properties. + * @throws IOException If an I/O exception occurs. + */ + private Properties getProperties(String command) throws IOException { + Connection.Response response = connection.execute(PROTOCOL_VERSION, command, null, null, null); + try { + checkHeader(response); + byte[] buffer = new byte[1024]; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int length; + while ((length = response.read(buffer)) != -1) { + outputStream.write(buffer, 0, length); + } + Properties properties = new Properties(); + properties.load(new ByteArrayInputStream(outputStream.toByteArray())); + return properties; + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public void loadAgent(String jarFile, String argument) throws IOException { + load(jarFile, false, argument); + } + + /** + * {@inheritDoc} + */ + public void loadAgentPath(String path, String argument) throws IOException { + load(path, true, argument); + } + + /** + * {@inheritDoc} + */ + public void loadAgentLibrary(String library, String argument) throws IOException { + load(library, false, argument); + } + + /** + * Loads an agent by the given command. + * + * @param file The Java agent or library to be loaded. + * @param absolute {@code true} if the agent location is absolute. + * @param argument The argument to the agent or {@code null} if no argument is given. + * @throws IOException If an I/O exception occurs. + */ + protected void load(String file, boolean absolute, String argument) throws IOException { + Connection.Response response = connection.execute(PROTOCOL_VERSION, LOAD_COMMAND, INSTRUMENT_COMMAND, Boolean.toString(absolute), (argument == null + ? file + : file + ARGUMENT_DELIMITER + argument)); + try { + checkHeader(response); + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public void startManagementAgent(Properties properties) throws IOException { + StringBuilder stringBuilder = new StringBuilder("ManagementAgent.start "); + boolean first = true; + for (Map.Entry entry : properties.entrySet()) { + if (!(entry.getKey() instanceof String) || !((String) entry.getKey()).startsWith("com.sun.management.")) { + throw new IllegalArgumentException("Illegal property name: " + entry.getKey()); + } else if (first) { + first = false; + } else { + stringBuilder.append(' '); + } + stringBuilder.append(((String) entry.getKey()).substring("com.sun.management.".length())).append('='); + String value = entry.getValue().toString(); + if (value.contains(" ")) { + stringBuilder.append('\'').append(value).append('\''); + } else { + stringBuilder.append(value); + } + } + Connection.Response response = connection.execute(PROTOCOL_VERSION, "jcmd", stringBuilder.toString(), null, null); + try { + checkHeader(response); + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public String startLocalManagementAgent() throws IOException { + Connection.Response response = connection.execute(PROTOCOL_VERSION, "jcmd", "ManagementAgent.start_local", null, null); + try { + checkHeader(response); + return getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); + } finally { + response.close(); + } + } + + /** + * {@inheritDoc} + */ + public void detach() throws IOException { + connection.close(); + } + + /** + * Represents a connection to a virtual machine. + */ + public interface Connection extends Closeable { + + /** + * Executes a command on the current connection. + * + * @param protocol The target VMs protocol version for the attach API. + * @param argument The arguments to send to the target VM. + * @return The response of the target JVM. + * @throws IOException If an I/O error occurred. + */ + Response execute(String protocol, String... argument) throws IOException; + + /** + * A response to an execution command to a VM. + */ + interface Response extends Closeable { + + /** + * Reads a buffer from the target VM. + * + * @param buffer The buffer to read to. + * @return The bytes read or {@code -1} if no more bytes could be read. + * @throws IOException If an I/O exception occurred. + */ + int read(byte[] buffer) throws IOException; + } + + /** + * A factory for creating connections to virtual machines. + */ + interface Factory { + + /** + * Connects to the supplied process. + * + * @param processId The process id. + * @return The connection to the virtual machine with the supplied process id. + * @throws IOException If an I/O exception occurs during connecting to the targeted VM. + */ + Connection connect(String processId) throws IOException; + + /** + * A factory for attaching via a socket file. + */ + abstract class ForSocketFile implements Factory { + + /** + * The name prefix for a socket. + */ + private static final String SOCKET_FILE_PREFIX = ".java_pid"; + + /** + * The name prefix for an attachment file indicator. + */ + private static final String ATTACH_FILE_PREFIX = ".attach_pid"; + + /** + * The temporary directory to use. + */ + private final String temporaryDirectory; + + /** + * The maximum amount of attempts for checking the establishment of a socket connection. + */ + private final int attempts; + + /** + * The pause between two checks for an established socket connection. + */ + private final long pause; + + /** + * The time unit of the pause time. + */ + private final TimeUnit timeUnit; + + /** + * Creates a connection factory for creating a socket connection via a file. + * + * @param temporaryDirectory The temporary directory to use. + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + */ + protected ForSocketFile(String temporaryDirectory, int attempts, long pause, TimeUnit timeUnit) { + this.temporaryDirectory = temporaryDirectory; + this.attempts = attempts; + this.pause = pause; + this.timeUnit = timeUnit; + } + + /** + * {@inheritDoc} + */ + public Connection connect(String processId) throws IOException { + File socket = new File(temporaryDirectory, SOCKET_FILE_PREFIX + processId); + if (!socket.exists()) { + String target = ATTACH_FILE_PREFIX + processId, path = "/proc/" + processId + "/cwd/" + target; + File attachFile = new File(path); + try { + if (!attachFile.createNewFile() && !attachFile.isFile()) { + throw new IllegalStateException("Could not create attach file: " + attachFile); + } + } catch (IOException ignored) { + attachFile = new File(temporaryDirectory, target); + if (!attachFile.createNewFile() && !attachFile.isFile()) { + throw new IllegalStateException("Could not create attach file: " + attachFile); + } + } + try { + kill(processId, 3); + int attempts = this.attempts; + while (!socket.exists() && attempts-- > 0) { + timeUnit.sleep(pause); + } + if (!socket.exists()) { + throw new IllegalStateException("Target VM did not respond: " + processId); + } + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(exception); + } finally { + if (!attachFile.delete()) { + attachFile.deleteOnExit(); + } + } + } + return doConnect(socket); + } + + /** + * Sends a kill signal to the target process. + * + * @param processId The process id. + * @param signal The signal to send. + */ + protected abstract void kill(String processId, int signal); + + /** + * Connects to the supplied POSIX socket. + * + * @param socket The socket to connect to. + * @return An active connection to the supplied socket. + * @throws IOException If an error occurs during connection. + */ + protected abstract Connection doConnect(File socket) throws IOException; + } + } + + /** + * A connection that is represented by a byte channel that is persistent during communication. + * + * @param The connection representation. + */ + abstract class OnPersistentByteChannel implements Connection { + + /** + * A blank line argument. + */ + private static final byte[] BLANK = new byte[]{0}; + + /** + * {@inheritDoc} + */ + public Connection.Response execute(String protocol, String... argument) throws IOException { + T connection = connect(); + try { + write(connection, protocol.getBytes("UTF-8")); + write(connection, BLANK); + for (String anArgument : argument) { + if (anArgument != null) { + write(connection, anArgument.getBytes("UTF-8")); + } + write(connection, BLANK); + } + return new Response(connection); + } catch (Throwable throwable) { + close(connection); + if (throwable instanceof RuntimeException) { + throw (RuntimeException) throwable; + } else if (throwable instanceof IOException) { + throw (IOException) throwable; + } else { + throw new IllegalStateException(throwable); + } + } + } + + /** + * A response of a persistent byte channel. + */ + private class Response implements Connection.Response { + + /** + * The connection representing this response. + */ + private final T connection; + + /** + * Creates a new response for a persistent byte channel. + * + * @param connection The connection representing this response. + */ + private Response(T connection) { + this.connection = connection; + } + + /** + * {@inheritDoc} + */ + public int read(byte[] buffer) throws IOException { + return OnPersistentByteChannel.this.read(connection, buffer); + } + + /** + * {@inheritDoc} + */ + public void close() throws IOException { + OnPersistentByteChannel.this.close(connection); + } + } + + /** + * Creates a new connection to the target VM. + * + * @return Returns a new connection to the target VM. + * @throws IOException If an I/O exception occurs. + */ + protected abstract T connect() throws IOException; + + /** + * Closes the connection to the target VM. + * + * @param connection The connection to close. + * @throws IOException If an I/O exception occurs. + */ + protected abstract void close(T connection) throws IOException; + + /** + * Writes to the target VM. + * + * @param connection The connection to write to. + * @param buffer The buffer to write to. + * @throws IOException If an I/O exception occurs during writing. + */ + protected abstract void write(T connection, byte[] buffer) throws IOException; + + /** + * Reads from the target VM. + * + * @param connection The connection to read from. + * @param buffer The buffer to store the result in. + * @return The number of byte that were read. + * @throws IOException If an I/O exception occurs. + */ + protected abstract int read(T connection, byte[] buffer) throws IOException; + } + + /** + * Implements a connection for a POSIX socket in JNA. + */ + class ForJnaPosixSocket extends OnPersistentByteChannel { + + /** + * The JNA library to use. + */ + private final PosixLibrary library; + + /** + * The POSIX socket. + */ + private final File socket; + + /** + * Creates a connection for a virtual POSIX socket implemented in JNA. + * + * @param library The JNA library to use. + * @param socket The POSIX socket. + */ + protected ForJnaPosixSocket(PosixLibrary library, File socket) { + this.library = library; + this.socket = socket; + } + + @Override + protected Integer connect() { + int handle = library.socket(1, 1, 0); + try { + PosixLibrary.SocketAddress address = new PosixLibrary.SocketAddress(); + try { + address.setPath(socket.getAbsolutePath()); + library.connect(handle, address, address.size()); + return handle; + } finally { + address = null; + } + } catch (RuntimeException exception) { + library.close(handle); + throw exception; + } + } + + @Override + protected int read(Integer handle, byte[] buffer) { + int read = library.read(handle, ByteBuffer.wrap(buffer), buffer.length); + return read == 0 ? -1 : read; + } + + @Override + protected void write(Integer handle, byte[] buffer) { + library.write(handle, ByteBuffer.wrap(buffer), buffer.length); + } + + @Override + protected void close(Integer handle) { + library.close(handle); + } + + /** + * {@inheritDoc} + */ + public void close() { + /* do nothing */ + } + + /** + * A JNA library binding for POSIX sockets. + */ + protected interface PosixLibrary extends Library { + + /** + * Sends a kill command. + * + * @param processId The process id to kill. + * @param signal The signal to send. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int kill(int processId, int signal) throws LastErrorException; + + /** + * Creates a POSIX socket connection. + * + * @param domain The socket's domain. + * @param type The socket's type. + * @param protocol The protocol version. + * @return A handle to the socket that was created or {@code 0} if no socket could be created. + * @throws LastErrorException If an error occurs. + */ + int socket(int domain, int type, int protocol) throws LastErrorException; + + /** + * Connects a socket connection. + * + * @param handle The socket's handle. + * @param address The address of the POSIX socket. + * @param length The length of the socket value. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int connect(int handle, SocketAddress address, int length) throws LastErrorException; + + /** + * Reads from a POSIX socket. + * + * @param handle The socket's handle. + * @param buffer The buffer to read from. + * @param count The bytes being read. + * @return The amount of bytes that could be read. + * @throws LastErrorException If an error occurs. + */ + int read(int handle, ByteBuffer buffer, int count) throws LastErrorException; + + /** + * Writes to a POSIX socket. + * + * @param handle The socket's handle. + * @param buffer The buffer to write to. + * @param count The bytes being written. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int write(int handle, ByteBuffer buffer, int count) throws LastErrorException; + + /** + * Closes the socket connection. + * + * @param handle The handle of the connection. + * @return The return code. + * @throws LastErrorException If an error occurs. + */ + int close(int handle) throws LastErrorException; + + /** + * Represents an address for a POSIX socket. + */ + class SocketAddress extends Structure { + + /** + * The socket family. + */ + @SuppressWarnings("unused") + public short family = 1; + + /** + * The socket path. + */ + public byte[] path = new byte[100]; + + /** + * Sets the socket path. + * + * @param path The socket path. + */ + protected void setPath(String path) { + try { + System.arraycopy(path.getBytes("UTF-8"), 0, this.path, 0, path.length()); + System.arraycopy(new byte[]{0}, 0, this.path, path.length(), 1); + } catch (UnsupportedEncodingException exception) { + throw new IllegalStateException(exception); + } + } + + @Override + protected List getFieldOrder() { + return Arrays.asList("family", "path"); + } + } + } + + /** + * A factory for a POSIX socket connection to a JVM using JNA. + */ + public static class Factory extends Connection.Factory.ForSocketFile { + + /** + * The socket library API. + */ + private final PosixLibrary library; + + /** + * Creates a connection factory for a POSIX socket using JNA. + * + * @param temporaryDirectory The temporary directory to use. + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + */ + @SuppressWarnings("deprecation") + public Factory(String temporaryDirectory, int attempts, long pause, TimeUnit timeUnit) { + super(temporaryDirectory, attempts, pause, timeUnit); + library = Native.loadLibrary("c", PosixLibrary.class); + } + + /** + * Creates a connection factory for a POSIX socket using JNA while locating the default temporary directory used on the + * current platform. + * + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + * @return An appropriate connection factory. + */ + @SuppressWarnings("deprecation") + public static Connection.Factory withDefaultTemporaryFolder(int attempts, long pause, TimeUnit timeUnit) { + String temporaryDirectory; + if (Platform.isMac()) { + MacLibrary library = Native.loadLibrary("c", MacLibrary.class); + Memory memory = new Memory(4096); + try { + long length = library.confstr(MacLibrary.CS_DARWIN_USER_TEMP_DIR, memory, memory.size()); + if (length == 0 || length > 4096) { + temporaryDirectory = "/tmp"; + } else { + temporaryDirectory = memory.getString(0); + } + } finally { + memory = null; + } + } else { + temporaryDirectory = "/tmp"; + } + return new Factory(temporaryDirectory, attempts, pause, timeUnit); + } + + @Override + protected void kill(String processId, int signal) { + library.kill(Integer.parseInt(processId), signal); + } + + @Override + public Connection doConnect(File socket) { + return new Connection.ForJnaPosixSocket(library, socket); + } + + /** + * A library for reading a Mac user's temporary directory. + */ + public interface MacLibrary extends Library { + + /** + * The temporary directory. + */ + int CS_DARWIN_USER_TEMP_DIR = 65537; + + /** + * Reads a configuration dependant variable into a memory segment. + * + * @param name The name of the variable. + * @param buffer The buffer to read the variable into. + * @param length The length of the buffer. + * @return The amount of bytes written to the buffer. + */ + long confstr(int name, Pointer buffer, long length); + } + } + } + + /** + * Implements a connection for a Windows named pipe in JNA. + */ + class ForJnaWindowsNamedPipe implements Connection { + + /** + * Indicates a memory release. + */ + private static final int MEM_RELEASE = 0x8000; + + /** + * The library to use for communicating with Windows native functions. + */ + private final WindowsLibrary library; + + /** + * The library to use for communicating with Windows attachment extension that is included as a DLL. + */ + private final WindowsAttachLibrary attachLibrary; + + /** + * The handle of the target VM's process. + */ + private final WinNT.HANDLE process; + + /** + * A pointer to the code that was injected into the target process. + */ + private final WinDef.LPVOID code; + + /** + * A source of random values being used for generating pipe names. + */ + private final SecureRandom random; + + /** + * Creates a new connection via a named pipe. + * + * @param library The library to use for communicating with Windows native functions. + * @param attachLibrary The library to use for communicating with Windows attachment extension that is included as a DLL. + * @param process The handle of the target VM's process. + * @param code A pointer to the code that was injected into the target process. + */ + protected ForJnaWindowsNamedPipe(WindowsLibrary library, + WindowsAttachLibrary attachLibrary, + WinNT.HANDLE process, + WinDef.LPVOID code) { + this.library = library; + this.attachLibrary = attachLibrary; + this.process = process; + this.code = code; + random = new SecureRandom(); + } + + /** + * {@inheritDoc} + */ + public Response execute(String protocol, String... argument) { + if (!"1".equals(protocol)) { + throw new IllegalArgumentException("Unknown protocol version: " + protocol); + } else if (argument.length > 4) { + throw new IllegalArgumentException("Cannot supply more then four arguments to Windows attach mechanism: " + Arrays.asList(argument)); + } + String name = "\\\\.\\pipe\\javatool" + Math.abs(random.nextInt() + 1); + + WinBase.SECURITY_ATTRIBUTES sa = createSecurityAttributesToAllowMediumIntegrity(); + + WinNT.HANDLE pipe = Kernel32.INSTANCE.CreateNamedPipe(name, + WinBase.PIPE_ACCESS_INBOUND, + WinBase.PIPE_TYPE_BYTE | WinBase.PIPE_READMODE_BYTE | WinBase.PIPE_WAIT, + 1, + 4096, + 8192, + WinBase.NMPWAIT_USE_DEFAULT_WAIT, + sa); + if (pipe == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + WinDef.LPVOID data = attachLibrary.allocate_remote_argument(process, + name, + argument.length < 1 ? null : argument[0], + argument.length < 2 ? null : argument[1], + argument.length < 3 ? null : argument[2], + argument.length < 4 ? null : argument[3]); + if (data == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + WinNT.HANDLE thread = library.CreateRemoteThread(process, null, 0, code.getPointer(), data.getPointer(), null, null); + if (thread == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + int result = Kernel32.INSTANCE.WaitForSingleObject(thread, WinBase.INFINITE); + if (result != 0) { + throw new Win32Exception(result); + } + IntByReference exitCode = new IntByReference(); + if (!library.GetExitCodeThread(thread, exitCode)) { + throw new Win32Exception(Native.getLastError()); + } else if (exitCode.getValue() != 0) { + throw new IllegalStateException("Target VM could not dispatch command successfully: " + exitCode.getValue()); + } + if (!Kernel32.INSTANCE.ConnectNamedPipe(pipe, null)) { + int code = Native.getLastError(); + if (code != WinError.ERROR_PIPE_CONNECTED) { + throw new Win32Exception(code); + } + } + return new NamedPipeResponse(pipe); + } finally { + if (!Kernel32.INSTANCE.CloseHandle(thread)) { + throw new Win32Exception(Native.getLastError()); + } + } + } finally { + if (!library.VirtualFreeEx(process, data.getPointer(), 0, MEM_RELEASE)) { + throw new Win32Exception(Native.getLastError()); + } + } + } catch (Throwable throwable) { + if (!Kernel32.INSTANCE.CloseHandle(pipe)) { + throw new Win32Exception(Native.getLastError()); + } else if (throwable instanceof RuntimeException) { + throw (RuntimeException) throwable; + } else { + throw new IllegalStateException(throwable); + } + } + } + + /** + * Custom {@link WinBase.SECURITY_ATTRIBUTES} is required here to "get" Medium Integrity Level. + * In order to allow Medium Integrity Level clients to open + * and use a NamedPipe created by an High Integrity Level process. + * + * @return A security attributes object that gives everyone read and write access. + */ + private WinBase.SECURITY_ATTRIBUTES createSecurityAttributesToAllowMediumIntegrity() { + // Allow read/write to Everybody + WinNT.PSID pSidEverybody = new WinNT.PSID(WinNT.SECURITY_MAX_SID_SIZE); + if (!Advapi32.INSTANCE.CreateWellKnownSid(WinNT.WELL_KNOWN_SID_TYPE.WinWorldSid, null, pSidEverybody, new IntByReference(WinNT.SECURITY_MAX_SID_SIZE))) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + // Allow full control to System + WinNT.PSID pSidSystem = new WinNT.PSID(WinNT.SECURITY_MAX_SID_SIZE); + if (!Advapi32.INSTANCE.CreateWellKnownSid(WinNT.WELL_KNOWN_SID_TYPE.WinBuiltinSystemOperatorsSid, null, pSidSystem, new IntByReference(WinNT.SECURITY_MAX_SID_SIZE))) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + // Allow full control to Administrators + WinNT.PSID pSidAdmin = new WinNT.PSID(WinNT.SECURITY_MAX_SID_SIZE); + if (!Advapi32.INSTANCE.CreateWellKnownSid(WinNT.WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, null, pSidAdmin, new IntByReference(WinNT.SECURITY_MAX_SID_SIZE))) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + + // Prepare ACL + int cbAcl = Native.getNativeSize(WinNT.ACL.class, null); + cbAcl += Native.getNativeSize(WinNT.ACCESS_ALLOWED_ACE.class, null) * 3; + cbAcl += (Advapi32.INSTANCE.GetLengthSid(pSidEverybody) - WinDef.DWORD.SIZE); + cbAcl += (Advapi32.INSTANCE.GetLengthSid(pSidSystem) - WinDef.DWORD.SIZE); + cbAcl += (Advapi32.INSTANCE.GetLengthSid(pSidAdmin) - WinDef.DWORD.SIZE); + cbAcl = Advapi32Util.alignOnDWORD(cbAcl); + WinNT.ACL pAcl = new WinNT.ACL(cbAcl); + if (!Advapi32.INSTANCE.InitializeAcl(pAcl, cbAcl, WinNT.ACL_REVISION)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_READ | WinNT.GENERIC_WRITE, pSidEverybody)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_ALL, pSidSystem)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_ALL, pSidAdmin)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WinNT.SECURITY_DESCRIPTOR sd = new WinNT.SECURITY_DESCRIPTOR(64 * 1024); + if (!Advapi32.INSTANCE.InitializeSecurityDescriptor(sd, WinNT.SECURITY_DESCRIPTOR_REVISION)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.SetSecurityDescriptorDacl(sd, true, pAcl, false)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WinBase.SECURITY_ATTRIBUTES sa = new WinBase.SECURITY_ATTRIBUTES(); + sa.dwLength = new WinDef.DWORD(sa.size()); + sa.lpSecurityDescriptor = sd.getPointer(); + return sa; + } + + /** + * {@inheritDoc} + */ + public void close() { + try { + if (!library.VirtualFreeEx(process, code.getPointer(), 0, MEM_RELEASE)) { + throw new Win32Exception(Native.getLastError()); + } + } finally { + if (!Kernel32.INSTANCE.CloseHandle(process)) { + throw new Win32Exception(Native.getLastError()); + } + } + } + + /** + * A library for interacting with Windows. + */ + protected interface WindowsLibrary extends StdCallLibrary { + + /** + * Changes the state of memory in a given process. + * + * @param process The process in which to change the memory. + * @param address The address of the memory to allocate. + * @param size The size of the allocated region. + * @param allocationType The allocation type. + * @param protect The memory protection. + * @return A pointer to the allocated memory. + */ + @SuppressWarnings({"unused", "checkstyle:methodname"}) + Pointer VirtualAllocEx(WinNT.HANDLE process, Pointer address, int size, int allocationType, int protect); + + /** + * Frees memory in the given process. + * + * @param process The process in which to change the memory. + * @param address The address of the memory to free. + * @param size The size of the freed region. + * @param freeType The freeing type. + * @return {@code true} if the operation succeeded. + */ + @SuppressWarnings("checkstyle:methodname") + boolean VirtualFreeEx(WinNT.HANDLE process, Pointer address, int size, int freeType); + + /** + * An alternative implementation of + * {@link Kernel32#CreateRemoteThread(WinNT.HANDLE, WinBase.SECURITY_ATTRIBUTES, int, WinBase.FOREIGN_THREAD_START_ROUTINE, Pointer, WinDef.DWORD, Pointer)} + * that uses a pointer as the {@code code} argument rather then a structure to avoid accessing foreign memory. + * + * @param process A handle of the target process. + * @param securityAttributes The security attributes to use or {@code null} if no attributes are provided. + * @param stackSize The stack size or {@code 0} for using the system default. + * @param code A pointer to the code to execute. + * @param argument A pointer to the argument to provide to the code being executed. + * @param creationFlags The creation flags or {@code null} if no flags are set. + * @param threadId A pointer to the thread id or {@code null} if no thread reference is set. + * @return A handle to the created remote thread or {@code null} if the creation failed. + */ + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE CreateRemoteThread(WinNT.HANDLE process, + WinBase.SECURITY_ATTRIBUTES securityAttributes, + int stackSize, + Pointer code, + Pointer argument, + WinDef.DWORD creationFlags, + Pointer threadId); + + /** + * Receives the exit code of a given thread. + * + * @param thread A handle to the targeted thread. + * @param exitCode A reference to the exit code value. + * @return {@code true} if the exit code retrieval succeeded. + */ + @SuppressWarnings("checkstyle:methodname") + boolean GetExitCodeThread(WinNT.HANDLE thread, IntByReference exitCode); + } + + /** + * A library for interacting with Windows. + */ + protected interface WindowsAttachLibrary extends StdCallLibrary { + + /** + * Allocates the code to invoke on the remote VM. + * + * @param process A handle to the target process. + * @return A pointer to the allocated code or {@code null} if the code could not be allocated. + */ + + @SuppressWarnings("checkstyle:methodname") + WinDef.LPVOID allocate_remote_code(WinNT.HANDLE process); + + /** + * Allocates the remote argument to supply to the remote code upon execution. + * + * @param process A handle to the target process. + * @param pipe The name of the pipe used for supplying an answer. + * @param argument0 The first argument or {@code null} if no such argument is provided. + * @param argument1 The second argument or {@code null} if no such argument is provided. + * @param argument2 The third argument or {@code null} if no such argument is provided. + * @param argument3 The forth argument or {@code null} if no such argument is provided. + * @return A pointer to the allocated argument or {@code null} if the argument could not be allocated. + */ + + @SuppressWarnings("checkstyle:methodname") + WinDef.LPVOID allocate_remote_argument(WinNT.HANDLE process, + String pipe, + String argument0, + String argument1, + String argument2, + String argument3); + } + + /** + * A response that is sent via a named pipe. + */ + protected static class NamedPipeResponse implements Response { + + /** + * A handle of the named pipe. + */ + private final WinNT.HANDLE pipe; + + /** + * Creates a new response via a named pipe. + * + * @param pipe The handle of the named pipe. + */ + protected NamedPipeResponse(WinNT.HANDLE pipe) { + this.pipe = pipe; + } + + /** + * {@inheritDoc} + */ + public int read(byte[] buffer) { + IntByReference read = new IntByReference(); + if (!Kernel32.INSTANCE.ReadFile(pipe, buffer, buffer.length, read, null)) { + int code = Native.getLastError(); + if (code == WinError.ERROR_BROKEN_PIPE) { + return -1; + } else { + throw new Win32Exception(code); + } + } + return read.getValue(); + } + + /** + * {@inheritDoc} + */ + public void close() { + try { + if (!Kernel32.INSTANCE.DisconnectNamedPipe(pipe)) { + throw new Win32Exception(Native.getLastError()); + } + } finally { + if (!Kernel32.INSTANCE.CloseHandle(pipe)) { + throw new Win32Exception(Native.getLastError()); + } + } + } + } + + /** + * A factory for establishing a connection to a JVM using a named pipe in JNA. + */ + public static class Factory implements Connection.Factory { + + /** + * The name of the native code library that is included in this artifact to support Windows attachment. + * This property can be set by other libraries that shade Byte Buddy agent and relocates the library. + */ + public static final String LIBRARY_NAME = "net.bytebuddy.library.name"; + + /** + * The library to use for communicating with Windows native functions. + */ + private final WindowsLibrary library; + + /** + * The library to use for communicating with Windows attachment extension that is included as a DLL. + */ + private final WindowsAttachLibrary attachLibrary; + + /** + * Creates a new connection factory for Windows using JNA. + */ + @SuppressWarnings("deprecation") + public Factory() { + library = Native.loadLibrary("kernel32", WindowsLibrary.class, W32APIOptions.DEFAULT_OPTIONS); + attachLibrary = Native.loadLibrary(System.getProperty(LIBRARY_NAME, "attach_hotspot_windows"), WindowsAttachLibrary.class); + } + + /** + * {@inheritDoc} + */ + public Connection connect(String processId) { + WinNT.HANDLE process = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_ALL_ACCESS, false, Integer.parseInt(processId)); + if (process == null) { + throw new Win32Exception(Native.getLastError()); + } + try { + WinDef.LPVOID code = attachLibrary.allocate_remote_code(process); + if (code == null) { + throw new Win32Exception(Native.getLastError()); + } + return new ForJnaWindowsNamedPipe(library, attachLibrary, process, code); + } catch (Throwable throwable) { + if (!Kernel32.INSTANCE.CloseHandle(process)) { + throw new Win32Exception(Native.getLastError()); + } else if (throwable instanceof RuntimeException) { + throw (RuntimeException) throwable; + } else { + throw new IllegalStateException(throwable); + } + } + } + } + } + + /** + * A connection to a VM using a Solaris door. + */ + class ForJnaSolarisDoor implements Connection { + + /** + * The library to use for interacting with Solaris. + */ + private final SolarisLibrary library; + + /** + * The socket used for communication. + */ + private final File socket; + + /** + * Creates a new connection using a Solaris door. + * + * @param library The library to use for interacting with Solaris. + * @param socket The socket used for communication. + */ + protected ForJnaSolarisDoor(SolarisLibrary library, File socket) { + this.library = library; + this.socket = socket; + } + + /** + * {@inheritDoc} + */ + public Connection.Response execute(String protocol, String... argument) throws IOException { + int handle = library.open(socket.getAbsolutePath(), 2); + try { + SolarisLibrary.DoorArgument door = new SolarisLibrary.DoorArgument(); + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write(protocol.getBytes("UTF-8")); + outputStream.write(0); + for (String anArgument : argument) { + if (anArgument != null) { + outputStream.write(anArgument.getBytes("UTF-8")); + } + outputStream.write(0); + } + door.dataSize = outputStream.size(); + Memory dataPointer = new Memory(outputStream.size()); + try { + dataPointer.write(0, outputStream.toByteArray(), 0, outputStream.size()); + door.dataPointer = dataPointer; + Memory result = new Memory(128); + try { + door.resultPointer = result; + door.resultSize = (int) result.size(); + if (library.door_call(handle, door) != 0) { + throw new IllegalStateException("Door call to target VM failed"); + } else if (door.resultSize < 4 || door.resultPointer.getInt(0) != 0) { + throw new IllegalStateException("Target VM could not execute door call"); + } else if (door.descriptorCount != 1 || door.descriptorPointer == null) { + throw new IllegalStateException("Did not receive communication descriptor from target VM"); + } else { + return new Response(library, door.descriptorPointer.getInt(4)); + } + } finally { + result = null; + } + } finally { + dataPointer = null; + } + } finally { + door = null; + } + } finally { + library.close(handle); + } + } + + /** + * {@inheritDoc} + */ + public void close() { + /* do nothing */ + } + + /** + * A library for interacting with Solaris. + */ + protected interface SolarisLibrary extends Library { + + /** + * Sends a kill signal to the target VM. + * + * @param processId The target process's id. + * @param signal The signal to send. + * @return The return code. + * @throws LastErrorException If an error occurred while sending the signal. + */ + int kill(int processId, int signal) throws LastErrorException; + + /** + * Opens a file. + * + * @param file The file name. + * @param flags the flags for opening. + * @return The file descriptor. + * @throws LastErrorException If the file could not be opened. + */ + int open(String file, int flags) throws LastErrorException; + + /** + * Reads from a handle. + * + * @param handle The handle representing the source being read. + * @param buffer The buffer to read to. + * @param length The buffer length. + * @return The amount of bytes being read. + * @throws LastErrorException If a read operation failed. + */ + int read(int handle, ByteBuffer buffer, int length) throws LastErrorException; + + /** + * Releases a descriptor. + * + * @param descriptor The descriptor to release. + * @return The return code. + * @throws LastErrorException If the descriptor could not be closed. + */ + int close(int descriptor) throws LastErrorException; + + /** + * Executes a door call. + * + * @param descriptor The door's descriptor. + * @param argument A pointer to the argument. + * @return The door's handle. + * @throws LastErrorException If the door call failed. + */ + @SuppressWarnings("checkstyle:methodname") + int door_call(int descriptor, DoorArgument argument) throws LastErrorException; + + /** + * A structure representing the argument to a Solaris door operation. + */ + class DoorArgument extends Structure { + + /** + * A pointer to the operation argument. + */ + + public Pointer dataPointer; + + /** + * The size of the argument being pointed to. + */ + public int dataSize; + + /** + * A pointer to the operation descriptor. + */ + + public Pointer descriptorPointer; + + /** + * The size of the operation argument. + */ + public int descriptorCount; + + /** + * A pointer to the operation result. + */ + public Pointer resultPointer; + + /** + * The size of the operation argument. + */ + public int resultSize; + + @Override + protected List getFieldOrder() { + return Arrays.asList("dataPointer", "dataSize", "descriptorPointer", "descriptorCount", "resultPointer", "resultSize"); + } + } + } + + /** + * A response from a VM using a Solaris door. + */ + protected static class Response implements Connection.Response { + + /** + * The Solaris library to use. + */ + private final SolarisLibrary library; + + /** + * The door handle. + */ + private final int handle; + + /** + * Creates a response from a VM using a Solaris door. + * + * @param library The Solaris library to use. + * @param handle The door handle. + */ + protected Response(SolarisLibrary library, int handle) { + this.library = library; + this.handle = handle; + } + + /** + * {@inheritDoc} + */ + public int read(byte[] buffer) { + int read = library.read(handle, ByteBuffer.wrap(buffer), buffer.length); + return read == 0 ? -1 : read; + } + + /** + * {@inheritDoc} + */ + public void close() { + library.close(handle); + } + } + + /** + * A factory for establishing a connection to a JVM using a Solaris door in JNA. + */ + public static class Factory extends Connection.Factory.ForSocketFile { + + /** + * The library to use for interacting with Solaris. + */ + private final SolarisLibrary library; + + /** + * Creates a new connection factory for a Solaris VM. + * + * @param attempts The maximum amount of attempts for checking the establishment of a socket connection. + * @param pause The pause between two checks for an established socket connection. + * @param timeUnit The time unit of the pause time. + */ + @SuppressWarnings("deprecation") + public Factory(int attempts, long pause, TimeUnit timeUnit) { + super("/tmp", attempts, pause, timeUnit); + library = Native.loadLibrary("c", SolarisLibrary.class); + } + + /** + * {@inheritDoc} + */ + protected void kill(String processId, int signal) { + library.kill(Integer.parseInt(processId), signal); + } + + /** + * {@inheritDoc} + */ + protected Connection doConnect(File socket) { + return new ForJnaSolarisDoor(library, socket); + } + } + } + } + } + + /** + * A virtual machine attachment implementation for OpenJ9 or any compatible JVM. + */ + class ForOpenJ9 extends AbstractBase { + + /** + * The temporary folder for attachment files for OpenJ9 VMs. + */ + private static final String IBM_TEMPORARY_FOLDER = "com.ibm.tools.attach.directory"; + + /** + * A secure random for generating randomized ids. + */ + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + + /** + * The socket on which this VM and the target VM communicate. + */ + private final Socket socket; + + /** + * Creates a new virtual machine connection for OpenJ9. + * + * @param socket The socket on which this VM and the target VM communicate. + */ + protected ForOpenJ9(Socket socket) { + this.socket = socket; + } + + /** + * Attaches to the supplied process id using the default JNA implementation. This method will not consider + * attaching to VMs owned by different users than the current user. + * + * @param processId The process id. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId) throws IOException { + return attach(processId, 5000, Platform.isWindows() + ? new Dispatcher.ForJnaWindowsEnvironment() + : new Dispatcher.ForJnaPosixEnvironment(15, 100, TimeUnit.MILLISECONDS)); + } + + /** + * Attaches to the supplied process id. + * + * @param processId The process id. + * @param timeout The timeout for establishing the socket connection. + * @param dispatcher The connector to use to communicate with the target VM. + * @return A suitable virtual machine implementation. + * @throws IOException If an IO exception occurs during establishing the connection. + */ + public static VirtualMachine attach(String processId, int timeout, Dispatcher dispatcher) throws IOException { + String temporary = System.getProperty(IBM_TEMPORARY_FOLDER); + File directory = temporary == null + ? new File(dispatcher.getTemporaryFolder(processId), ".com_ibm_tools_attach") + : new File(temporary); + long userId = dispatcher.userId(); + RandomAccessFile attachLock = new RandomAccessFile(new File(directory, "_attachlock"), "rw"); + try { + FileLock attachLockLock = attachLock.getChannel().lock(); + try { + List virtualMachines; + RandomAccessFile master = new RandomAccessFile(new File(directory, "_master"), "rw"); + try { + FileLock masterLock = master.getChannel().lock(); + try { + File[] vmFolder = directory.listFiles(); + if (vmFolder == null) { + throw new IllegalStateException("No descriptor files found in " + directory); + } + virtualMachines = new ArrayList(); + for (File aVmFolder : vmFolder) { + if (aVmFolder.isDirectory() && (userId == 0L || dispatcher.getOwnerIdOf(aVmFolder) == userId)) { + File attachInfo = new File(aVmFolder, "attachInfo"); + if (attachInfo.isFile()) { + Properties virtualMachine = new Properties(); + FileInputStream inputStream = new FileInputStream(attachInfo); + try { + virtualMachine.load(inputStream); + } finally { + inputStream.close(); + } + int targetProcessId = Integer.parseInt(virtualMachine.getProperty("processId")); + long targetUserId; + try { + targetUserId = Long.parseLong(virtualMachine.getProperty("userUid")); + } catch (NumberFormatException ignored) { + targetUserId = 0L; + } + if (userId != 0L && targetUserId == 0L) { + targetUserId = dispatcher.getOwnerIdOf(attachInfo); + } + if (targetProcessId == 0L || dispatcher.isExistingProcess(targetProcessId)) { + virtualMachines.add(virtualMachine); + } else if (userId == 0L || targetUserId == userId) { + File[] vmFile = aVmFolder.listFiles(); + if (vmFile != null) { + for (File aVmFile : vmFile) { + if (!aVmFile.delete()) { + aVmFile.deleteOnExit(); + } + } + } + if (!aVmFolder.delete()) { + aVmFolder.deleteOnExit(); + } + } + } + } + } + } finally { + masterLock.release(); + } + } finally { + master.close(); + } + Properties target = null; + for (Properties virtualMachine : virtualMachines) { + if (virtualMachine.getProperty("processId").equalsIgnoreCase(processId)) { + target = virtualMachine; + break; + } + } + if (target == null) { + throw new IllegalStateException("Could not locate target process info in " + directory); + } + ServerSocket serverSocket = new ServerSocket(0); + try { + serverSocket.setSoTimeout(timeout); + File receiver = new File(directory, target.getProperty("vmId")); + String key; + synchronized (SECURE_RANDOM) { + key = Long.toHexString(SECURE_RANDOM.nextLong()); + } + File reply = new File(receiver, "replyInfo"); + long targetUserId; + try { + targetUserId = Long.parseLong(target.getProperty("userUid")); + } catch (NumberFormatException ignored) { + targetUserId = 0L; + } + try { + if (reply.createNewFile()) { + dispatcher.setPermissions(reply, 0600); + } + if (userId == 0L && targetUserId != 0L) { + dispatcher.chownFileToUser(reply, targetUserId); + } + FileOutputStream outputStream = new FileOutputStream(reply); + try { + outputStream.write(key.getBytes("UTF-8")); + outputStream.write("\n".getBytes("UTF-8")); + outputStream.write(Long.toString(serverSocket.getLocalPort()).getBytes("UTF-8")); + outputStream.write("\n".getBytes("UTF-8")); + } finally { + outputStream.close(); + } + Map locks = new HashMap(); + try { + String pid = Long.toString(dispatcher.pid()); + for (Properties virtualMachine : virtualMachines) { + if (!virtualMachine.getProperty("processId").equalsIgnoreCase(pid)) { + String attachNotificationSync = virtualMachine.getProperty("attachNotificationSync"); + RandomAccessFile syncFile = new RandomAccessFile(attachNotificationSync == null + ? new File(directory, "attachNotificationSync") + : new File(attachNotificationSync), "rw"); + try { + locks.put(syncFile, syncFile.getChannel().lock()); + } catch (IOException ignored) { + syncFile.close(); + } + } + } + int notifications = 0; + File[] item = directory.listFiles(); + if (item != null) { + for (File anItem : item) { + String name = anItem.getName(); + if (!name.startsWith(".trash_") + && !name.equalsIgnoreCase("_attachlock") + && !name.equalsIgnoreCase("_master") + && !name.equalsIgnoreCase("_notifier")) { + notifications += 1; + } + } + } + boolean global = Boolean.parseBoolean(target.getProperty("globalSemaphore")); + dispatcher.incrementSemaphore(directory, "_notifier", global, notifications); + try { + Socket socket = serverSocket.accept(); + String answer = new String(read(socket), "UTF-8"); + if (answer.contains(' ' + key + ' ')) { + return new ForOpenJ9(socket); + } else { + socket.close(); + throw new IllegalStateException("Unexpected answered to attachment: " + answer); + } + } finally { + dispatcher.decrementSemaphore(directory, "_notifier", global, notifications); + } + } finally { + for (Map.Entry entry : locks.entrySet()) { + try { + try { + entry.getValue().release(); + } finally { + entry.getKey().close(); + } + } catch (Throwable ignored) { + /* do nothing */ + } + } + } + } finally { + if (!reply.delete()) { + reply.deleteOnExit(); + } + } + } finally { + serverSocket.close(); + } + } finally { + attachLockLock.release(); + } + } finally { + attachLock.close(); + } + } + + /** + * {@inheritDoc} + */ + public Properties getSystemProperties() throws IOException { + write(socket, "ATTACH_GETSYSTEMPROPERTIES".getBytes("UTF-8")); + Properties properties = new Properties(); + properties.load(new ByteArrayInputStream(read(socket))); + return properties; + } + + /** + * {@inheritDoc} + */ + public Properties getAgentProperties() throws IOException { + write(socket, "ATTACH_GETAGENTPROPERTIES".getBytes("UTF-8")); + Properties properties = new Properties(); + properties.load(new ByteArrayInputStream(read(socket))); + return properties; + } + + /** + * {@inheritDoc} + */ + public void loadAgent(String jarFile, String argument) throws IOException { + write(socket, ("ATTACH_LOADAGENT(instrument," + jarFile + '=' + (argument == null ? "" : argument) + ')').getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM failed loading agent: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void loadAgentPath(String path, String argument) throws IOException { + write(socket, ("ATTACH_LOADAGENTPATH(" + path + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM failed loading native agent: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void loadAgentLibrary(String library, String argument) throws IOException { + write(socket, ("ATTACH_LOADAGENTLIBRARY(" + library + (argument == null ? "" : (',' + argument)) + ')').getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM failed loading native library: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void startManagementAgent(Properties properties) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + properties.store(outputStream, null); + write(socket, "ATTACH_START_MANAGEMENT_AGENT".getBytes("UTF-8")); + write(socket, outputStream.toByteArray()); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM could not start management agent: " + answer); + } else if (!answer.startsWith("ATTACH_ACK") && !answer.startsWith("ATTACH_RESULT=")) { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public String startLocalManagementAgent() throws IOException { + write(socket, "ATTACH_START_LOCAL_MANAGEMENT_AGENT".getBytes("UTF-8")); + String answer = new String(read(socket), "UTF-8"); + if (answer.startsWith("ATTACH_ERR")) { + throw new IllegalStateException("Target VM could not start management agent: " + answer); + } else if (answer.startsWith("ATTACH_ACK")) { + return answer.substring("ATTACH_ACK".length()); + } else if (answer.startsWith("ATTACH_RESULT=")) { + return answer.substring("ATTACH_RESULT=".length()); + } else { + throw new IllegalStateException("Unexpected response: " + answer); + } + } + + /** + * {@inheritDoc} + */ + public void detach() throws IOException { + try { + write(socket, "ATTACH_DETACH".getBytes("UTF-8")); + read(socket); // The answer is intentionally ignored. + } finally { + socket.close(); + } + } + + /** + * Writes the supplied value to the target socket. + * + * @param socket The socket to write to. + * @param value The value being written. + * @throws IOException If an I/O exception occurs. + */ + private static void write(Socket socket, byte[] value) throws IOException { + socket.getOutputStream().write(value); + socket.getOutputStream().write(0); + socket.getOutputStream().flush(); + } + + /** + * Reads a {@code '\0'}-terminated value from the target socket. + * + * @param socket The socket to read from. + * @return The value that was read. + * @throws IOException If an I/O exception occurs. + */ + private static byte[] read(Socket socket) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = socket.getInputStream().read(buffer)) != -1) { + if (length > 0 && buffer[length - 1] == 0) { + outputStream.write(buffer, 0, length - 1); + break; + } else { + outputStream.write(buffer, 0, length); + } + } + return outputStream.toByteArray(); + } + + /** + * A dispatcher for native operations being used for communication with an OpenJ9 virtual machine. + */ + public interface Dispatcher { + + /** + * Returns this machine's temporary folder. + * + * @param processId The target process's id. + * @return The temporary folder. + */ + String getTemporaryFolder(String processId); + + /** + * Returns the process id of this process. + * + * @return The process id of this process. + */ + int pid(); + + /** + * Returns the user id of this process. + * + * @return The user id of this process + */ + int userId(); + + /** + * Returns {@code true} if the supplied process id is a running process. + * + * @param processId The process id to evaluate. + * @return {@code true} if the supplied process id is currently running. + */ + boolean isExistingProcess(int processId); + + /** + * Returns the user id of the owner of the supplied file. + * + * @param file The file for which to locate the owner. + * @return The owner id of the supplied file. + */ + int getOwnerIdOf(File file); + + /** + * Sets permissions for the supplied file. + * + * @param file The file for which to set the permissions. + * @param permissions The permission bits to set. + */ + void setPermissions(File file, int permissions); + + /** + * Increments a semaphore. + * + * @param directory The sempahore's control directory. + * @param name The semaphore's name. + * @param global {@code true} if the semaphore is in the global namespace (only applicable on Windows). + * @param count The amount of increments. + */ + void incrementSemaphore(File directory, String name, boolean global, int count); + + /** + * Decrements a semaphore. + * + * @param directory The sempahore's control directory. + * @param name The semaphore's name. + * @param global {@code true} if the semaphore is in the global namespace (only applicable on Windows). + * @param count The amount of decrements. + */ + void decrementSemaphore(File directory, String name, boolean global, int count); + + /** + * Changes the ownership of a file. Can be called only if this process is owned by root. + * + * @param file The path of the file to change ownership of. + * @param userId The user that should own the file. + */ + void chownFileToUser(File file, long userId); + + /** + * A connector implementation for a POSIX environment using JNA. + */ + class ForJnaPosixEnvironment implements Dispatcher { + + /** + * The JNA library to use. + */ + private final PosixLibrary library; + + /** + * The POSIX owner provider to use. + */ + private final PosixOwnerProvider provider; + + /** + * Creates a new connector for a POSIX environment using JNA. + * + * @param attempts The maximum amount of attempts for checking the result of a foreign process. + * @param pause The pause between two checks for another process to return. + * @param timeUnit The time unit of the pause time. + */ + @SuppressWarnings("deprecation") + public ForJnaPosixEnvironment(int attempts, long pause, TimeUnit timeUnit) { + provider = Platform.isAIX() + ? new PosixOwnerProvider.UsingIStat(attempts, pause, timeUnit) + : new PosixOwnerProvider.UsingStat(attempts, pause, timeUnit); + library = Native.loadLibrary("c", PosixLibrary.class); + } + + /** + * {@inheritDoc} + */ + public String getTemporaryFolder(String processId) { + if (Platform.isLinux()) { + File file = new File("/proc/" + processId + "/root/tmp"); + if (file.isDirectory() && file.canRead()) { + return file.getAbsolutePath(); + } + } + String temporaryFolder = System.getenv("TMPDIR"); + return temporaryFolder == null ? "/tmp" : temporaryFolder; + } + + /** + * {@inheritDoc} + */ + public int pid() { + return library.getpid(); + } + + /** + * {@inheritDoc} + */ + public int userId() { + return library.getuid(); + } + + /** + * {@inheritDoc} + */ + public boolean isExistingProcess(int processId) { + return library.kill(processId, PosixLibrary.NULL_SIGNAL) != PosixLibrary.ESRCH; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + return provider.getOwnerIdOf(file); + } + + /** + * {@inheritDoc} + */ + public void setPermissions(File file, int permissions) { + library.chmod(file.getAbsolutePath(), permissions); + } + + /** + * {@inheritDoc} + */ + public void incrementSemaphore(File directory, String name, boolean global, int count) { + notifySemaphore(directory, name, count, (short) 1, (short) 0, false); + } + + /** + * {@inheritDoc} + */ + public void decrementSemaphore(File directory, String name, boolean global, int count) { + notifySemaphore(directory, name, count, (short) -1, (short) (PosixLibrary.SEM_UNDO | PosixLibrary.IPC_NOWAIT), true); + } + + /** + * {@inheritDoc} + */ + public void chownFileToUser(File file, long userId) { + library.chown(file.getAbsolutePath(), userId); + } + + /** + * Notifies a POSIX semaphore. + * + * @param directory The semaphore's directory. + * @param name The semaphore's name. + * @param count The amount of notifications to send. + * @param operation The operation to apply. + * @param flags The flags to set. + * @param acceptUnavailable {@code true} if a {@code EAGAIN} code should be accepted. + */ + private void notifySemaphore(File directory, String name, int count, short operation, short flags, boolean acceptUnavailable) { + int semaphore = library.semget(library.ftok(new File(directory, name).getAbsolutePath(), 0xA1), 2, 0666); + PosixLibrary.SemaphoreOperation target = new PosixLibrary.SemaphoreOperation(); + target.operation = operation; + target.flags = flags; + while (count-- > 0) { + try { + library.semop(semaphore, target, 1); + } catch (LastErrorException exception) { + if (acceptUnavailable && (Native.getLastError() == PosixLibrary.EAGAIN + || Native.getLastError() == PosixLibrary.EDEADLK)) { + break; + } else { + throw exception; + } + } + } + } + + /** + * An API for interaction with POSIX systems. + */ + protected interface PosixLibrary extends Library { + + /** + * A null signal. + */ + int NULL_SIGNAL = 0; + + /** + * Indicates that a process does not exist. + */ + int ESRCH = 3; + + /** + * Indicates that a request timed out. + */ + int EAGAIN = 11; + + /** + * Indicates a dead lock on a resource. + */ + int EDEADLK = 35; + + /** + * Indicates that a semaphore's operations should be undone at process shutdown. + */ + short SEM_UNDO = 0x1000; + + /** + * Indicates that one should not wait for the release of a semaphore if it is not currently available. + */ + short IPC_NOWAIT = 04000; + + /** + * Runs the {@code getpid} command. + * + * @return The command's return value. + * @throws LastErrorException If an error occurred. + */ + int getpid() throws LastErrorException; + + /** + * Runs the {@code getuid} command. + * + * @return The command's return value. + * @throws LastErrorException If an error occurred. + */ + int getuid() throws LastErrorException; + + /** + * Runs the {@code kill} command. + * + * @param processId The target process id. + * @param signal The signal to send. + * @return The command's return value. + * @throws LastErrorException If an error occurred. + */ + int kill(int processId, int signal) throws LastErrorException; + + /** + * Runs the {@code chmod} command. + * + * @param path The file path. + * @param mode The mode to set. + * @return The return code. + * @throws LastErrorException If an error occurred. + */ + int chmod(String path, int mode) throws LastErrorException; + + /** + * Runs the {@code chown} command. + * + * @param path The file path. + * @param userId The user id to set. + * @return The return code. + * @throws LastErrorException If an error occurred. + */ + int chown(String path, long userId) throws LastErrorException; + + /** + * Runs the {@code ftok} command. + * + * @param path The file path. + * @param id The id being used for creating the generated key. + * @return The generated key. + * @throws LastErrorException If an error occurred. + */ + int ftok(String path, int id) throws LastErrorException; + + /** + * Runs the {@code semget} command. + * + * @param key The key of the semaphore. + * @param count The initial count of the semaphore. + * @param flags The flags to set. + * @return The id of the semaphore. + * @throws LastErrorException If an error occurred. + */ + int semget(int key, int count, int flags) throws LastErrorException; + + /** + * Runs the {@code semop} command. + * + * @param id The id of the semaphore. + * @param operation The initial count of the semaphore. + * @param flags The flags to set. + * @return The return code. + * @throws LastErrorException If the operation was not successful. + */ + int semop(int id, SemaphoreOperation operation, int flags) throws LastErrorException; + + /** + * A structure to represent a semaphore operation for {@code semop}. + */ + class SemaphoreOperation extends Structure { + + /** + * The semaphore number. + */ + @SuppressWarnings("unused") + public short number; + + /** + * The operation to execute. + */ + public short operation; + + /** + * The flags being set for the operation. + */ + public short flags; + + @Override + protected List getFieldOrder() { + return Arrays.asList("number", "operation", "flags"); + } + } + } + + /** + * Represents a system that supports POSIX ownership. + */ + protected interface PosixOwnerProvider { + + /** + * Returns the user id of the owner of the supplied file. + * + * @param file The file for which to locate the owner. + * @return The owner id of the supplied file. + */ + int getOwnerIdOf(File file); + + /** + * An implementation of reading POSIX ownership using {@code stat}. + */ + class UsingStat implements PosixOwnerProvider { + + /** + * The maximum amount of attempts for checking the result of a foreign process. + */ + private final int attempts; + + /** + * The pause between two checks for another process to return. + */ + private final long pause; + + /** + * The time unit of the pause time. + */ + private final TimeUnit timeUnit; + + /** + * Creates a new provider where an owner is derived using the {@code stat} command. + * + * @param attempts The maximum amount of attempts for checking the result of a foreign process. + * @param pause The pause between two checks for another process to return. + * @param timeUnit The time unit of the pause time. + */ + public UsingStat(int attempts, long pause, TimeUnit timeUnit) { + this.attempts = attempts; + this.pause = pause; + this.timeUnit = timeUnit; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + try { + // The binding for 'stat' is very platform dependant. To avoid the complexity of binding the correct method, + // stat is called as a separate command. This is less efficient but more portable. + Process process = Runtime.getRuntime().exec(new String[]{"stat", + Platform.isMac() ? "-f" : "-c", + "%u", + file.getAbsolutePath()}); + int attempts = this.attempts; + String line = null; + do { + try { + if (process.exitValue() != 0) { + throw new IllegalStateException("Error while executing stat"); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); + try { + line = reader.readLine(); + } finally { + reader.close(); + } + break; + } catch (IllegalThreadStateException ignored) { + try { + Thread.sleep(timeUnit.toMillis(pause)); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(exception); + } + } + } while (--attempts > 0); + if (line == null) { + process.destroy(); + throw new IllegalStateException("Command for stat did not exit in time"); + } + return Integer.parseInt(line); + } catch (IOException exception) { + throw new IllegalStateException("Unable to execute stat command", exception); + } + } + } + + /** + * An implementation for reading a POSIX owner using {@code istat}. + */ + class UsingIStat implements PosixOwnerProvider { + + /** + * A pattern to represent the owner on the console output. + */ + private static final Pattern AIX_OWNER_PATTERN = Pattern.compile("Owner: (\\d+)\\("); + + /** + * The maximum amount of attempts for checking the result of a foreign process. + */ + private final int attempts; + + /** + * The pause between two checks for another process to return. + */ + private final long pause; + + /** + * The time unit of the pause time. + */ + private final TimeUnit timeUnit; + + /** + * Creates a new provider for reading a POSIX owner using {@code istat}. + * + * @param attempts The maximum amount of attempts for checking the result of a foreign process. + * @param pause The pause between two checks for another process to return. + * @param timeUnit The time unit of the pause time. + */ + public UsingIStat(int attempts, long pause, TimeUnit timeUnit) { + this.attempts = attempts; + this.pause = pause; + this.timeUnit = timeUnit; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + try { + Process process = Runtime.getRuntime().exec(new String[]{"istat", file.getAbsolutePath()}); + int attempts = this.attempts; + String lines = null; + do { + try { + if (process.exitValue() != 0) { + throw new IllegalStateException("Error while executing istat"); + } + StringBuilder output = new StringBuilder(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); + try { + String line; + while ((line = reader.readLine()) != null) { + output.append(line).append("\n"); + } + } finally { + reader.close(); + } + lines = output.toString(); + break; + } catch (IllegalThreadStateException ignored) { + try { + Thread.sleep(timeUnit.toMillis(pause)); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(exception); + } + } + } while (--attempts > 0); + if (lines == null) { + process.destroy(); + throw new IllegalStateException("Command for istat did not exit in time"); + } + Matcher matcher = AIX_OWNER_PATTERN.matcher(lines); + if (matcher.find()) { + return Integer.parseInt(matcher.group(1)); + } else { + throw new IllegalStateException("Unable to parse response from istat command: " + lines); + } + } catch (IOException exception) { + throw new IllegalStateException("Unable to execute istat command", exception); + } + } + } + } + } + + /** + * A connector implementation for a Windows environment using JNA. + */ + class ForJnaWindowsEnvironment implements Dispatcher { + + /** + * Indicates a missing user id what is not supported on Windows. + */ + private static final int NO_USER_ID = 0; + + /** + * The name of the creation mutex. + */ + private static final String CREATION_MUTEX_NAME = "j9shsemcreationMutex"; + + /** + * A library to use for interacting with Windows. + */ + private final WindowsLibrary library; + + /** + * Creates a new connector for a Windows environment using JNA. + */ + @SuppressWarnings("deprecation") + public ForJnaWindowsEnvironment() { + library = Native.loadLibrary("kernel32", WindowsLibrary.class, W32APIOptions.DEFAULT_OPTIONS); + } + + /** + * {@inheritDoc} + */ + public String getTemporaryFolder(String processId) { + WinDef.DWORD length = new WinDef.DWORD(WinDef.MAX_PATH); + char[] path = new char[length.intValue()]; + if (Kernel32.INSTANCE.GetTempPath(length, path).intValue() == 0) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return Native.toString(path); + } + + /** + * {@inheritDoc} + */ + public int pid() { + return Kernel32.INSTANCE.GetCurrentProcessId(); + } + + /** + * {@inheritDoc} + */ + public int userId() { + return NO_USER_ID; + } + + /** + * {@inheritDoc} + */ + public boolean isExistingProcess(int processId) { + WinNT.HANDLE handle = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION, false, processId); + if (handle == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + IntByReference exists = new IntByReference(); + if (!Kernel32.INSTANCE.GetExitCodeProcess(handle, exists)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return exists.getValue() == WinBase.STILL_ACTIVE; + } + + /** + * {@inheritDoc} + */ + public int getOwnerIdOf(File file) { + return NO_USER_ID; + } + + /** + * {@inheritDoc} + */ + public void setPermissions(File file, int permissions) { + /* do nothing */ + } + + /** + * {@inheritDoc} + */ + public void incrementSemaphore(File directory, String name, boolean global, int count) { + AttachmentHandle handle = openSemaphore(directory, name, global); + try { + while (count-- > 0) { + if (!library.ReleaseSemaphore(handle.getHandle(), 1, null)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } + } finally { + handle.close(); + } + } + + /** + * {@inheritDoc} + */ + public void decrementSemaphore(File directory, String name, boolean global, int count) { + AttachmentHandle handle = openSemaphore(directory, name, global); + try { + while (count-- > 0) { + int result = Kernel32.INSTANCE.WaitForSingleObject(handle.getHandle(), 0); + switch (result) { + case WinBase.WAIT_ABANDONED: + case WinBase.WAIT_OBJECT_0: + break; + case WinError.WAIT_TIMEOUT: + return; + default: + throw new Win32Exception(result); + } + } + } finally { + handle.close(); + } + } + + /** + * {@inheritDoc} + */ + public void chownFileToUser(File file, long userId) { + /* do nothing */ + } + + /** + * Opens a semaphore for signaling another process that an attachment is performed. + * + * @param directory The control directory. + * @param name The semaphore's name. + * @param global {@code true} if the semaphore is in the global namespace. + * @return A handle for signaling an attachment to the target process. + */ + private AttachmentHandle openSemaphore(File directory, String name, boolean global) { + WinNT.SECURITY_DESCRIPTOR securityDescriptor = new WinNT.SECURITY_DESCRIPTOR(64 * 1024); + try { + if (!Advapi32.INSTANCE.InitializeSecurityDescriptor(securityDescriptor, WinNT.SECURITY_DESCRIPTOR_REVISION)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + if (!Advapi32.INSTANCE.SetSecurityDescriptorDacl(securityDescriptor, true, null, true)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WindowsLibrary.SecurityAttributes securityAttributes = new WindowsLibrary.SecurityAttributes(); + try { + securityAttributes.length = new WinDef.DWORD(securityAttributes.size()); + securityAttributes.securityDescriptor = securityDescriptor.getPointer(); + WinNT.HANDLE mutex = library.CreateMutex(securityAttributes, false, CREATION_MUTEX_NAME); + if (mutex == null) { + int lastError = Kernel32.INSTANCE.GetLastError(); + if (lastError == WinError.ERROR_ALREADY_EXISTS) { + mutex = library.OpenMutex(WinNT.STANDARD_RIGHTS_REQUIRED | WinNT.SYNCHRONIZE | 0x0001, false, CREATION_MUTEX_NAME); + if (mutex == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } else { + throw new Win32Exception(lastError); + } + } + int result = Kernel32.INSTANCE.WaitForSingleObject(mutex, 2000); + switch (result) { + case WinBase.WAIT_FAILED: + case WinError.WAIT_TIMEOUT: + throw new Win32Exception(result); + default: + try { + String target = (global ? "Global\\" : "") + + (directory.getAbsolutePath() + '_' + name).replaceAll("[^a-zA-Z0-9_]", "") + + "_semaphore"; + WinNT.HANDLE parent = library.OpenSemaphoreW(WindowsLibrary.SEMAPHORE_ALL_ACCESS, false, target); + if (parent == null) { + parent = library.CreateSemaphoreW(null, 0, Integer.MAX_VALUE, target); + if (parent == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + WinNT.HANDLE child = library.CreateSemaphoreW(null, 0, Integer.MAX_VALUE, target + "_set0"); + if (child == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return new AttachmentHandle(parent, child); + } else { + WinNT.HANDLE child = library.OpenSemaphoreW(WindowsLibrary.SEMAPHORE_ALL_ACCESS, false, target + "_set0"); + if (child == null) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + return new AttachmentHandle(parent, child); + } + } finally { + if (!library.ReleaseMutex(mutex)) { + throw new Win32Exception(Native.getLastError()); + } + } + } + } finally { + securityAttributes = null; + } + } finally { + securityDescriptor = null; + } + } + + /** + * A library for interacting with Windows. + */ + protected interface WindowsLibrary extends StdCallLibrary { + + /** + * Indicates that a semaphore requires all access rights. + */ + int SEMAPHORE_ALL_ACCESS = 0x1F0003; + + /** + * Opens an existing semaphore. + * + * @param access The access rights. + * @param inheritHandle {@code true} if the handle is inherited. + * @param name The semaphore's name. + * @return The handle or {@code null} if the handle could not be created. + */ + + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE OpenSemaphoreW(int access, boolean inheritHandle, String name); + + /** + * Creates a new semaphore. + * + * @param securityAttributes The security attributes for the created semaphore. + * @param count The initial count for the semaphore. + * @param maximumCount The maximum count for the semaphore. + * @param name The semaphore's name. + * @return The handle or {@code null} if the handle could not be created. + */ + + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE CreateSemaphoreW(WinBase.SECURITY_ATTRIBUTES securityAttributes, + long count, + long maximumCount, + String name); + + /** + * Releases the semaphore. + * + * @param handle The semaphore's handle. + * @param count The amount with which to increase the semaphore. + * @param previousCount The previous count of the semaphore or {@code null}. + * @return {@code true} if the semaphore was successfully released. + */ + @SuppressWarnings("checkstyle:methodname") + boolean ReleaseSemaphore(WinNT.HANDLE handle, long count, Long previousCount); + + /** + * Create or opens a mutex. + * + * @param attributes The mutex's security attributes. + * @param owner {@code true} if the caller is supposed to be the initial owner. + * @param name The mutex name. + * @return The handle to the mutex or {@code null} if the mutex could not be created. + */ + + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE CreateMutex(SecurityAttributes attributes, boolean owner, String name); + + /** + * Opens an existing object. + * + * @param access The required access privileges. + * @param inherit {@code true} if the mutex should be inherited. + * @param name The mutex's name. + * @return The handle or {@code null} if the mutex could not be opened. + */ + @SuppressWarnings("checkstyle:methodname") + WinNT.HANDLE OpenMutex(int access, boolean inherit, String name); + + /** + * Releases the supplied mutex. + * + * @param handle The handle to the mutex. + * @return {@code true} if the handle was successfully released. + */ + @SuppressWarnings("checkstyle:methodname") + boolean ReleaseMutex(WinNT.HANDLE handle); + + /** + * A structure representing a mutex's security attributes. + */ + class SecurityAttributes extends Structure { + + /** + * The descriptor's length. + */ + + public WinDef.DWORD length; + + /** + * A pointer to the descriptor. + */ + + public Pointer securityDescriptor; + + /** + * {@code true} if the attributes are inherited. + */ + @SuppressWarnings("unused") + public boolean inherit; + + @Override + protected List getFieldOrder() { + return Arrays.asList("length", "securityDescriptor", "inherit"); + } + } + } + + /** + * A handle for an attachment which is represented by a pair of handles. + */ + protected static class AttachmentHandle implements Closeable { + + /** + * The parent handle. + */ + private final WinNT.HANDLE parent; + + /** + * The child handle. + */ + private final WinNT.HANDLE child; + + /** + * Creates a new attachment handle. + * + * @param parent The parent handle. + * @param child The child handle. + */ + protected AttachmentHandle(WinNT.HANDLE parent, WinNT.HANDLE child) { + this.parent = parent; + this.child = child; + } + + /** + * Returns the handle on which signals are to be sent. + * + * @return The handle on which signals are to be sent. + */ + protected WinNT.HANDLE getHandle() { + return child; + } + + /** + * {@inheritDoc} + */ + public void close() { + boolean closed; + try { + if (!Kernel32.INSTANCE.CloseHandle(child)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } finally { + closed = Kernel32.INSTANCE.CloseHandle(parent); + } + if (!closed) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/memshell-agent/memshell-agent-attacher/src/main/resources/win32-x86-64/attach_hotspot_windows.dll b/memshell-agent/memshell-agent-attacher/src/main/resources/win32-x86-64/attach_hotspot_windows.dll new file mode 100755 index 0000000000000000000000000000000000000000..6748a72a0a7c2cad795fa3d29b24bbd6ffafcf58 GIT binary patch literal 301843 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 KoEY>Sfd2!&?XZ&o literal 0 HcmV?d00001 diff --git a/memshell-party-bom/build.gradle b/memshell-party-bom/build.gradle index 52608189..676dfdb3 100644 --- a/memshell-party-bom/build.gradle +++ b/memshell-party-bom/build.gradle @@ -11,6 +11,9 @@ dependencies { api 'net.bytebuddy:byte-buddy:1.17.5' api 'org.ow2.asm:asm-commons:9.7.1' + api 'net.java.dev.jna:jna:5.17.0' + api 'net.java.dev.jna:jna-platform:5.17.0' + api 'javax.servlet:javax.servlet-api:3.0.1' api 'jakarta.servlet:jakarta.servlet-api:6.0.0' api 'javax.websocket:javax.websocket-api:1.1' diff --git a/memshell-party-common/src/main/java/com/reajason/javaweb/buddy/ClassRenameUtils.java b/memshell-party-common/src/main/java/com/reajason/javaweb/buddy/ClassRenameUtils.java new file mode 100644 index 00000000..fbb717a3 --- /dev/null +++ b/memshell-party-common/src/main/java/com/reajason/javaweb/buddy/ClassRenameUtils.java @@ -0,0 +1,56 @@ +package com.reajason.javaweb.buddy; + +import com.reajason.javaweb.asm.InnerClassDiscovery; +import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.ClassFileLocator; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.dynamic.scaffold.TypeValidation; +import net.bytebuddy.jar.asm.Opcodes; +import net.bytebuddy.pool.TypePool; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * @author ReaJason + * @since 2025/5/22 + */ +public class ClassRenameUtils { + + @SneakyThrows + public static Map renamePackage(Class clazz, String packageName) { + String originalClassName = clazz.getName(); + String originalPackageName = clazz.getPackage().getName(); + String newClassName = packageName + "." + clazz.getSimpleName(); + Map map = new HashMap<>(); + try (DynamicType.Unloaded make = new ByteBuddy() + .redefine(clazz) + .visit(new ClassRenameVisitorWrapper(originalClassName, newClassName)) + .visit(new TargetJreVersionVisitorWrapper(Opcodes.V1_6)) + .make()) { + map.put(newClassName, make.getBytes()); + } + Set innerClassNames = InnerClassDiscovery.findAllInnerClasses(clazz); + ClassFileLocator classFileLocator = ClassFileLocator.ForClassLoader.of(clazz.getClassLoader()); + TypePool typePool = TypePool.Default.of(classFileLocator); + for (String innerClassName : innerClassNames) { + TypeDescription innerTypeDesc = typePool.describe(innerClassName).resolve(); + String newInnerClassName = innerClassName.replace(originalClassName, newClassName); + DynamicType.Builder innerBuilder = new ByteBuddy() + .with(TypeValidation.DISABLED) + .redefine(innerTypeDesc, classFileLocator) + .visit(new ClassRenameVisitorWrapper(originalPackageName, packageName)) + .visit(new TargetJreVersionVisitorWrapper(Opcodes.V1_6)); + + try (DynamicType.Unloaded unloaded = innerBuilder.make()) { + for (Map.Entry entry : unloaded.getAllTypes().entrySet()) { + map.put(newInnerClassName, entry.getValue()); + } + } + } + return map; + } +} diff --git a/settings.gradle b/settings.gradle index 9f0dab69..a454deae 100644 --- a/settings.gradle +++ b/settings.gradle @@ -35,7 +35,7 @@ include 'vul:vul-springboot2-webflux' include 'vul:vul-springboot3-webflux' include 'memshell-agent' +include 'memshell-agent:memshell-agent-attacher' include 'memshell-agent:memshell-agent-asm' include 'memshell-agent:memshell-agent-javassist' -include 'memshell-agent:memshell-agent-bytebuddy' - +include 'memshell-agent:memshell-agent-bytebuddy' \ No newline at end of file diff --git a/web/src/i18n/en.json b/web/src/i18n/en.json index 0ce30a20..33ac2021 100644 --- a/web/src/i18n/en.json +++ b/web/src/i18n/en.json @@ -65,7 +65,9 @@ "ScriptEngine": "ScriptEngine", "SpEL": "SpEL", "Velocity": "Velocity", - "XxlJob": "XXL-JOB Executor" + "XxlJob": "XXL-JOB Executor", + "AgentJarWithJDKAttacher": "AgentJarWithJDKAttacher", + "AgentJarWithJREAttacher": "AgentJarWithJREAttacher" }, "title": "Package Method" }, diff --git a/web/src/i18n/zh-CN.json b/web/src/i18n/zh-CN.json index 20b40022..d4223291 100644 --- a/web/src/i18n/zh-CN.json +++ b/web/src/i18n/zh-CN.json @@ -65,7 +65,9 @@ "ScriptEngine": "内置脚本引擎", "SpEL": "SpEL 表达式", "Velocity": "Velocity", - "XxlJob": "XXL-JOB Executor" + "XxlJob": "XXL-JOB Executor", + "AgentJarWithJDKAttacher": "AgentJarWithJDKAttacher", + "AgentJarWithJREAttacher": "AgentJarWithJREAttacher" }, "title": "打包方式" },