Fix codex-host profile: capability allow + netlink (bwrap needs both)

Two bwrap failures found by live host tasks, both in the
AppArmor profile (not in codex or the worker):
1. deny capability sys_admin (etc.) breaks bwrap at userns
   creation: codex-host with the deny list failed, the same
   profile with capability, allowed it. codexsvc holds no host
   capabilities, so the allow only covers fake-root caps inside
   bwrap's own user namespace (scoped, harmless to the host);
   network/ptrace/file denies still hold independently.
2. bwrap brings up loopback in its new net namespace via a
   NETLINK_ROUTE socket: without network netlink raw, codex
   workspace-write fails with 'Failed to bind NETLINK_ROUTE
   socket' and no tool runs. And a bare 'deny network raw'
   overrides the netlink allow (deny wins over allow), so the
   raw deny must name inet/inet6 explicitly (verified by an
   isolated netlink bind test under each profile variant).
README correction in the same change: codex workspace-write
does NOT isolate /tmp -- an agent /tmp write lands on host
/tmp (verified). The verified boundary is: own worktree
writable, everything else read-only, /tmp shared.
This commit is contained in:
host committed 2026-10-26 08:39:57 +08:00
1 parent bfe3521ef7
commit 4a78ca1e95
3 files changed
+50 -26

No files matched your search

+16
View File
@@ -93,6 +93,22 @@ class HostConfigProfileTestCase(unittest.TestCase):
self.assertIn("pivot_root,", text)
self.assertNotIn("deny mount,", text)
self.assertNotIn("deny umount,", text)
# bwrap 还需要 userns 内的 capability(实测:deny
# capability sys_admin 会让 bwrap 在 userns 创建处失败,
# 而 capability, 允许则成功;codexsvc 本身无宿主
# capability,所以这里允许的只是 userns 内的假 root
# capability,不授予宿主特权)。
self.assertIn("capability,", text)
self.assertNotIn("deny capability sys_admin,", text)
# bwrap 还需要 netlink(在新网络命名空间里拉起 loopback;
# 缺了会报 Failed to bind NETLINK_ROUTE socket,且任何
# 工具都跑不起来)。注意 AppArmor 里 deny 优先于 allow,
# 所以 raw 的 deny 必须写明 inet/inet6,不能写裸的
# deny network raw(那样会连 netlink raw 一起挡掉,
# 已用隔离 netlink bind 实测验证)。
self.assertIn("network netlink raw,", text)
self.assertIn("deny network inet raw,", text)
self.assertNotIn("deny network raw,", text)
if __name__ == "__main__":