Claude Media
apply-seccompのsetgroups書き込みがPermission deniedで失敗する原因と対処

apply-seccompのsetgroups書き込みがPermission deniedで失敗する原因と対処

apply-seccompのsetgroups書き込みがPermission deniedで失敗するLinuxサンドボックス不具合の2つの原因説と、allowAllUnixSocketsなど回避策の代償を扱います。

Claude CodeのLinuxサンドボックスを有効にすると、すべてのBashコマンドが次のエラーで失敗することがあります。

apply-seccomp: write /proc/self/setgroups (nested userns is capability-restricted; caller must provide CAP_SYS_ADMIN): Permission denied

結論から言うと、network.allowAllUnixSockets: trueを設定すると、サンドボックスを残したままこのエラーを避けられます。sysctlでAppArmorの制限を外しても直らないことが多く、修正は入っていません。

GitHub Issue #43454は、Claude Code 2.1.92でapply-seccompヘルパーが必ず呼ばれるようになってから、Ubuntu 24.04以降で起きている不具合です。Issueは2026年4月4日に登録され、2026年8月24日のコメントでも同じ失敗が報告されています。原因の説明が2つに割れており、サンドボックスを丸ごと切らずに済む回避策がnetwork.allowAllUnixSocketsだという点が、この記事の中心です。

似た場面で起きるunshare(CLONE_NEWUSER)のEINVAL失敗とは原因も対処も別物です。サンドボックスそのものの有効化・無効化の挙動はsandbox.enabledはClaude CodeのBashコマンドを隔離する設定で確認できます。

/proc/self/setgroups書き込みが拒否される仕組み

sandbox.enabledが有効なLinux環境で、Claude Codeはapply-seccompという名前のヘルパーを使い、ユーザー名前空間(user namespace)を作ってからBashコマンドを起動します。ユーザー名前空間の内側では、UID/GIDのマッピングより先に/proc/self/setgroupsへdenyを書き込む手順を踏みます。Issue本文の再現コマンドは、この書き込みだけを切り出したものです。

# apply-seccompが内部で行っているのと同じパターン
unshare -U bash -c "echo deny > /proc/self/setgroups"
# → Permission denied
 
# 先にUIDマッピングを済ませると成功する
unshare -Ur echo test

エラー文は「CAP_SYS_ADMIN(Linuxの特権のうち特に広範なもの)が要る」と言っています。ところがIssueのコメントでは、この説明が正しいかどうかで意見が分かれています。

原因は2つの説に割れている

くらべる

Issueに出ている原因の説明

4月から

AppArmorの拒否説

Ubuntuの/etc/apparmor.d/bwrap-userns-restrictが定義するunpriv_bwrapプロファイルが、audit deny capabilityでbwrap配下の子プロセスからCAP_SYS_ADMINを剥がします。apply-seccompもその対象です。kernel.apparmor_restrict_unprivileged_usernsを0にしても直らないのは、制限の場所が別だからだと説明されます。

8月5日のコメント

bwrapの継承説

非特権で動くbwrapが自分のユーザー名前空間にsetgroups=denyを設定し、これは子孫の名前空間でも変えられません。ヘルパーの中でもう一度denyを書く処理が、カーネルに拒否されます。bwrap --cap-add CAP_SYS_ADMINを付けても失敗する比較表が根拠で、bwrapがsetuid rootの環境ではsetgroupsがallowのままになるため、同じ書き込みが通るとされています。

どちらの説でも、kernel.apparmor_restrict_unprivileged_userns=0では直らない点は一致しています。

失敗する書き込みは環境によって異なります。8月18日のClaude Code側のコメントは、カーネルによって失敗するのがsetgroupsの場合もuid_mapの場合もあるが、根本原因は同じだと書いています。同じ日の別のコメントは、カーネル更新の後にunshare -Urがuid_mapの書き込みで失敗するようになったと報告しました。以前は通っていたコマンドです。標準のunprivileged_usernsプロファイルがcapabilityをaudit denyすることが、AppArmor説の根拠の一つになっています。6月22日のコメント(Ubuntu 26.04・kernel 7.0.0-15)も、同じ設定値のまま再現したと報告しています。

自分の環境がこの不具合に該当するか

エラーメッセージが同じでも原因が違うケースがあります。次の順で確かめると、的外れな対処を避けられます。

手順

