Skip to content

Fix java attach - #11848

Open
yinjiping wants to merge 1 commit into
v6.6from
fix_java_attach
Open

Fix java attach#11848
yinjiping wants to merge 1 commit into
v6.6from
fix_java_attach

Conversation

@yinjiping

@yinjiping yinjiping commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Add a shared java_attach_preflight() gate used by both the Java symbol collector and deepflow-jattach before socket creation, Agent SO copying, or injection.

The preflight validates process liveness and zombie state, identifies HotSpot/OpenJ9 from the target maps, executes the target JVM's -version in the correct Host/POD namespace, and rechecks PID start time and executable path to detect reuse.

For HotSpot Java 8, distinguish the 8u0-351 range missing JDK-8173361 from the 8u352-381 range missing the 8u-specific JDK-8305165 follow-up; keep 8u382 as the complete-fix attach baseline and log the two skip reasons separately. Also reject DisableAttachMechanism and unreadable attach options, harden command/output buffers, and add the local release-check script plus investigation and operator documentation.

This PR is for:

  • agent

Affected branches

  • v6.6

5.1 JVM 缺陷复现测试

测试项 结果
8u342 无 Agent 基线 PASS,30 秒正常退出
8u342 + Honest Profiler,类加载/卸载压力 SIGSEGV,约 26 秒
8u342 + DeepFlow,类加载/卸载压力 SIGSEGV,约 16–17 秒
8u342 + DeepFlow,重复 attach 60 次 PASS,60/60 成功
8u342 + DeepFlow,socket 背压 PASS,300 秒正常退出
8u382 + Honest Profiler,同等压力 300 秒 PASS,无 SIGSEGV
8u382 + DeepFlow,同等压力 300 秒 PASS,无 SIGSEGV

5.2 Attach 预检测试

测试项 结果
C 代码编译 PASS
git diff --check PASS
HotSpot 8u342 版本识别 PASS,跳过 attach
HotSpot 8u382 版本识别 PASS,通过版本门禁
HotSpot 8u412 版本识别 PASS,允许继续检查
POD 中 HotSpot 8u212 PASS,正确跳过 attach
Host 与目标同 namespace PASS,不切换 namespace
Host 与目标跨 namespace PASS,正确进入并恢复 namespace
极简容器缺少 shell/env/timeout PASS,使用宿主机回退路径
DisableAttachMechanism 参数 PASS,正确跳过
PID 被复用或 exe 变化 PASS,正确跳过
image

@yinjiping
yinjiping force-pushed the fix_java_attach branch 4 times, most recently from 8b7a284 to f289555 Compare August 11, 2026 04:13
@yinjiping
yinjiping marked this pull request as draft August 11, 2026 04:14
Add a shared java_attach_preflight() gate used by both the Java symbol collector and deepflow-jattach before socket creation, Agent SO copying, or injection.

The preflight validates process liveness and zombie state, identifies HotSpot/OpenJ9 from the target maps, executes the target JVM's -version in the correct Host/POD namespace, and rechecks PID start time and executable path to detect reuse.

For HotSpot Java 8, distinguish the 8u0-351 range missing JDK-8173361 from the 8u352-381 range missing the 8u-specific JDK-8305165 follow-up; keep 8u382 as the complete-fix attach baseline and log the two skip reasons separately. Also reject DisableAttachMechanism and unreadable attach options, harden command/output buffers, and add the local release-check script plus investigation and operator documentation.
@kylewanginchina

Copy link
Copy Markdown
Contributor

@claude review一下当前PR中的代码修改

@claude

claude Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kylewanginchina's task in 12m 18s —— View job


Todo

  • 阅读仓库说明和 PR 上下文
  • 审查代码改动的正确性与安全性
  • 汇总结论并更新评论
  • 复核额外的 namespace 路径解析问题并补充 review

Review

整体思路没问题:java_attach_preflight() 的接入点放在 socket 创建、SO 拷贝和 jattach 之前,这个方向是对的。不过我复核后,当前改动里有 3 个需要修的 correctness 问题。

  1. agent/src/ebpf/user/profile/java/jvm_symbol_collect.c:491-529agent/src/ebpf/user/profile/java/jvm_symbol_collect.c:670-682
    新增的 java_preflight_proc_contains() 现在是对 /proc/<pid>/cmdline/proc/<pid>/environ 做原始子串匹配。这样只要业务参数或某个无关环境变量里恰好包含 -XX:+DisableAttachMechanism 这段文本,就会被误判成 JVM 显式禁用了 attach,然后在预检里永久跳过该进程的符号采集。比如应用自己接受一个 --note=-XX:+DisableAttachMechanism 参数时就会中招。这里需要按“真实 JVM option 边界”匹配,而不是任意字节子串。
    Fix this →

  2. agent/src/ebpf/user/profile/java/jvm_symbol_collect.c:419-470
    跨 mount namespace 的 -version 探测实际上没有进入目标 rootfs。这里虽然调用了 df_enter_ns(..., "pid") / df_enter_ns(..., "mnt"),但后面执行的仍然是绝对路径 /usr/bin/env/bin/envexe_pathsetns() 进入 mount namespace 并不会自动把当前进程的 root/cwd 切到目标容器根目录,所以这些绝对路径仍会从 agent/host 的根文件系统解析。fallback 路径里的 nsenter --target ... --mount --pid -- %s -version 也同样没有带 --root(或等价做法),问题一样存在。结果就是:对 rootfs 不同的容器,预检可能会错误地执行宿主机 Java,进而按宿主机版本放行一个本该被拒绝的目标 JVM;反过来也可能因为找不到目标二进制而错误跳过本来可采集的进程。
    Fix this →

  3. agent/src/ebpf/user/utils.c:1151-1162
    df_enter_ns() 在打开目标 namespace fd 成功后,如果随后打开 /proc/self/ns/<type> 失败,会直接 return -1,但没有关闭前面已经打开的 newns。这个错误路径现在会泄漏 fd;如果宿主机处于 fd 紧张或这个路径被重复触发,后续 attach / namespace 切换都会被拖垮。
    Fix this →

Summary

  • 我没有在这个评论里直接改代码,只做了 review。
  • 目前我确认了 3 个需要修的 correctness 问题;其中第 2 个会直接影响跨容器场景下版本门禁的真实性,优先级最高。

@yinjiping
yinjiping marked this pull request as ready for review August 11, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants