Skip to content
← 博客2026年11月4日 · Kernflux

DSec 的 aether 和 chronus:一条命令经过哪些组件 ​

DeepSeek DSec 论文(§2、§3.3)说,sandbox 运行后的操作依次经过 apiserver、edge、aether、chronus。aether 是每个 sandbox 一个的代理,chronus 是一个 shell 会话。论文讲清了它们的分工,但具体协议和异常处理留给了实现。这篇记录 OpenDsec 的做法,不代表 DSec 内部也这样做。

请求链 ​

一次 await sb.run_shell("pip install -e ."):

text
SDK
 │ gRPC + TLS
 ▼
apiserver     鉴权 sandbox.operate,按 sandbox id 找到 edge
 │ gRPC
 ▼
edge          暂停中就先恢复,刷新空闲超时,调用期间不做空闲回收
 │ unix socket(容器)或 vsock(VM)
 ▼
aether        sandbox 内的 PID 1,按会话 id 找到或启动 chronus
 │ unix socket
 ▼
chronus       持有一个常驻 shell,执行命令,记录输出

三段内部通信用同一组 gRPC 消息:对外的接口带 sandbox_id,edge 转发,aether 和 chronus 实现同一个 Runtime 服务。所以容器和 VM 的差别只在 edge 到 aether 这一段的传输方式上,上层不用管。这也是论文要的效果:同一套接口覆盖容器和 VM。

每一层为什么存在 ​

apiserver 不保存状态。sandbox id 里编码了它创建时所在的 edge,不用查表。暂停的 microVM 换过节点后,edge 的状态里会列出迁入的 id,原节点也会回复新位置。

edge 是唯一和 sandbox 通信的控制面组件。透明恢复放在这里,因为只有它知道 sandbox 当前的状态。当前节点放不下时,由 apiserver 把暂停的 microVM 迁到别的节点。

aether 还负责存活检测。edge 和它保持一条 Watch 流,流断了就算 sandbox 丢失,这一点和论文相同。会话关闭时,aether 杀掉 chronus 的整棵进程树。

chronus 让 cd、export 的状态在命令之间保留。每个会话一个进程,同一会话里的命令串行执行,要并发就开多个会话。

论文没细说、实现时要决定的事 ​

命令比连接活得久。 输出写进文件,调用方断开后可以按偏移量继续取(GetOutput),也可以流式接收。每条命令有请求 id,SDK 重试时能找到已经在跑的命令,不会执行第二遍。这对 pip install 这种有副作用的命令很重要。

输出不能无限记。 论文记录过智能体无限输出写满存储。命令的输出先写进命名管道,由 chronus 读出来记录,每条命令每路最多记 64 MB,超出的部分读出后丢弃,命令不会因此阻塞。每个会话最多保留 512 MB,超出就删最早的记录。

后台进程不能漏掉。 chronus 是子进程收割者(subreaper),命令里放到后台的进程也留在会话的进程树里。杀进程树时要先反复 SIGSTOP,直到再也找不到新进程,再统一发信号;只扫描一次会漏掉扫描之后 fork 出来的进程。

不是所有调用都适合走 shell。 文件操作由 chronus 直接执行,不经过 shell。要按 pid 寻址、写 stdin、用 PTY 的独立进程,由 aether 管理,不经过会话,E2B 网关就用这个接口。

智能体会攻击这条链 ​

论文记录了智能体直接向 chronus 的 socket 发伪造请求,以及读 chronus 的日志找答案。DSec 用 AppArmor 限制。OpenDsec 没有用 AppArmor,因为它挡不住 microVM guest 里的 root,改成让 agent 会话用普通用户:

攻击OpenDsec 的处理
向其他会话的 chronus socket 发请求socket 权限 0600,普通用户连不上
读其他会话的命令记录记录目录属 root,输出文件只有 chronus 能读写
覆盖 /bin/bash普通用户改不了系统文件
在记录目录放符号链接,让 chronus 以 root 写别的文件目录一直属 root,普通用户不能往里放文件(2026-10-27 修复)
从 microVM guest 经 vsock 连 aetherguest 内核没有开 vsock loopback,连不上

这些都有一个前提:调用方要给 agent 指定普通用户(run_shell(..., user=...))。agent 跑在 root 会话里时,这张表前三行都不成立。

和论文不同的地方 ​

  • FnCall:论文的 FnCall 不用 aether 和 chronus,直接在预建容器里执行。OpenDsec 的 fncall 是预建池里 aether 已经就绪的容器,走同一条链。
  • PID 1:在 OpenDsec 里 aether 通常是 sandbox 的 PID 1。论文没有说明。
  • 容器位置:论文的容器跑在 VM 里,OpenDsec 的容器直接跑在宿主机上,所以 edge 到 aether 是 unix socket。

相关阅读 ​

OpenDsec 与 DeepSeek 没有关联。文中关于 DSec 的内容均来自上述论文。

基于论文 DeepSeek Elastic Compute (DSec)(arXiv:2609.22978)实现。本项目独立开发,与 DeepSeek 没有关系。