137 lines
5.9 KiB
Diff
137 lines
5.9 KiB
Diff
Date: Tue, 30 May 2023 03:43:28 +0000
|
|
Subject: [PATCH 02/59] 8179498: attach in linux should be relative to
|
|
/proc/pid/root and namespace aware
|
|
Bug url: https://bugs.openjdk.org/browse/JDK-8179498
|
|
---
|
|
.../sun/tools/attach/LinuxVirtualMachine.java | 70 ++++++++++++++++---
|
|
1 file changed, 62 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/jdk/src/solaris/classes/sun/tools/attach/LinuxVirtualMachine.java b/jdk/src/solaris/classes/sun/tools/attach/LinuxVirtualMachine.java
|
|
index 20fdb5c0d..cc2ac0df2 100644
|
|
--- a/jdk/src/solaris/classes/sun/tools/attach/LinuxVirtualMachine.java
|
|
+++ b/jdk/src/solaris/classes/sun/tools/attach/LinuxVirtualMachine.java
|
|
@@ -32,6 +32,10 @@ import com.sun.tools.attach.spi.AttachProvider;
|
|
import java.io.InputStream;
|
|
import java.io.IOException;
|
|
import java.io.File;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.nio.file.Path;
|
|
+import java.nio.file.Paths;
|
|
+import java.nio.file.Files;
|
|
|
|
/*
|
|
* Linux implementation of HotSpotVirtualMachine
|
|
@@ -66,12 +70,15 @@ public class LinuxVirtualMachine extends HotSpotVirtualMachine {
|
|
throw new AttachNotSupportedException("Invalid process identifier");
|
|
}
|
|
|
|
+ // Try to resolve to the "inner most" pid namespace
|
|
+ int ns_pid = getNamespacePid(pid);
|
|
+
|
|
// Find the socket file. If not found then we attempt to start the
|
|
// attach mechanism in the target VM by sending it a QUIT signal.
|
|
// Then we attempt to find the socket file again.
|
|
- path = findSocketFile(pid);
|
|
+ path = findSocketFile(pid, ns_pid);
|
|
if (path == null) {
|
|
- File f = createAttachFile(pid);
|
|
+ File f = createAttachFile(pid, ns_pid);
|
|
try {
|
|
// On LinuxThreads each thread is a process and we don't have the
|
|
// pid of the VMThread which has SIGQUIT unblocked. To workaround
|
|
@@ -99,7 +106,7 @@ public class LinuxVirtualMachine extends HotSpotVirtualMachine {
|
|
try {
|
|
Thread.sleep(delay);
|
|
} catch (InterruptedException x) { }
|
|
- path = findSocketFile(pid);
|
|
+ path = findSocketFile(pid, ns_pid);
|
|
i++;
|
|
} while (i <= retries && path == null);
|
|
if (path == null) {
|
|
@@ -272,8 +279,12 @@ public class LinuxVirtualMachine extends HotSpotVirtualMachine {
|
|
}
|
|
|
|
// Return the socket file for the given process.
|
|
- private String findSocketFile(int pid) {
|
|
- File f = new File(tmpdir, ".java_pid" + pid);
|
|
+ private String findSocketFile(int pid, int ns_pid) {
|
|
+ // A process may not exist in the same mount namespace as the caller.
|
|
+ // Instead, attach relative to the target root filesystem as exposed by
|
|
+ // procfs regardless of namespaces.
|
|
+ String root = "/proc/" + pid + "/root/" + tmpdir;
|
|
+ File f = new File(root, ".java_pid" + ns_pid);
|
|
if (!f.exists()) {
|
|
return null;
|
|
}
|
|
@@ -284,14 +295,23 @@ public class LinuxVirtualMachine extends HotSpotVirtualMachine {
|
|
// if not already started. The client creates a .attach_pid<pid> file in the
|
|
// target VM's working directory (or temp directory), and the SIGQUIT handler
|
|
// checks for the file.
|
|
- private File createAttachFile(int pid) throws IOException {
|
|
- String fn = ".attach_pid" + pid;
|
|
+ private File createAttachFile(int pid, int ns_pid) throws IOException {
|
|
+ String fn = ".attach_pid" + ns_pid;
|
|
String path = "/proc/" + pid + "/cwd/" + fn;
|
|
File f = new File(path);
|
|
try {
|
|
f.createNewFile();
|
|
} catch (IOException x) {
|
|
- f = new File(tmpdir, fn);
|
|
+ String root;
|
|
+ if (pid != ns_pid) {
|
|
+ // A process may not exist in the same mount namespace as the caller.
|
|
+ // Instead, attach relative to the target root filesystem as exposed by
|
|
+ // procfs regardless of namespaces.
|
|
+ root = "/proc/" + pid + "/root/" + tmpdir;
|
|
+ } else {
|
|
+ root = tmpdir;
|
|
+ }
|
|
+ f = new File(root, fn);
|
|
f.createNewFile();
|
|
}
|
|
return f;
|
|
@@ -317,6 +337,40 @@ public class LinuxVirtualMachine extends HotSpotVirtualMachine {
|
|
}
|
|
|
|
|
|
+ // Return the inner most namespaced PID if there is one,
|
|
+ // otherwise return the original PID.
|
|
+ private int getNamespacePid(int pid) throws AttachNotSupportedException, IOException {
|
|
+ // Assuming a real procfs sits beneath, reading this doesn't block
|
|
+ // nor will it consume a lot of memory.
|
|
+ String statusFile = "/proc/" + pid + "/status";
|
|
+ File f = new File(statusFile);
|
|
+ if (!f.exists()) {
|
|
+ return pid; // Likely a bad pid, but this is properly handled later.
|
|
+ }
|
|
+
|
|
+ Path statusPath = Paths.get(statusFile);
|
|
+
|
|
+ try {
|
|
+ for (String line : Files.readAllLines(statusPath, StandardCharsets.UTF_8)) {
|
|
+ String[] parts = line.split(":");
|
|
+ if (parts.length == 2 && parts[0].trim().equals("NSpid")) {
|
|
+ parts = parts[1].trim().split("\\s+");
|
|
+ // The last entry represents the PID the JVM "thinks" it is.
|
|
+ // Even in non-namespaced pids these entries should be
|
|
+ // valid. You could refer to it as the inner most pid.
|
|
+ int ns_pid = Integer.parseInt(parts[parts.length - 1]);
|
|
+ return ns_pid;
|
|
+ }
|
|
+ }
|
|
+ // Old kernels may not have NSpid field (i.e. 3.10).
|
|
+ // Fallback to original pid in the event we cannot deduce.
|
|
+ return pid;
|
|
+ } catch (NumberFormatException | IOException x) {
|
|
+ throw new AttachNotSupportedException("Unable to parse namespace");
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
//-- native methods
|
|
|
|
static native boolean isLinuxThreads();
|
|
--
|
|
2.22.0
|
|
|