终端工件授权完整性¶
点击终端输出中的路径,会针对一个位于全局可写临时目录中的文件签发一个短生命周期授权。在签发授权和使用它之间,主机上的任何进程都可以替换该文件。本页是捕获此类替换的检查的契约——更重要的是,也是它们未关闭的时间窗口的契约。
在削弱 src/main/runtime/runtime-file-commands-terminal-artifact-access.ts 中的某个检查之前、在假设该序列是原子的之前、或在将保证扩展到远程主机之前,请先阅读本页。
stat 标识比看起来更弱¶
授权将文件固定为 dev:ino:nlink:size:mtimeMs。这五个字段中有四个能在同一路径的删除并重建中存活,这是在 Linux(Node 24)上通过重放该确切序列测量得到的:
| 字段 | 在同一目录中执行 rm + 重建后 |
|---|---|
dev |
不变 — 同一文件系统 |
ino |
100% 的时间被复用(3000/3000);ext4 会交还已释放的 inode |
nlink |
前后均为 1 |
size |
只要替换内容长度相同就不变 |
mtimeMs |
量化到 1 ms — 内核的粗粒度时钟每个 tick 前进一次 |
因此,对于等长替换,整个标识字符串会坍缩为 1 ms 的时间戳竞争。完整字符串在连续迭代中 63.7% 发生碰撞,在 0.5 ms 间隔下为 19.8%,在 ≥1 ms 下为 0%。同样的探测在 macOS 上 2000 次中碰撞 0 次——没有 inode 复用,mtime 为纳秒级——这就是为什么它只在 Linux CI 上出现过。
ino 对它本应捕获的精确情形没有任何区分能力。不要添加 ctimeMs 或 birthtimeMs 指望修复此问题:它们来自同一个粗粒度时钟,并在同一窗口内碰撞。bigint: true 的 stat 也无济于事——精度损失在于存储的内核时间戳,而不是 Node 的 Number。
内容摘要与标识并列存在,且不能替代标识¶
本地授权还会固定工件字节的 sha256,从与 stat 同一个打开句柄读取,使两者描述同一个 inode,且二者之间没有间隙。
标识字符串保持原样,因为它是线路契约,而不是主机本地细节:src/relay/fs-handler-terminal-artifact.ts 会从它自己的 stat 逐字段重新计算相同的 dev:ino:nlink:size:mtimeMs 格式,并将其与主机发送的 expectedStatIdentity 进行比较。更改格式会使新主机发布一个旧中继永远无法复现的字符串,导致所有远程工件读取都失败为 terminal_file_grant_stale——这种破坏会波及旧对等端,且完全不需要线路模式变更。参见 远程线路兼容性。
仍然开放的问题¶
摘要缩小了这些检查的范围。它没有使其中任何一项变成原子的。
- 读取和预览 — 已关闭。 返回给调用方的字节就是被摘要的同一内存缓冲区,中间没有重新读取,并且句柄在整个操作期间固定 inode。在
open之后发生的替换会使句柄仍停留在被授权的 inode 上,因此提供的是被授权的内容;在它之前发生的替换会使摘要校验失败。 - 写入 — 仍存在窗口。 在最终的重命名前校验与
rename()本身之间,目标路径仍可能被替换,而 rename 会覆盖那里已有的任何内容。POSIXrename()没有“仅当目标仍是 inode X 时”的形式;Linux 的renameat2(RENAME_EXCHANGE)可以关闭它,但不可移植,且 Node 未暴露它。进一步缩小它意味着改变提交策略,而不是在它之前再加一个检查。 - 超过 10 MB 的工件回退到仅 stat 检查。 它们的摘要为
null,因此只有标识在保护它们。没有泄露:所有读取、预览和写入路径都会在读取前按大小拒绝。该弱点不可达,而非已修复——后续的大小上限变更可能使其暴露。 - 远程和 SSH 授权未受影响。 它们保留仅 stat 检查,并在中继运行的任何文件系统上保留完整的 1 ms 弱点。关闭它需要协商能力,确保旧中继永远不会收到它无法验证的摘要。
已证明的内容与推断的内容¶
上述文件系统数字是直接测量结果。相同 stat 加上内容变化之前会返回被替换的字节,而现在不会,这一点由 orca-runtime-files-terminal-artifact-swap-detection.test.ts 固定,它会重放某个路径首次看到的 stat,使碰撞是确定性的,而不是 1 ms 的抛硬币。
两者之间的关联是一条证据链,而不是单一观察。该缺陷表现为 orca-runtime-files-terminal-artifact-io.test.ts 在 rejects stale absolute terminal artifact previews before returning changed content 上的间歇性失败,该测试将一个 8 字节工件替换为 8 个不同字节。没有人对 Linux 运行器进行插桩以证明某个特定 CI 失败是同一 tick 的 mtime 碰撞;该结论建立在每个要素都被单独测量之上。如果未来失败不符合此情况,请相应处理。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 orca48/orca