世界を動かす技術を、日本語で。

CVE-2026-31431: ルートレスコンテナにおけるコピー失敗

概要

  • CVE-2026-31431 (Copy Fail)脆弱性の検証とラボ構築手順の解説
  • shellcode 解析から実際のエクスプロイト実行、カーネル挙動のトレースまでを詳細に記録
  • rootless Podman とユーザ名前空間による特権昇格の封じ込めを確認
  • straceeBPF を活用した動作観察とその結果の考察
  • uid_map によるホストとコンテナ間の権限マッピング証明

CVE-2026-31431「Copy Fail」脆弱性の実験と検証

  • SELinux MCS とGitLab Runnerの安全性検討の一環としてCVE-2026-31431を題材に選定
  • Theori による詳細な技術解説は xint.io/blog/copy-fail-linux-distributions を参照推奨
  • 本記事では 公開エクスプロイトのshellcode解析 から rootless環境での実行カーネルレベルでのトレース までを網羅
  • rootless Podman アーキテクチャがどのように特権昇格を封じ込めるかを実証

shellcodeの解析

  • Pythonエクスプロイト に埋め込まれた圧縮・hexエンコード済みshellcodeを zlib.decompress() で展開
  • ELF 64-bit実行ファイル として構成、/usr/bin/suのページキャッシュを上書き
  • objdump で解析不能な最小構成(ELF golfing)
  • 実際の命令列は setuid(0)execve("/bin/sh")exit(0) の流れ
  • /bin/sh の文字列を埋め込み、execveでシェル起動を実現

実験ラボの構築

  • Fedora 43 VM をvirt-installで用意、脆弱なカーネル(6.17.x系)を使用
  • rootless Podman のセットアップ
    • podman専用ユーザ作成
    • pastaによるネットワーク設定
    • Sub-UID/Sub-GIDの広範な割り当て
  • Podman の動作確認コマンド例
    • podman run --rm alpine echo "Rootless Podman is working!"

コンテナ内でのエクスプロイト実行

  • strace によるシステムコールトレースには--cap-add=SYS_PTRACEおよび--security-opt seccomp=unconfinedが必要
  • copy_fail_exp.py を事前にダウンロードし、内容を必ず確認
  • コンテナ内で strace とともにエクスプロイトを実行し、詳細なシステムコールログを取得

エクスプロイトの仕組みトレース

  • AF_ALGソケット を利用し、カーネルの暗号API経由でページキャッシュを不正に上書き
  • sendmsg/splice の組み合わせで、/usr/bin/suのページキャッシュにshellcodeを4バイト単位で注入
  • execve("/usr/sbin/su") でキャッシュ上の不正ELFを実行、 /bin/sh が起動
  • これらの挙動は strace ログで逐次確認可能

rootlessコンテナによる昇格阻止

  • setuid(0) 成功によりコンテナ内でroot取得
  • しかし User Namespace により、コンテナ内UID 0はホスト上の一般ユーザ(例:UID 1000)にマッピング
  • コンテナ内root はホスト上での特権を持たず、/etc/shadowやホストプロセスにはアクセス不可

eBPFによるカーネル動作観察

  • strace ではSUIDバイナリ実行時にカーネルがsecureexec遷移でイベント報告を一時停止するため、setuid(0)拒否を直接観察できない
  • bpftrace を用い、カーネルtracepointでsetuidシステムコールの入出力を監視
  • strace有効時はsetuid(0)が-1(EPERM)で失敗、straceなしでは0で成功
  • 成功時も User Namespace で隔離されているため、ホストへの影響なし

uid_mapによる権限マッピングの証明

  • Podman のユーザ名前空間設定により、コンテナ内UID 0がホストUID 1000(podmanユーザ)に対応
  • /proc/self/uid_map でマッピング状況を確認可能
  • rootless運用 の安全性を数値的に証明

結論

  • CVE-2026-31431 のような深刻なカーネル脆弱性も、 rootless Podman やユーザ名前空間の活用で現実的な攻撃リスクを大幅に低減可能
  • straceやeBPF などのツールを併用し、カーネル挙動の可視化と検証が重要
  • ダウンロードしたエクスプロイトやshellcodeは必ず内容を確認し、安易な実行を避けるべき
  • rootlessコンテナ はCI/CDやランナー環境における安全な隔離手段として有効
  • 今後も ユーザ名前空間最小権限原則 を徹底し、システム全体の堅牢化を推進

Hackerたちの意見

ELFバイナリにsstripを実行するのはELF「ゴルフ」って呼ぶの?今日知った…

それはそうだけど、実際のELFゴルファーはちょっとナイーブだと考えているよ。

