本文解答了有关在 .NET 中收集转储的常见问题。
为什么在 Linux 上收集转储会失败?
为实现转储收集,.NET 进程会生成一个名为 createdump 的子进程。 此子进程使用 Linux API ptrace() 并从 /proc 文件系统读取,以访问写入转储文件的线程和内存数据。 尽管许多 Linux 发行版上的默认安全设置允许使用 API,但有时不太常见的安全配置会拒绝访问。 你可能会看到 createdump 进程将如下输出写入被转储应用程序的控制台:
[createdump] The process or container does not have permissions or access: open(/proc/1234/mem) FAILED Permission denied (13)
访问可能被拒绝的一个原因是安全沙盒使用 seccomp BPF 筛选器拦截了调用。 对于使用开放容器计划技术在容器中运行的应用程序,配置文件 seccomp 必须允许调用 ptrace。 例如,Docker 在后台使用 containerd 作为容器运行时。 初始化时,它会指定默认的 seccomp 配置文件。仅当容器主机的内核版本高于 4.8,或已为容器指定 CAP_SYS_PTRACE 功能时,该配置文件才允许 ptrace。
如果未截获调用,则内核会执行各种内置访问检查。 ptrace() 的文档在末尾包括一个详细说明,标题为“Ptrace 访问模式检查”,描述这种检查是如何进行的。 访问 /proc 文件系统时也会使用同一 ptrace 访问模式检查的变体。 下面是执行的安全检查的简要总结,以及可能拒绝访问的位置:
- 调用进程需要具有与目标进程相同的用户 ID,或者调用进程需要具有CAP_SYS_PTRACE。 如果这两个都不是真的,则拒绝访问。 由于 .NET 运行时在启动 createdump 时不会执行任何作来更改用户帐户,因此用户 ID 应匹配,此步骤应成功。
- 如果 createdump 没有CAP_SYS_PTRACE(默认情况下不),则需要将要转储的目标进程标记为“可转储”。 默认情况下,Linux 上的大多数进程都是可转储的,但可以通过使用 PR_SET_DUMPABLE 选项调用 prctl() 来更改此设置。 使用 setcap 工具向进程添加功能也可能导致该进程不再可转储。 有关 dumpable 设置及其禁用原因的详细说明,请参阅 Linux 文档。
- 枚举所有已启用的 Linux 安全模块 (LSM),每个模块都必须批准访问。 遗憾的是,如果 LSM 拒绝访问,则没有统一的 Linux 报告机制来知道哪一个负责。 相反,你需要确定哪些功能已在你的系统上启用,然后对每个功能进行单独调查。 可以通过运行
cat /sys/kernel/security/lsm来确定哪些 LSM 处于活动状态。 尽管任何 LSM 都可能是原因,但 Yama、SELinux 和 AppArmor 通常是相关模块。
AppArmor 和 SELinux 都具有丰富的配置和报告机制,因此,如果需要了解如何使用它们,最好查看每个项目自己的文档。 Yama 只有一个配置选项,可以通过运行以下命令来查看:
cat /proc/sys/kernel/yama/ptrace_scope
此命令输出一个数字,指示当前的 Yama ptrace 安全策略:
- 0:传统 ptrace 权限。
- 1:受限 ptrace。
- 2:仅允许管理员附加。
- 3:无附件。
Yama 应在策略 0 和 1 下授予 createdump 的访问权限,但预期在策略 2 和 3 下将拒绝访问。 策略 3 始终拒绝访问,策略 2 默认不起作用,因为 createdump 通常没有CAP_SYS_PTRACE的功能。
为什么只有在 dotnet-dump 或发生崩溃的进程以提升的权限运行时,才能在 Linux 上获取转储?
某些基于 Linux 的系统配置了安全策略,要求任何收集转储的进程都具有 CAP_SYS_PTRACE 功能。 进程通常不具有此功能,但以提升的权限运行可启用该功能。 有关 Linux 安全策略如何影响转储收集的更完整说明,请参阅“为什么 Linux 上的转储收集失败?
为什么在容器内运行时无法收集转储?
对于在任何开放容器计划技术下运行的应用程序,配置文件seccomp必须允许调用 ptrace()。 例如,Docker 在后台使用 containerd 作为容器运行时。 初始化运行时时,它指定默认的 seccomp 配置文件,仅在容器主机的内核版本高于 4.8 或指定了 CAP_SYS_PTRACE 功能时才允许 ptrace。
有关 Linux 安全策略如何影响转储收集的更完整说明,请参阅问题“为什么在 Linux 上转储收集失败?
为什么无法在 macOS 上收集转储?
在 macOS 上使用ptrace时,目标进程的主机需具备适当的授权。 有关最低所需权利的信息,请参阅 默认权利。
为什么无法在 Android 或 iOS 上收集转储?
移动平台(Android 和 iOS)不支持转储收集。 这些平台使用不支持内存转储生成的 Mono 运行时。
在哪里可以详细了解如何利用转储来帮助诊断 .NET 应用程序中的问题?
下面是一些其他资源:
如何解决“找不到任何兼容的框架版本”
在 Linux 上, DOTNET_ROOT 环境变量必须在设置时指向正确的文件夹。 当它指向另一个 .NET 版本时, dotnet-dump 始终生成此错误。
DOTNET_ROOT如果未设置环境变量,则会生成其他错误(“必须安装 .NET 才能运行此应用程序”)。