症状の切り分け

  1. 1

    AppArmorが実際に拒否しているかを見る

    監査ログにunpriv_bwrapの拒否が出ていれば、AppArmor側にも原因があります。

  2. 2

    bwrapの内側で`setgroups`が`deny`になっているかを見る

    bwrap --dev-bind / / --unshare-user -- cat /proc/self/setgroupsがdenyを返し、外側のcat /proc/self/setgroupsがallowなら、継承説に当てはまります。

  3. 3

    どちらでもなければ別の原因を疑う

    apply-seccompの実行権限の欠落や、コンテナ内の/procマウント失敗は、同じ画面に別のエラーで出ます。後の節で扱います。

sudo dmesg | grep -i "apparmor.*DENIED.*unpriv_bwrap"

出力にはprofile="unpriv_bwrap" comm="apply-seccomp" capability=21 capname="sys_admin"のような行が並びます。報告はkernel 6.17.0-14から7.0.0-30まで複数のバージョンにまたがっており、特定のカーネルビルドに限った不具合ではありません。

v2.1.92でサンドボックスのフォールバックが消えた

この不具合は既存のバイナリが壊れたのではなく、新しいヘルパーの導入で表面化しました。CHANGELOGはv2.1.92の変更点を次のように記録しています。

Linux sandbox now ships the apply-seccomp helper in both npm and native builds, restoring unix-socket blocking for sandboxed commands

v2.1.91で動いていたという報告の中には、サンドボックス自体が起動していなかった環境があります。4月17日のコメントは自環境でsocatが未導入だったと書いています。当時はsocatが入っていないとサンドボックスが黙って無効化され、Bashは素のまま(Seccomp: 0、ユーザー名前空間なし)で実行されていたためです。v2.1.92からはヘルパーがsocatの有無に関係なく呼ばれ、それまで隠れていた失敗が起動エラーとして表に出ました。

公式ドキュメントはseccompフィルターを「任意」と書き、足りなければnpm install -g @anthropic-ai/sandbox-runtimeで入れるよう案内しています。一方、sandbox-runtimeを入れていないネイティブ版でも失敗は出たと、8月18日のコメントは報告しています。npmパッケージを外しても、この不具合の逃げ道にはなりません。

似た症状の別原因と混同しない

npmでインストールした環境では、apply-seccompバイナリ自体に実行権限が付いていないケースが報告されています。macOSのHomebrew経由のnpmインストールでも、同じ手順を挙げるコメントがあります。

