Ubuntu 下解决 Codex 的 bubblewrap / user namespace 报错

在 Ubuntu 24.04 上使用 Codex CLI 时,可能会看到如下提示:

1
⚠ Codex's Linux sandbox uses bubblewrap and needs access to create user namespaces.

系统中已经安装了 bubblewrap,但进一步测试:

1
2
3
4
which bwrap
# /usr/bin/bwrap

codex sandbox linux /bin/true

仍会出现错误:

1
bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted

原因

Codex 在 Linux 上优先使用系统的 /usr/bin/bwrap
Ubuntu 24.04 默认启用了 AppArmor 针对 unprivileged user namespaces 的限制策略,而 bwrap 在创建 sandbox 时需要完成 namespace 与 loopback 相关初始化,因此会在该阶段失败。

不建议采用的处理方式

一个直接的办法是关闭全局限制:

1
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0

这样虽然可能立即恢复正常,但代价是将整台机器这一层防护一并关闭。对单个 CLI 工具而言,这种处理方式并不合适。

较为稳妥的处理方式

更合理的做法,是为 bwrap 配置专用的 AppArmor profile:bwrap-userns-restrict

可直接执行以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
sudo apt update
sudo apt install --yes apparmor apparmor-profiles apparmor-profiles-extra

profile="$(dpkg-query -L apparmor apparmor-profiles apparmor-profiles-extra 2>/dev/null | grep '/bwrap-userns-restrict$' | head -n1)"

if [ -n "$profile" ]; then
echo "Using packaged profile: $profile"
if [ "$profile" != "/etc/apparmor.d/bwrap-userns-restrict" ]; then
sudo ln -sf "$profile" /etc/apparmor.d/bwrap-userns-restrict
fi
else
echo "Packaged profile not found; fetching upstream AppArmor profile"
sudo wget -O /etc/apparmor.d/bwrap-userns-restrict \
https://gitlab.com/apparmor/apparmor/-/raw/master/profiles/apparmor/profiles/extras/bwrap-userns-restrict
fi

# 确保两个 profile 都有 mediate_deleted flag,
# 否则 Flatpak 应用的原子保存(linkat 到已删除 inode)会被拒绝
sudo sed -i \
-e 's/profile bwrap \/usr\/bin\/bwrap flags=(attach_disconnected)/profile bwrap \/usr\/bin\/bwrap flags=(attach_disconnected,mediate_deleted)/' \
-e 's/profile unpriv_bwrap flags=(attach_disconnected)/profile unpriv_bwrap flags=(attach_disconnected,mediate_deleted)/' \
/etc/apparmor.d/bwrap-userns-restrict

# 保留 Flatpak 沙箱内 linkat(/proc/self/fd/N) 所需的 capability,
# 否则依赖 Qt QSaveFile 的应用(如 KeePassXC)会无法保存文件
sudo mkdir -p /etc/apparmor.d/local
echo "allow capability dac_read_search," | sudo tee /etc/apparmor.d/local/unpriv_bwrap

sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict

sudo grep -E '(^bwrap |^unpriv_bwrap )' /sys/kernel/security/apparmor/profiles
codex sandbox linux /bin/true

如果最后一条命令执行成功,问题通常已经解决。

验证

可以通过以下命令确认当前状态:

1
2
3
4
which bwrap
sysctl kernel.apparmor_restrict_unprivileged_userns kernel.apparmor_restrict_unprivileged_unconfined
sudo grep -E '(^bwrap |^unpriv_bwrap )' /sys/kernel/security/apparmor/profiles
codex sandbox linux /bin/true

which bwrap 输出为 /usr/bin/bwrap,对应 profile 已加载,且 codex sandbox linux /bin/true 可以正常执行,说明配置已经生效。

额外加固

另一个相关参数是:

1
kernel.apparmor_restrict_unprivileged_unconfined

一些系统上的默认值是 0

这个参数与本文中的 Codex 报错没有直接关系,因此不调整也可以完成修复。

若希望进一步增强限制策略,可以设为 1

1
2
echo "kernel.apparmor_restrict_unprivileged_unconfined=1" | sudo tee /etc/sysctl.d/10-apparmor-hardening.conf
sudo sysctl --load /etc/sysctl.d/10-apparmor-hardening.conf

此操作属于额外的加固,并非本次修复所必需。


可能的其他影响

加载 bwrap-userns-restrict 后,系统上所有经由 /usr/bin/bwrap 启动的程序都会受其约束——最常见的就是 Flatpak 应用。apparmor_parser -r 重载 profile 后,已经在运行的 Flatpak 进程不会自动应用新策略,建议重启受影响的应用。

unpriv_bwrap 子 profile 的 audit deny capability 拒绝了所有 Linux capabilities。除了上述提到 Flatpak 保存问题外,其他 Flatpak 应用如果在沙箱内需要特定 capability,也可能出现功能异常且无明显报错。

排查方式:

1
sudo dmesg | grep -i apparmor | tail -20

若有对应的 deny 记录,在 /etc/apparmor.d/local/unpriv_bwrap 中补上所需的 capability 并重载即可。


参考

Mastodon