排查 dsh Web Profile 中的 landlock-run ENOENT,最后发现问题不在 Landlock
这次排查的起点很简单。
在使用 dsh 的 Web 模式时,曾经出现过类似下面的信息:
spawn .../landlock-run ENOENT
第一反应通常会落在几个方向上:
-
landlock-run文件不存在 -
systemd 用户会话异常 -
sandbox 配置错误 -
Web Profile 和 Headless Profile 行为不一致
后面的检查基本围绕这几个假设展开。
随着证据一点点补齐,最后得到的结论反而很朴素。
当前机器上的 Landlock、systemd user、dsh sandbox 以及 Web Profile 本身都工作正常,真正需要找的是那一次历史会话里为什么出现了 ENOENT。
先确认 systemd user 环境是否正常
dsh 的 subprocess 会通过 systemd user scope 拉起隔离进程。
先检查用户级 systemd 是否正常运行。
systemctl --user is-system-running
返回结果:
running
继续确认运行时目录和 DBus 地址。
echo "XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR"
echo "DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS"
输出:
XDG_RUNTIME_DIR=/run/user/0
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus
这两个变量都已经存在。
随后直接测试 systemd user scope 能否正常创建。
systemd-run --user --scope --quiet --collect --expand-environment=no \
--unit=dsh-test \
-- /usr/bin/node -e 'console.log("SYSTEMD_RUN_OK")'
echo "exit=$?"
结果:
SYSTEMD_RUN_OK
exit=0
如果这里失败,后面很多排查都没有意义。
至少到这一步,可以确认 dsh 依赖的 systemd user 环境没有问题。
用 Headless Profile 验证 subprocess 能否真正启动
下一步直接绕开 Web Profile。
使用 Headless Profile 执行一段最简单的 Bash。
dsh --profile headless \
'printf "USER=%s\n" "$(whoami)";
printf "SHELL=%s\n" "$SHELL";
command -v bash;
echo HELLO'
echo "exit=$?"
返回内容:
USER=root
SHELL=/bin/bash
/usr/bin/bash
HELLO
exit=0
这里验证了几件事:
| 检查项 | 结果 |
|---|---|
| Bash 可执行文件存在 | 成功 |
| 用户身份正常 | root |
| Shell 环境正常 | /bin/bash |
| subprocess 可以执行命令 | 成功 |
如果 landlock-run 真不存在,这一步通常就会直接报错。
Web Profile 的行为和 Headless 完全不同
接下来尝试同样的命令。
dsh --profile web \
'printf "USER=%s\n" "$(whoami)";
printf "SHELL=%s\n" "$SHELL";
command -v bash;
echo WEB_TEST_OK'
返回:
error: too many arguments.
Expected 0 arguments but got 1
再次测试:
dsh --profile web \
'id; /usr/bin/env bash -c "echo CHILD_BASH_OK; command -v bash; id"'
结果仍然相同:
error: too many arguments.
Expected 0 arguments but got 1
这一步其实说明了一件容易忽略的事情。
Web Profile 根本不是一个命令执行入口。
查看帮助信息后可以确认这一点。
dsh --profile web --help
输出:
Usage: dsh --profile web [options]
Serve the DeepSeek Harness browser UI.
它启动的是 Web UI 服务,不接受命令字符串作为参数。
因此这里的报错与 sandbox 无关,只是 CLI 用法不匹配。
把 Web Profile 配置完整导出来
为了确认 Web 和 Headless 是否使用了不同的 Sandbox 组件,导出配置。
dsh --profile web --dump-config > /tmp/dsh-web-config.txt
重点检查 sandbox 相关插件。
配置中出现:
- id: subprocess
name: '@deepseek-ai/dsh-subprocess-local'
- id: sandbox
name: '@deepseek-ai/dsh-sandbox-local'
- id: sandbox-policy
name: '@deepseek-ai/dsh-sandbox-policy'
- id: bash-sandbox
name: '@deepseek-ai/dsh-bash-sandbox'
同时还能看到:
mode: workspace-write
以及权限预设:
read-only
workspace-write
danger-full-access
从配置角度看,Web Profile 并没有切换到另一套 sandbox 实现。
使用的仍然是:
dsh-subprocess-local
dsh-sandbox-local
dsh-bash-sandbox
这和 Headless Profile 的关键组件是一致的。
检查 Profile 是否存在额外覆盖
继续查看 Profile 文件。
sed -n '1,260p' /root/.dsh/profiles/web/cordis.yml
结果:
[]
查看补丁层:
sed -n '1,260p' /root/.dsh/profiles/web/cordis.patch.yml
结果:
[]
这说明当前 Web Profile 没有用户自定义覆盖。
不存在某个 patch 把 sandbox runner 换掉的情况。
确认实际运行的 Web 服务
查看正在运行的 dsh 进程。
pgrep -af dsh
结果:
800 node /usr/bin/dsh web --no-open --trusted-host kenfan0108.vip
进一步查看命令行。
tr '\0' ' ' < /proc/800/cmdline
得到:
node /usr/bin/dsh web --no-open --trusted-host kenfan0108.vip
说明当前 Web 服务确实是这一个进程。
最关键的证据来自 journalctl
真正有价值的信息出现在 systemd 日志里。
查询最近日志。
journalctl --user --since "2 hours ago" --no-pager \
| grep -Ei \
'dsh|ENOENT|landlock|sandbox|runner|subprocess|bash'
日志中出现了多次 subprocess 启动记录。
例如:
Started dsh-subprocess-8634-9c10d71c9244.scope -
/usr/bin/node
/usr/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/dsh-subprocess-local/lib/runner.js
--
/usr/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/landlock-run
--
bash -c "echo HELLO"
以及:
Started dsh-subprocess-8712-bcceb363dfa8.scope -
...
landlock-run
...
bash -c "printf \"USER=%s\n\" ..."
这里已经能确认几个关键事实。
事实一
landlock-run 文件存在。
因为 systemd 已经成功执行到该路径。
事实二
Node 的 spawn 能找到 landlock-run。
否则不会进入 scope。
事实三
Landlock 能实际创建隔离环境。
日志里已经看到:
--ro /
--rw /tmp
--rw /root
这些参数已经被成功传入。
事实四
Bash 能在 Landlock 环境里执行。
因为对应命令已经运行结束。
当前证据能得到什么结论
截至排查结束,已经验证成功的项目如下。
Landlock kernel OK
landlock-run ELF OK
Node spawn landlock-run OK
landlock --probe OK
Landlock confinement OK
systemd-run --user OK
headless profile OK
web profile sandbox config OK
web subprocess startup OK
这意味着最初看到的:
spawn .../landlock-run ENOENT
大概率不是当前环境持续存在的问题。
更像是某一次具体 Session、Subagent 或历史工具调用里的异常记录。
下一步应该查什么
此时继续改配置已经没有意义。
更合理的方向是回到历史数据。
重点搜索:
grep -RniE \
'spawn .*landlock-run|landlock-run.*ENOENT|ENOENT' \
/root/.dsh
同时检查 Session 目录:
find /root/.dsh/sessions \
-type f \
\( -name '*.jsonl' -o -name '*.log' -o -name '*.ndjson' -o -name '*.json' \)
以及 Subagent 历史记录:
grep -RniE \
'ENOENT|landlock-run|node-addon-system-linux-x64' \
/root/.dsh/subagent-gc-backup
因为当前系统已经能够稳定创建:
systemd scope
→ dsh-subprocess-local
→ landlock-run
→ bash
剩下真正需要定位的,是当时记录下 ENOENT 的那份历史上下文。
操作清单速览
-
[ ] 验证 systemctl --user is-system-running -
[ ] 检查 XDG_RUNTIME_DIR -
[ ] 检查 DBUS_SESSION_BUS_ADDRESS -
[ ] 验证 systemd-run --user -
[ ] 用 Headless Profile 测试 Bash 执行 -
[ ] 导出 Web Profile 配置 -
[ ] 检查 cordis.patch.yml -
[ ] 确认 Web 服务实际运行进程 -
[ ] 从 journalctl 提取 subprocess 日志 -
[ ] 在 Session 与 Subagent 历史记录中搜索 ENOENT
FAQ
Web Profile 为什么执行不了命令?
因为 dsh --profile web 的作用是启动 Web UI 服务,本身不接受命令字符串作为执行参数。
too many arguments 是 sandbox 报错吗?
不是。CLI 参数解析阶段就失败了,还没有进入 sandbox。
当前机器上的 landlock-run 存在吗?
存在。systemd 日志已经显示其完整路径并成功执行。
Node 能成功 spawn landlock-run 吗?
能。日志里已经出现多个成功启动的 subprocess scope。
Headless Profile 是否正常?
正常,可以执行 Bash 命令并返回结果。
Web Profile 是否使用不同的 Sandbox 实现?
从导出的配置看,没有。核心组件仍然是 dsh-subprocess-local、dsh-sandbox-local 和 dsh-bash-sandbox。
是否需要重装 dsh?
目前没有证据支持这一操作。
当前最值得排查的方向是什么?
搜索历史 Session、Subagent 和日志文件,找到最初记录 landlock-run ENOENT 的原始上下文。

