How to use Java to track JVM file system access

Use a custom security manager as a low overhead alternative to native tracers.

Native tracing tools are always the first choice for tracking file system access to Java applications. On Windows, use Process Monitor to track I / O. On Linux, use strace. Other platforms also provide similar functions.

By tracing directly in Java, you can address environmental constraints. For example, when the cap is missing_ SYS_ strace is not available in the container of ptrace function, and the container host is not always accessible. In addition, the potential lighter weight tracking mechanism can be easily tracked in the production environment.

To follow the Java route, you can extend to implement your own security manager Java lang.SecurityManager. This class provides checkRead, checkWrite and checkDelete methods. Once the code attempts to access them, they will be called.

An example implementation:

public class TraceSecurityManager extends SecurityManager {
  public void checkRead(String file) {
    System.out.println("Read: " + file);
    super.checkRead(file);
  }
  public void checkRead(String file, Object context) {
    System.out.println("Read: " + file);
    super.checkRead(file, context);
  }
  public void checkWrite(String file) {
    System.out.println("Write: " + file);
    super.checkWrite(file);
  }
  public void checkDelete(String file) {
    System.out.println("Delete: " + file);
    super.checkDelete(file);
  }
}

To test the sample, we use the Java compiler as the test object. To enable the trace security manager, we set the appropriate system properties and execute the command test. Using a valid Java source file Java:

$ java -Djava.security.manager=TraceSecurityManager com.sun.tools.javac.Main Test.java
Read: /home/user/com/sun/tools/javac/resources/spi/compilerProvider.class
Read: /home/user/com/sun/tools/javac/resources/compiler_en.properties
Read: /home/user/com/sun/tools/javac/resources/compiler_en_US.properties
Exception in thread "main" java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getenv.JDK_JAVAC_OPTIONS")
        at java.base/java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
        at java.base/java.security.AccessController.checkPermission(AccessController.java:897)
        at java.base/java.lang.SecurityManager.checkPermission(SecurityManager.java:322)
        at java.base/java.lang.System.getenv(System.java:999)
        at jdk.compiler/com.sun.tools.javac.main.CommandLine.appendParsedEnvVariables(CommandLine.java:252)
        at jdk.compiler/com.sun.tools.javac.main.CommandLine.parse(CommandLine.java:99)
        at jdk.compiler/com.sun.tools.javac.main.CommandLine.parse(CommandLine.java:123)
        at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:215)
        at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:170)
        at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:57)
        at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:43)

Tracking is effective. We can even see class loading attempts. However, javac failed because of a lack of permissions. The reason is that after installing the security manager through the system attribute, the default Java security policy is active and the required permissions are not granted. To solve this problem, you can provide a minimum of custom policies, or you can override this method with an empty implementation of checkPermission. In this case, I chose the minimum strategy:

grant {
  permission java.security.AllPermission "", "";
};

With appropriate policies, we can retest:

$ java -Djava.security.policy=test.policy -Djava.security.manager=TraceSecurityManager com.sun.tools.javac.Main Test.java
Read: /home/user/com/sun/tools/javac/resources/spi/compilerProvider.class
Read: /home/user/com/sun/tools/javac/resources/compiler_en.properties
Read: /home/user/com/sun/tools/javac/resources/compiler_en_US.properties
Read: Test.java
Read: Test.java
Read: /usr/lib/jvm/java-11-openjdk-11.0.10.0.9-1.el7_9.x86_64/lib/modules
Read: /usr/lib/jvm/java-11-openjdk-11.0.10.0.9-1.el7_9.x86_64/lib/modules
Read: /usr/lib/jvm/java-11-openjdk-11.0.10.0.9-1.el7_9.x86_64/lib/jfxrt.jar
Read: /home/user/META-INF/services/java.nio.file.spi.FileSystemProvider
Read: /usr/lib/jvm/java-11-openjdk-11.0.10.0.9-1.el7_9.x86_64/lib/modules
Read: /usr/lib/jvm/java-11-openjdk-11.0.10.0.9-1.el7_9.x86_64/lib/modules
Read: Test.java
Read: /home/user/Test.java
Read: ./.bash_logout
Read: /home/user/.bash_logout
Read: ./.bash_profile
Read: /home/user/.bash_profile
Read: ./.bashrc
Read: /home/user/.bashrc
[...]
Read: /home/user/com/sun/tools/javac/resources/spi/ctProvider.class
Read: /home/user/com/sun/tools/javac/resources/ct_en.properties
Read: /home/user/com/sun/tools/javac/resources/ct_en_US.properties
Read: /home/user/TraceSecurityManager.class
Read: /home/user/Test.class
Read: /home/user
Write: /home/user/Test.class
Read: Test.java

This time, we have obtained the complete javac file system access trace. You can also enable the security manager at run time, which is useful if you cannot control the Java command line for some reason:

System.setSecurityManager(new TraceSecurityManager());

In this particular case, there is no need to customize the policy because the default policy is not active.
Free collection group of learning materials: 3907814
Using security manager to track file system access is certainly not the best choice, because there may be a lack of details related to the debugging scheme, but this is a good compromise if you have no other choice and need to complete the work or the cost is small. Tracking is required.

Original link: https://segmentfault.com/a/1190000039858551

Keywords: Java Linux jvm Programmer Operating System

Added by Tokunbo on Fri, 04 Mar 2022 05:07:34 +0200