RFC-0178:每个作业有多个调试异常通道

RFC-0178:每个作业有多个调试异常渠道
状态已接受
领域
  • 内核
说明

Zircon 允许对一个作业使用多个调试异常通道。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-06-08
审核日期(年-月-日)2022-07-12

摘要

此 RFC 建议更改 zx_task_create_exception_channel,以允许多达 32 个 调试异常渠道。

设计初衷

Fuchsia 上的调试程序依赖于在作业上创建调试异常通道, 监控进程启动,以便捕获感兴趣的进程, 调试异常渠道通常在 根作业,以便调试程序可以监控所有进程。

当进程启动时,内核会遍历作业层次结构 来通知调试作业异常渠道。此次步行从新的 该进程包含的作业,并且会上层层次结构,直到出现调试作业异常 找到渠道或已到达根作业。

不过,目前的实现方法也存在两个缺点。

  • 对于给定的作业,最多只能有一个调试异常渠道,这意味着 大多数调试程序可以监控作业层次结构的任意给定子树。
  • 只有第一个找到的调试异常渠道会收到通知,即 子作业上的调试程序阻止父作业上的调试程序观察 进程启动。

利益相关方

教员:cpu@google.com

审核者:brettw@google.com、maniscalco@google.com

已咨询:johngro@google.com

社交化:在 Fuchsia 的《Kernel Evolution Works》(内核演变工作)中讨论了这一想法 群组。

设计

我们提议 Zircon 允许一个作业上有多个调试作业异常通道。

Zircon 中有 5 种例外渠道: 调试作业、作业、调试进程、进程和线程。它们的每一个 最多对相应的对象执行一次。此限制旨在避免 棘手的情况,比如多个异常处理程序针对 ZX_PROP_EXCEPTION_STATE

不过,“调试作业”因为它只发出通知 渠道:它能收到的唯一异常类型是 ZX_EXCP_PROCESS_STARTING 其中 ZX_PROP_EXCEPTION_STATE 会被忽略。因此,您可以允许 同时处理一个作业的多个调试异常渠道,而无需担心 不一致性。

在一个作业上创建多个调试作业异常渠道后, ZX_EXCP_PROCESS_STARTING 事件将依序发送到所有渠道, 允许多个监听器检查进程只有 一个可连接到给定进程的调试程序不会改变,因为“debug” 进程”异常渠道仍然是独有的,除 第一个请求将获得 ZX_ERR_ALREADY_BOUND

此外,我们还建议修改 ZX_EXCP_PROCESS_STARTING 事件,以便一个事件可以全部传播 即使子作业中创建了异常渠道也是如此。调试 系统会通知作业层次结构中较低级别的作业异常渠道 优先级高于更高层级的算法在任何给定级别,先前创建的渠道 在后续创建的频道之前收到通知。可以继续 仅在所有异常渠道都收到通知且异常对象时开始 已关闭。

请注意,任何异常消息接收器都可能 只是不关闭异常对象的句柄,从而无限期地启动。 但是,它们不能直接停止进程启动。

实现

系统调用不会有任何 API 或 ABI 更改。当前的行为模式 zx_task_create_exception_channel 将更改为允许最多 N 个频道 而不是在第一个事件发生后返回 ZX_ERR_ALREADY_BOUND

性能

性能可能会下降,因为可能会阻塞更多监听器 进程启动。不过,预计不会使用调试异常渠道 或由长时间运行的程序持有。预期 调试器或类似调试工具,因此影响应该微乎其微。

一般来说,调试程序应立即关闭异常句柄 。

安全注意事项

为了避免针对内核的 DoS 攻击, 针对一个作业创建的调试作业异常渠道。上限应该较大 足以允许运行任何合理数量的调试程序,例如 32 个。

测试

我们将向 //zircon/system/utest/debugger 添加新的测试用例以涵盖这方面 功能。

文档

介绍异常处理zx_task_create_exception_channel将 以体现相应更改。

缺点、替代方案和未知问题

替代方案:用户空间的进程委托在根作业上启动

此方法可避免更改内核。而是由用户空间委托 保留根作业调试渠道,并为调试程序提供 FIDL 接口 订阅进程启动受托可以是组件管理器 自行(现在提供fuchsia.kernel.RootJob)或独立计划。

协议应如以下所示

@discoverable
protocol RootJob {
    /// Hanging get pattern
    GetProcessStartingEvent() -> (resource struct {
        process zx.handle:PROCESS;
        continue zx.handle:EVENTPAIR;  // dropping this eventpair will propagate
                                       // the event to the next listener.
    }) error zx.status;
};

这种方法存在以下问题:

  • 它仅适用于根作业。调试程序需要两个逻辑来处理根作业 非根作业
  • 在子作业上创建的异常渠道可以阻止事件传播 根。
  • 引入 FIDL API,其功能与 系统调用。

替代方案:debug_agent 支持多个客户端

我们还可以让 debug_agent 支持多个客户端,以解决当今的问题, 也就是说,debug_agent 会变为单例。

这些问题包括

  • 这会涉及更多工作。
  • debug_agent 将成为 Fuchsia 的指定调试程序。其他调试程序 就必须使用 debug_agent,这样会暴露一个大型且不稳定的 界面。