要するに、コンテナ内ではエクスプロイトが機能して、コンテナ内でroot(uid 0)に昇格するんだけど、実際にはその名前空間が外部でuid 1000(ユーザー)にマッピングされてるから、ホストには昇格が反映されないってこと。でも…これってコンテナから脱出できるの?もしそうじゃないなら(著者もそう言ってるみたいだし)、Dockerでもrootless Podmanでも関係ないよね?結局、コンテナ内でrootに昇格してるわけだし。コンテナのファイルシステムの隔離がちゃんと機能してれば、結果は同じじゃない?でも、コンテナから脱出するための別の連鎖的なエクスプロイトがあったら、Dockerではもっと悪化するのかな?合ってる?

これは問題で、ほとんどの人はこれまで考えたことがなかったと思う。キャッシュはビルドパイプラインのパフォーマンスを向上させるために行われているからね。「ルートレスコンテナは攻撃者がホストのrootに昇格するのを防ぐけど、ページキャッシュはホスト全体で共有されている。 同じベースイメージレイヤーを再利用するコンテナは、そのレイヤーの同じキャッシュページを共有する。もし悪意のあるCIジョブがページキャッシュ内のバイナリを破損させたら、その同じイメージから起動された他のコンテナが汚染されたバージョンを実行することになっちゃう。」

ホストからのセキュリティ関連のファイルがコンテナにマウントされていると、これが簡単に悪用される可能性がある。コンテナ脱出のための実行可能なツールではあるけど、攻撃チェーンが必要だし、すべてのコンテナが脆弱というわけではないよ。

はぁ。1. デフォルトのseccompポリシーがこれらのコンテナでAF_ALGをブロックしてることを願ってるけど、たぶんしてないだろうな。まぁいいや。2. 書き込み用のROページキャッシュのプリミティブはまだ機能してる!ただ、使われた特定のエクスプロイトは、すでにコンテナ内でrootになってる状況では意味がなかっただけ。自分が安全だと思ってるなら、たぶん間違ってるよ。新しいエクスプロイトを作るのに必要なのは、書き込みが許可されてないはずの何かを表すfdだけだよ。これには、CoWのものも含まれるだろうけど、CoW後に書き込みできるはずなのに、ソースには書き込みできないはずなんだよね。だから:- これらのコンテナを共通のイメージやレイヤーで使って危険なワークロードを隔離してる?うっかりすると、イメージレイヤーを変更してお互いを壊しちゃうよ。クロステナントの隔離なんて意味がなくなる。- ゼロページにバックアップされたfdを取得して、それに書き込んだらどうなる?管理者が承認するような結果にはならないよね。- 何かをro-bind-mountしたらどうなる?もうroじゃなくなるよ。

実際、著者はウェブサイトの最初の行で、copy/failプリミティブがコンテナ脱出に使えると明言してる。この記事の全体の前提が間違ってて無責任だよ。

最後に追記があって、rootless podmanでもページの破損がまだ問題だと認めてる。これを使ってマイクロVMへの移行を正当化するのは、私にはとても奇妙だな。確かにこのCVEに関しては、そっちの方が良かったかもしれないけど、将来の攻撃ではコンテナではなくVM間で共有されるコンポーネントに影響する可能性もあるよね?人々は本当に毎週のCVEに基づいて技術を選んでるの?

podmanについては調べてないけど、moby/dockerは今これをブロックしてると思う。 https://github.com/moby/profiles/commit/7158007a83005b14a24f...

これ、seccompのためにやりたいことを実現するために貢献したよ。デフォルトではないけど、プロファイリングがこの攻撃に対して効果的になった。あ、これも起きたよ。

これらのコンテナでデフォルトのseccompポリシーがAF_ALGをブロックしてくれることを期待してる。多分、ブロックされてないだろうけど。まあ、仕方ないか。多くのプロジェクトがこの脆弱性に対する反応として、コンテナ内でこれらのソケットをブロックしているけど、なんだか変な感じがする。セキュリティバグが一度あったからって、暗号化のパフォーマンス向上機能を完全に無効にするの?それってちょっと変なデフォルトだよね。誰かがEoPバグを発見するたびに、カーネルモジュールを一斉に無効にするわけじゃないし。Heartbleedの後にOpenSSLのバイナリをブラックリストにしたっけ?脆弱なカーネルのデフォルトとしては理解できるけど(脆弱なカーネルを使っている人は、回避策よりもパッチを当てる努力をすべきだと思うけど)、これらのデフォルトはコピー失敗が遠い記憶になる10年後も残ってるんだろうな。

これらのコンテナでデフォルトのseccompポリシーがAF_ALGをブロックしてくれることを期待してる。多分、ブロックされてないだろうけど。まあ、デフォルトポリシーである理由はないよね。他のソケットを全部ブロックして、標準入力/出力で全部マルチプレックスすればいいかも。

