这是一个将 Java agent 注入到正在运行的 JVM 进程中的工具。该 agent 会尝试修补所有已加载的 org.apache.logging.log4j.core.lookup.JndiLookup 实例的 lookup() 方法,使其无条件返回字符串 "Patched JndiLookup::lookup()"。该工具旨在解决 CVE-2021-44228 中披露的 Log4j 远程代码执行漏洞,而无需重启 Java 进程。该工具同样可用于解决 CVE-2021-45046。
目前仅在 Linux 上使用 JDK 8、11、15 和 17 进行过测试!
要在 Linux、mac 和 Windows 子系统(WSL)上构建
./gradlew build
要在 Windows 上构建
.\gradlew.bat build
根据你构建的平台,将生成 build/libs/Log4jHotPatch.jar。
要使用 Maven 构建,请执行
mvn clean package
这将生成 target/Log4jHotPatch.jar。
JDK 8
java -cp <java-home>/lib/tools.jar:Log4jHotPatch.jar Log4jHotPatch <java-pid>
JDK 11 及更高版本
java -jar Log4jHotPatch.jar <java-pid>
只需将 agent 添加到你的 java 命令行中,如下所示:
java -classpath <class-path> -javaagent:Log4jHotPatch.jar <main-class> <arguments>
这里有一组可以在 Gradle 或 Maven 之外运行的测试。
build-tools/bin/run_tests.sh Log4jHotPatch.jar <JDK_ROOT>
如果你遇到如下错误:
Exception in thread "main" com.sun.tools.attach.AttachNotSupportedException: The VM does not support the attach mechanism
at jdk.attach/sun.tools.attach.HotSpotAttachProvider.testAttachable(HotSpotAttachProvider.java:153)
at jdk.attach/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:56)
at jdk.attach/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:207)
at Log4jHotPatch.loadInstrumentationAgent(Log4jHotPatch.java:115)
at Log4jHotPatch.main(Log4jHotPatch.java:139)
这意味着你的 JVM 拒绝了任何形式的附加(attach)操作,因为它是以 -XX:+DisableAttachMechanism 参数运行的。
如果你遇到如下错误:
com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:106)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208)
at Log4jHotPatch.loadInstrumentationAgent(Log4jHotPatch.java:182)
at Log4jHotPatch.main(Log4jHotPatch.java:259)
这意味着你使用的用户(包括 root)与目标 JVM 的运行用户不同。JDK 8 无法以 root 用户执行修补操作(并会在目标 JVM 中触发线程转储,这无害)。在 JDK 11 中,以 root 进程修补非 root 进程则完全可以正常工作。
如果你在目标进程中遇到如下错误:
Exception in thread "Attach Listener" java.lang.ExceptionInInitializerError
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:411)
Caused by: java.security.AccessControlException: access denied ("java.util.PropertyPermission" "log4jFixerAgentVersion" "write")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:886)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.System.setProperty(System.java:794)
at Log4jHotPatch.<clinit>(Log4jHotPatch.java:66)
这意味着目标进程安装了安全管理器(Security Manager)。请在目标进程中查找以下命令行选项:
-Djava.security.policy=/local/apollo/.../apollo-security.policy
如果遇到此错误,请确保你使用的是最新版本的工具
重要提示: 如果你曾以错误的用户身份尝试修补,则在再次尝试之前可能需要删除 .attach_pid<pid> 文件(位于 /tmp 和/或 VM 进程的工作目录中)。这些文件需要具有正确的所有权,附加(attach)操作才能成功。