Podman ルートレスコンテナと Copy Fail エクスプロイト: 影響範囲の分析

CVE-2026-31431(通称 "Copy Fail")の公開は Linux コミュニティに大きな波紋を投げかけました。この脆弱性は、ローカルの非特権ユーザーがカーネルの特定のファイル操作の取り扱いを悪用して root シェルを取得できるようにし、実質的に読み取り専用であるべきファイルを書き換えることを可能にします。

コンテナ化を利用している場合、その影響は重大です。コンテナはしばしば外部向けサービス、CI/CD ジョブ、開発環境を分離するために使用されます。攻撃者がリモートコード実行(RCE)で足場を得た場合、Copy Fail はコンテナ内部で権限昇格に利用され得ます。本稿では Podman のルートレスコンテナにおけるこの脆弱性を検証し、設定の違いが攻撃の「影響範囲」に与える影響を探ります。

ルートレスコンテナの理解

Copy Fail の影響を把握するには、まず Podman がルートレスコンテナをどのように実装しているかを理解する必要があります。従来の Docker デーモンモデル(root 権限のデーモンがコンテナを生成)とは異なり、Podman は fork/exec モデルを採用しています。コンテナプロセスは podman run プロセスの直接の子孫であり、起動したユーザーの UID を継承します。

ユーザー名前空間と UID マッピング

Podman は Linux のユーザー名前空間を利用して分離を提供します。これにより、コンテナ内部ではある UID が、ホスト側では別の UID として扱われます。たとえば、ルートレスコンテナ内で root(UID 0)として動作するプロセスは、ホスト上では非特権ユーザー(例: UID 1001)にマッピングされます。

このマッピングは /etc/subuid によって管理され、非特権ユーザーが名前空間プロセスに割り当て可能な UID の範囲を定義します。これにより、コンテナ内で root であってもホスト側からは非特権ユーザーとして扱われ、ホストシステムへの被害を大幅に制限できます。

Linux ケーパビリティ

Linux の特権は単一のものではなく、"ケーパビリティ" と呼ばれる細分化された権限に分かれています。Podman はこれらを利用してコンテナプロセスに粒度の細かい権限を付与します。たとえば apt でパッケージをインストールするには CAP_CHOWNCAP_SETUID といったケーパビリティが必要です。

デフォルトでは、ルートレスの rootful コンテナ(名前空間内で root として実行)に多くのケーパビリティが付与されます。これにより攻撃面が広がります。より安全なアプローチは "ルートレス non-root" コンテナを実行し、コンテナ内部・外部ともに非特権ユーザーで動作させ、不要なケーパビリティはすべて削除することです。

Copy Fail エクスプロイトのテスト

実際のテストでは、さまざまな Podman 設定下で Copy Fail を用いて権限昇格を試みました。エクスプロイトは通常、su コマンドをパスワード入力なしで実行できる Python スクリプトをダウンロードし、root シェルを取得する手順を含みます。

ルートレス rootful コンテナ

プロセスがすでにコンテナ内で root として実行されている構成では、Copy Fail は冗長です。ユーザーはエクスプロイトが提供しようとする権限をすでに持っています。ただし、プロセスはホスト上では非特権ユーザーにマッピングされているため、ホストの root ファイルにはアクセスできません。

ルートレス non-root コンテナ

ここでエクスプロイトは威力を発揮します。コンテナが非特権ユーザー(例: foo)として実行されている場合、Copy Fail はプロセスをコンテナ内の root に昇格させます。

攻撃者はコンテナ内部で root 権限を得て名前空間の root が所有するファイルにアクセスできますが、ホストユーザーの権限に制限されるため、ホスト上の実際の root が所有するファイルにはアクセスできません。

エスカレーションの緩和策

Copy Fail エクスプロイトの即時効果を阻止するために、主に次の 2 つの Podman フラグが利用できます。

  1. --security-opt=no-new-privileges: 追加の特権取得を防止します。このフラグが設定されていると、Copy Fail エクスプロイトは root シェルを生成できず、ユーザーは foo のままです。
  2. --cap-drop=all: すべてのケーパビリティを削除することで、同様に特権昇格を防ぎます。

これらのフラグは su エクスプロイトを阻止しますが、根本的な脆弱性(ページキャッシュ上の読み取り専用ファイルを書き換える能力)は依然として残ります。カーネルのパッチ適用が完全な解決策です。

深層防御: 影響範囲の限定

単一のセキュリティ境界だけでは不十分なため、深層防御(defense‑in‑depth)戦略が必要です。これにより、侵害されたコンテナが行える被害を最小限に抑えます。

読み取り専用ファイルシステム

--read-only フラグ(--read-only-tmpfs=false と併用)を使用すると、コンテナのルートファイルシステムが読み取り専用でマウントされます。これにより、エクスプロイト後に攻撃者が悪意あるバイナリを書き込んだりシステム設定を変更したりすることは防げますが、メモリ上でのパイプコマンド実行自体は阻止できません。

リソース制限

cgroup を利用してメモリ、CPU、PID 数を制限すれば、侵害されたコンテナがホストや他のコンテナに対して DoS 攻撃を仕掛けることを防げます。

最小イメージ

攻撃者に利用可能なツールセットを減らすことは重要です。ubuntu ベースイメージは curlpython3 など多数のバイナリを含み、エクスプロイトに便利です。-slim イメージ、Alpine Linux、あるいは "distroless" イメージへ移行すれば、シェルやパッケージマネージャが除かれ、エクスプロイトのブートストラップが格段に困難になります。

ネットワークファイアウォール

iptablesnftables で入出力接続を制限すれば、侵害されたコンテナが C2 サーバーと通信したり、内部ネットワーク内で横移動したりすることを防げます。

批判的視点と反論

主なエクスプロイト例は su を用いた root シェル取得に焦点を当てていますが、コミュニティの議論では Copy Fail の真の危険性はそれ以上に広範であると指摘されています。

"この脆弱性により、コンテナと共有すべきだった読み取り専用のものが実質的に書き込み可能になるため、影響範囲は多くのシナリオで非常に大きくなります。'su' の例ほど簡単に利用できなくても、リスクは依然として高いです。"

さらに、一部の研究者は Copy Fail がコンテナ間の横方向攻撃に利用できる可能性を指摘しています。もし二つのコンテナが同一のベースイメージ層を共有している場合、悪意あるコンテナはその共有層のファイルを書き換えて、同じ非特権ユーザーで実行されている別のコンテナを侵害できるかもしれません。

また、Linux カーネルの分離メカニズム(名前空間、seccomp など)は高セキュリティ環境に対して不十分であるという見解が増えており、MicroVM をより強固なセキュリティ境界として推奨する声もあります。

結論

Podman のルートレスアーキテクチャは、コンテナ root がホスト root になることを防ぐ点で、標準的な rootful Docker インストールに比べてはるかに優れたセキュリティ姿勢を提供します。しかし、Copy Fail が示すように、コンテナは無敵の壁ではありません。ルートレス実行に加えてケーパビリティの削除、no‑new‑privileges オプション、最小イメージの採用を組み合わせることで、侵害時の影響範囲を大幅に縮小できます。最終的に最も効果的な防御は、タイムリーなカーネルパッチ適用と、コンテナ境界が最終的に破られることを前提とした多層的なセキュリティアプローチです。

Sources