[...] rootはホスト上の特権のないpodmanユーザーだっただけじゃん じゃあ、特権のないpodmanユーザーとして再度エクスプロイトを実行して、ホストでrootを取得できるんじゃないの?

誰か試した?ちゃんと動くはずだよね?

いや、まだコンテナの中にいるから、ホストのルートにアクセスできないんだよ。もしコンテナの「ルート」から脱出できる方法を見つけたら、すごいことになるね。

これ、LLM生成っぽいな。エムダッシュがたくさんあって、完全に間違った前提の周りにさらに多くのテキストがある。

記事の中での誤った前提は何?

もし目標が完全なroot権限を防ぐだけなら、systemdユニットにCapabilityBoundingSetを設定すればいい。ただ、コピー失敗はコンテナや上記の設定に含まれない他の方法でも使える。例えば、/etc/ssl/certsを改ざんしてMitM攻撃の準備をすることができる。同じイメージを基にした複数のコンテナがあると、1つの侵害されたCAセットが他にも影響を与える。

私の.serviceにこれを追加したんだけど、AmbientCapabilities=CAP_NET_BIND_SERVICE、CapabilityBoundingSet=CAP_NET_BIND_SERVICE、NoNewPrivileges=yes。これで十分かな?

エクスプロイトのダウンロード/ソース: https://github.com/theori-io/copy-fail-CVE-2026-31431/blob/m... 専用ウェブサイト: https://copy.fail

暗号化APIやVPNをカーネルに入れるのは悪いアイデアだったと思う。ユーザースペースが遅すぎるなら、コンテキストスイッチのオーバーヘッドを減らすか、隔離された特別なプロセスを作るべきだよ。それらは切り替えが速いからね。Windowsの失敗を繰り返してる。

悪いアイデアだとは思わないな。どんなアイデアでも投資が必要だし、カーネルレイヤーへの投資の方が良かったと思う。アメリカが何を恐れていたか、輸出管理法の歴史に聞いてみて。ユーザーレベルでセキュリティを持つと、カーネルやユーザーレベルでの攻撃が価値を持つことになる。カーネル内なら、OpenSSLよりも少ないリソースでより安全にできたはずだし、ユーザーレベルからはアクセスできない鍵も持てたかもしれない。でも、結局はみんながOpenSSLのクローンを使って、リソースを薄く広げているだけだった。

ユーザースペースより速くはないよ、普通はずっと遅い。特別なボードに暗号アクセラレーターがあれば速くなることもあるけど、そうしたい理由があるかもしれない。参考文献: [1] https://www.chronox.de/libkcapi/html/ch01s02.html [2] https://lwn.net/Articles/410763/ [3] https://trac.gateworks.com/wiki/linux/encryption#PerformaceC...

まあ、AF_ALGみたいなほとんど誰も使ってないような古いものなら、あまり反対しないけどね。WireGuardみたいな合理的な暗号化はカーネルにあってもいいと思う。

カーネルからできるだけ物を排除するってアイデアは好きだけど、今回は暗号化がカーネルに必要な理由があるんだ。ディスク上の暗号化が必要だし、暗号化されたディスクからブートできる必要がある。だから暗号化が必要なんだよね。ネットワークファイルシステムも必要だし、ネットワーク上のトラフィックも暗号化されている必要がある。だから暗号化が必要なんだ。IPsecは、良くも悪くも、トランスポート層で認証されて部分的に暗号化されてるから、LinuxマシンがIPsecを使うなら暗号化が必要だよ。これを修正・変更するにはカーネルの大規模な再構築が必要で、基本的にはマイクロカーネルに切り替える必要がある。誰も完全にクソじゃないマイクロカーネルを書いたことがないって事実を考えると、その努力が価値があるかどうかはわからないな。

あのWindowsのミスはもうずっと前に解決されてるよ。

どうやら、エクスプロイトは機能するけど、概念実証は表面的な理由でダメみたいだね(?) それを自慢するほどのことじゃない気がする。

表面的なことじゃないよ。これは防御の深さってやつで、コンテナ内のrootがコンテナ外のrootにならないようにするんだ。ページキャッシュにアクセスできる昇格ユーザーについての議論もあって、コンテナがページを共有する時(これはよくあること)に危険になることがある。攻撃が「うまくいかない」っていうのは、見た目には些細な構造的理由によることが多いのが防御の深さの特徴だよね。こんな攻撃が不可能だったらみんな嬉しいけど、不可能だって証拠がない限り、ちょっとはリスクヘッジしてもいいんじゃない?

もし俺の理解が正しければ、--userns=autoを使ったrootfull podmanも特権昇格を防げるってこと?

どういうこと?

いや、影響はないよ。エクスプロイトはネームスペースの影響を受けない。