sudo chmod +x /usr/local/lib/node_modules/@anthropic-ai/claude-code/vendor/seccomp/*/apply-seccomp

ただし、この実行権限の欠落は今回のCAP_SYS_ADMINエラーの原因ではないと、同じIssueの別のコメントが指摘しています。ネイティブインストールでは権限の問題が起きず、ヘルパーは起動したうえで拒否されるためです。

socatをアンインストールすると症状が消えたという報告もあります。これは前節のとおりサンドボックスを無効化しているだけで、修正ではありません。

Bubblewrapを非特権コンテナの中で動かすと、bwrap: Can't mount proc on /newroot/proc: Operation not permittedという別のエラーで失敗することもあります。公式ドキュメントのTroubleshootingが扱う制限で、enableWeakerNestedSandboxをtrueにすると、コンテナが用意した/procをそのままバインドマウントして回避します。メッセージが「Operation not permitted」で、かつコンテナの中で出ているなら、本記事の対処では直りません。

公式のAppArmorプロファイルは効くのか

公式のサンドボックスドキュメントは、Ubuntu 24.04以降の制限に対して、bwrapだけにユーザー名前空間の作成を許可するプロファイルを示しています。まず制限の有無を確認します。

sysctl kernel.apparmor_restrict_unprivileged_userns

値が1なら制限が有効です。0のとき、またはキーがない旨のエラーが出たときは、この手順は不要です。値が1のときは、次のプロファイルを追加してAppArmorを再読み込みします。

sudo tee /etc/apparmor.d/bwrap > /dev/null <<'EOF'
abi <abi/4.0>,
include <tunables/global>
 
profile bwrap /usr/bin/bwrap flags=(unconfined) {
  userns,
  include if exists <local/bwrap>
}
EOF
sudo systemctl reload apparmor

このプロファイルは/usr/bin/bwrapにだけ適用され、サンドボックス内部のコマンドには効きません。Issueでの評価は割れています。7月16日のコメントは、この手順をやり直して直ったと報告しました。8月18日のコメントは、公式のプロファイルがbubblewrapだけを対象にしているため、このエラーには足りない場合があると書いています。5月15日のコメントは、denyはallowやlocal/の上書きより常に優先されるので、配布元のbwrap-userns-restrictにある拒否行は上書きできないと述べています。

回避策と、それぞれが手放すもの

{
  "sandbox": {
    "enabled": true,
    "allowUnsandboxedCommands": false,
    "network": { "allowAllUnixSockets": true }
  }
}
対策内容手放すもの
network.allowAllUnixSockets: true内容seccompフィルターを使わずにサンドボックスを起動する手放すものUnixソケットの遮断(ファイルシステムの隔離は残る)
bwrap-userns-restrictを直接編集内容audit deny capabilityをコメントアウトしallow capability sys_adminを追加手放すものFlatpakなどすべての非特権bwrapアプリにCAP_SYS_ADMINを再付与する
干渉する別プロファイルの確認内容Lutrisが導入する/etc/apparmor.d/usr.bin.lutrisなどがunpriv_bwrapを上書きしていないか見る手放すもの該当する環境だけの対処
sandbox.enabled: false内容サンドボックスそのものを無効化する手放すものファイルシステムとネットワークの隔離が丸ごと失われる
v2.1.91への固定内容自動更新を止めて古いバージョンに留める手放すもの将来socatを入れた時点で同じ制限にぶつかる可能性がある

一番上の行が、サンドボックスを残せる回避策です。公式の設定リファレンスでは、LinuxとWSL2のseccompフィルターがsocket(AF_UNIX, ...)の呼び出しを遮断しており、allowAllUnixSocketsがそれを許可する唯一の手段だと説明されています。macOS向けのallowUnixSocketsのパス一覧はLinuxでは無視されます。

4月21日のコメントから、allowAllUnixSockets: trueで直ったという報告が複数出ています。8月18日のコメントは2.1.234で測り、この設定だけで、setgroupsはdenyの非初期ユーザー名前空間のまま、ワークスペース外への書き込みは拒否され、cwd内は書き込めたと報告しました。sandbox.enabled: falseに逃げるよりずっと小さな代償です。

ここでallowUnsandboxedCommandsも確認しておきます。この値が既定のtrueのままだと、最初のコマンドが失敗したあと、モデルがdangerouslyDisableSandboxで再試行し、サンドボックスの外で実行される経路が残ります。8月18日のコメントはこの挙動を観測しています。falseにすると、この再試行は無視されます。

個別のコマンドだけをサンドボックス対象外にするsandbox.excludedCommandsでdockerなど非対応コマンドを対象外にするという設定もあります。ただし、この不具合はサンドボックスの起動自体で起きるため、特定コマンドを除外しても他のコマンドで同じエラーに当たります。

修正はまだ入っていない

Issueはopenのままで、最後のコメントは8月24日、コメントは28件です。8月18日のコメントは、これを再現済みの回帰として開いたままにすると書いています。同じコメントは暫定策にkernel.apparmor_restrict_unprivileged_userns=0を挙げ、Troubleshootingを案内しています。ただし同じ日の11:21のコメントは、これに反論しています。6月の測定(7.0.0-15)でも、#81799(7.0.0-28、sysctlは両方0でAppArmorはunconfined)でも直らなかったためです。8月24日のコメントは、2.1.224・2.1.226・2.1.231の3バージョンで同じ失敗が出たと報告しています。CHANGELOGにこの不具合の修正を示す記載は、v2.1.289まで載っていません。

8月5日のコメントは修正案として、/proc/self/setgroupsがすでにdenyなら書き込みを飛ばす、という変更を挙げました。実現すればallowAllUnixSocketsなしで解消する見込みです。他のAIコーディングエージェントがLinux上で分離をどう作っているかはAIコーディングエージェントのサンドボックス実装比較で比較しています。

まとめ

エラー文は「CAP_SYS_ADMINが足りない」と言いますが、Issueの検証ではbwrapのsetgroups=denyの継承説のほうが、sysctlを0にしても直らない事実と合います。Ubuntuで試せる手段は、公式のAppArmorプロファイルと、Unixソケットの遮断だけを手放すallowAllUnixSockets: trueの2つです。8月24日のコメントは、単一段のbwrap(--unshare-user --cap-drop ALL)は通り、入れ子のときだけ失敗すると書いています。AppArmor側の原因を切り離せる根拠です。unpriv_bwrapの編集やsandbox.enabled: falseは、手放すものが大きい側にあります。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. github.com/anthropics/claude-code/issues/43454
  2. code.claude.com/docs/en/sandboxing
この記事を共有:XはてブLinkedIn