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

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

Hacker Newsで議論の続きを見る