Categories
程式開發

RASP研发踩坑之attach失败


1.创建一个简单的 Java Agent

主动发起 attach 代码

import com.sun.tools.attach.*;

import java.io.IOException;

public class Main {
public static void main(String[] args) {
VirtualMachine vm = null;
try {
vm = VirtualMachine.attach("50447");
// 指定Java Agent的jar包路径
String agentPath = "../agent-1.0-SNAPSHOT-jar-with-dependencies.jar";
vm.loadAgent(agentPath, "agent test");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
vm.detach();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

一个简单的Java Agent 代码

Java agent 包的代码: https://github.com/xl1605368195/SimpleAgent.git

下载下来之后执行 mvn clean package 打包

2.踩坑 /tmp目录下的 .java_pid 文件被删除之后,attach到目标Java 进程错误

1.问题背景

我们在一批次的主机上开启了RASP,灰度完成之后,发现其中有58台主机执行attach错误

Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

2.初步思路

看上面的告警信息是目标 JVM 进程未响应 socket 连接,没有详细调查问题之前,我对此问题的初步想法(问题出现在哪里)

1.attach失败异常在 rasp多个版本中都有出现,不仅仅在 rasp2.8.0,初步排查问题不在rasp2.8.0存在(也就是说不是2.8.0新特性导致 attach 失败)

2.attach 失败的主机总是出现在一些固定主机上(这点可以排除 rasp attach机制的问题,attach代码没毛病),可能与主机上的Java 服务有关

3.接上面的第2点,attach本质是与jvm进行socket通信,attach失败,可能是jvm无法响应到这个socket连接。(问题的突破点)

3.我想到了哪些可能会影响 attach?

1.jvm处于过载状态是否会响应socket通信;

2.使用 attach机制的工具还有 jmap,jstack,如果 rasp 不能 attach,这些工具应该也是不能 attach 成功的。

4.申请权限登陆目标主机,手动拉起 rasp

2020-04-10 11:49:51.478 Rasp-Server版本:2.8.0 开始尝试注入到进程pid:542 watcher.go:390:Run
2020-04-10 11:49:56.490 Rasp-Server版本:2.8.0 attach出错 watcher.go:350:Exec
2020-04-10 11:49:56.490 Rasp-Server版本:2.8.0 watcher运行失败:exit status 2 sandbox_process.go:130:func

attach 失败!!

查看 Java 服务的 CPU 和内存

PID USER %CPU %MEM COMMAND

542 sankuai 0.3 23.1 java

Java服务内存和 CPU 都属于正常状态,初步排除 “1.jvm处于过载状态是否会响应socket通信”这个原因

5. 我尝试 使用 jstack -l 542 ,也失

[[email protected] ~]$ jstack 542
542: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

6. 但是Java进程重启之后,jstack 工具可以正常使用,rasp 也正常attach

7. 再次熟悉 attach机制

链接博客的重点:.attach_pid 与 .java_pid 分别被主动发起attach的进程(这里是rasp-server)和目标JVM进程创建, 并且JVM 创建 .java_pid 由 Djava.io.tmp 路径指定默认为 /tmp

http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/17870c6c1d4e

8. 删除 .java_pid 再次使用 jstack -l

[[email protected] tmp]$ jstack -l 68546
68546: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

9.猜测

首次 attach到目标 JVM 后,.java_pid 文件被创建在 /tmp 下,/tmp 目录被系统清理之后,.java_pid被删除了,再次attach (jstack或者 rasp-server重启开启注入)都会失败

10.验证

在开启进程出错的主机上,查询 Java 进程看 Djava.io.tmp=dir的目录下是否有 .java_pid文件

验证主机:set-yp-logan-open-web-test01

结果:没有 .java_pid 文件,符合预期。

11. 出错复现

第一步,启动 java 进程 ,使用jstack 或者 rasp 执行 attach

第二步,删除/tmp 下的 .java_pid

第二步,开启rasp 执行注入,出现attach进程出错。

12. 问题的解决思路

策略1:对于无法开启attach 的 Java 进程只能等待 Java 进程重启之后,生成新的 .java_pid

策略2:Djava.io.tmp 建议指定到 Java进程的运行目录,因为默认的/tmp 容易被清除掉

参考连接:

https://stackoverflow.com/questions/5769877/attachnotsupportedexception-due-to-missing-java-pid-file-in-attach-api

踩坑2 attach时携带的字符串长度有限制

问题

一般我们会在 attach 时给JVM 传递一些字符串信息,来辅助 Agent 的初始化

vm.loadAgent(agentPath, "agent test");

随着,RASP各种需求的增加,需要给 Agent 传输的字符串变的越来越多

agentTomcatRule=(DP Server 6|Apache Tomcat/6|Apache Tomcat/7|Apache Tomcat/8|Apache Tomcat/9|6|7|8|9)..*, classTransLimit=12, confVersion=2.8.0.4_20200512_2, raspHome=/opt/meituan/apps/direwolf/plugin/1004, hookFileWrite=false, pid=30496, hookFileUpload=false, rsDegradeLimit=2, recordTimeSample=50000, offlineLogSize=50, bootClassPath=/opt/meituan/apps/direwolf/plugin/1004/lib/guava-20.0.0.jar:/opt/meituan/apps/direwolf/plugin/1004/lib/mygson-1.0.0.jar, hookFileUploadContent=false, maxFailSize=1, closeWaitTimeInSeconds=6, rsLimitDiskFree=10, agentJettyRule=(8.1|8.2|9.2|9.3|9.4)..*, debug=true, queueSize=500, enableHttpPara=true, rsLimitCpuPid=40, agentJdkRule=1.(?:7|8)..*, dumpDir=/tmp/rasp_dump, serverPID=30513, recordTimeThreshold=5, rsLimitMemPid=90, dumpClasses=false, rsCheckEnable=true, rsLimitMemTotal=95, enableHttpReq=true, rsCircuitBreakLimit=129600, agentLogLevel=DEBUG

经过测试,最大可以携带的字符串长度为:938

超过938时,报错如下:

java.io.IOException: Premature EOF
at sun.tools.attach.HotSpotVirtualMachine.readInt(HotSpotVirtualMachine.java:292)
at sun.tools.attach.BsdVirtualMachine.execute(BsdVirtualMachine.java:183)
at sun.tools.attach.HotSpotVirtualMachine.loadAgentLibrary(HotSpotVirtualMachine.java:58)
at sun.tools.attach.HotSpotVirtualMachine.loadAgentLibrary(HotSpotVirtualMachine.java:79)
at sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java:103)
at Main.main(Main.java:23)

疑问

attach 携带的字符串没有超过 String类型的最大长度,为什么会报错呢?我想去看下Java源码?

未完….待续