如何使用Java跟踪JVM文件系统访问

Posted Java攻城师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用Java跟踪JVM文件系统访问相关的知识,希望对你有一定的参考价值。

使用自定义安全管理器作为本机跟踪程序的低开销替代方法。

对于跟踪Java应用程序的文件系统访问,本机跟踪工具始终是首选。在Windows上,使用Process Monitor跟踪I / O。在Linux上,使用strace。其他平台也提供类似的功能。

通过直接在Java中进行跟踪,您可以解决环境限制。例如,在缺少该CAP_SYS_PTRACE功能的容器中strace不可用,并且容器主机并非始终可访问。此外,潜在的更轻量的跟踪机制可方便地在生产环境中进行跟踪。

要走Java路线,您可以通过扩展来实现自己的安全管理器java.lang.SecurityManager。此类提供了checkRead,checkWrite和checkDelete方法,一旦代码尝试进行相应的访问,它们就会被调用。

一个示例实现:

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);
  }
}

为了测试样本,我们使用Java编译器作为测试对象。为了启用跟踪安全管理器,我们设置适当的系统属性,并使用有效的Java源文件执行命令Test.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)

跟踪实现有效。我们甚至可以看到类加载尝试。但是,javac失败,因为缺少权限。原因是,通过system属性安装安全管理器后,默认的Java安全策略处于活动状态,并且未授予所需的权限。要解决此问题,您可以提供最少的自定义策略,也可以checkPermission使用空的实现覆盖该方法。在这种情况下,我选择了最小策略:

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

有了适当的政策,我们可以重新测试:

$ 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

这次,我们获得了完整的javac文件系统访问跟踪。还可以在运行时启用安全性管理器,如果由于某种原因而无法控制Java命令行,这将非常有用:

System.setSecurityManager(new TraceSecurityManager());

在这种特定情况下,由于默认策略未处于活动状态,因此不需要自定义策略。
学习资料免费领取群:3907814
使用安全管理器来跟踪文件系统访问肯定不是最好的选择,因为可能缺少与调试方案相关的详细信息,但是如果您没有其他选择并且需要完成工作或开销很小,则这是一个很好的折衷方案。跟踪是必需的。

以上是关于如何使用Java跟踪JVM文件系统访问的主要内容,如果未能解决你的问题,请参考以下文章

如何访问jvm默认KeyStore?

从JVM的角度看JAVA代码--代码优化

自定义 JVM 语言:创建可行的堆栈跟踪?

JVM中常用堆栈跟踪内建指令

JVM(java 虚拟机)

深入理解JVM(③)Java的模块化