genpack documentation

exec-guard — 実行保護機能

Gentoo Linux をベースに、不変システムイメージを宣言的に生成・配布・起動するための自社開発ツールチェーンの資料です。

概要

exec-guard は、overlayfs の upper layer(書き込み可能層)に持ち込まれたバイナリや共有ライブラリの実行を eBPF LSM でブロックする genpack-init のオプション機能です。

genpack イメージのルートファイルシステムは SquashFS(lower layer、読み取り専用)と書き込み可能な upper layer の overlayfs で構成されています。exec-guard は「SquashFS イメージに含まれていないバイナリは実行させない」という信頼境界を、署名検証なしにカーネルレベルで強制します。

SquashFS (lower layer)  ←── 信頼済み。exec-guard が許可
書き込み可能層 (upper)  ←── 不審なバイナリが持ち込まれても実行・ロード不可

有効化

genpack.json5use セクションに exec-guard を指定します。

{
    profile: "paravirt",
    packages: [
        "genpack/paravirt",
    ],
    use: {
        "sys-apps/genpack-init": "exec-guard",
    },
}

ビルド時に clang と bpftool が必要です(genpack-overlay の ebuild が自動的に依存関係として追加します)。

動作の仕組み

genpack-init が PID 1 として起動した直後に以下を実行します。

  1. eBPF LSM プログラムのロード: /sys/kernel/btf/overlay の BTF 情報を使い、overlayfs の内部構造(ovl_inode.__upperdentry)を解釈できる BPF プログラムをカーネルにロード
  2. 信頼済みデバイスの登録: /run/initramfs/ro(SquashFS のマウントポイント)の st_dev を BPF マップに登録
  3. BPF リンクのピン留め: execl(systemd) 後も BPF プログラムが有効であり続けるよう /sys/fs/bpf/exec_guard/ にリンクをピン留め
  4. /usr の読み取り専用マウント: touch /usr/bin/bash のような誤操作で上書きコピーが発生し exec-guard が自分自身をブロックしてしまう事態を防ぐため、/usr を read-only bind mount

これ以降のすべての execve()mmap(PROT_EXEC) に対し、以下のルールが適用されます。

ファイルの出所 exec / dlopen
SquashFS lower layer 由来 許可
upper layer 由来(持ち込みファイル) EPERM で拒否

ELF バイナリのみが対象

execve() のチェックは ELF バイナリ(マジックバイト \x7fELF)に限定しています。シェバン(#!/bin/bash)付きスクリプトを bash ./script.sh のようにインタープリタ経由で実行する操作は制限されません(管理者による通常のスクリプト作業を妨げないための設計です)。

dlopen() 経由の共有ライブラリロードは mmap(PROT_EXEC) フックで捕捉し、ELF ファイルに関わらずチェックされます。

system.ini での制御

system.ini に以下を記載すると exec-guard を無効化できます。

exec_guard = false

この設定は /usr の read-only mount も含めてすべての exec-guard の動作を無効化します。

監査ログ(audit)

exec-guard を有効にしたイメージには /etc/audit/rules.d/exec_guard.rules が自動的にインストールされます。auditd が起動するとこのルールが読み込まれ、ブロックされた execve() および mmap()key=exec_guard_deny でログに記録されます。

# 今回のブート分のみ表示
ausearch -k exec_guard_deny --interpret -ts boot | grep -v "^type=CONFIG_CHANGE"

出力例(exec ブロック):

type=SYSCALL ... syscall=execve success=no exit=-1 comm="bash" key="exec_guard_deny"
type=PATH ... name="/root/ls_copy" inode=84 dev=00:1c ...

出力例(dlopen ブロック):

type=SYSCALL ... syscall=mmap success=no exit=-1 comm="python3" key="exec_guard_deny"
type=MMAP fd=4 flags=0x812

key=exec_guard_deny のログが出た時点で upper layer への不審なバイナリ持ち込みが試みられたと判断できます。通常の運用ではこのキーのログはほぼ発生しないため、誤検知が少ない検知シグナルとして機能します。

セキュリティ上の位置づけ

exec-guard は「完全な防壁」ではなく、検知トラップとして捉えるのが適切です。

execve()EPERM で失敗する時点で、攻撃者には他の手段(シェルスクリプト実行、シグナル送信など)がすでにある可能性があります。exec-guard の価値は、攻撃ツールが自動的に試みる ELF バイナリの持ち込み実行を即座に audit ログに記録する点にあります。

exec-guard 自体を知らない攻撃者が一般的な Linux 環境を想定した手法で動作すると、高確率で exec_guard_deny の痕跡が残ります。

防御範囲

攻撃手法 対応
upper layer への ELF バイナリ持ち込み → execve ブロック+audit ログ
upper layer への .so 持ち込み → dlopen ブロック+audit ログ
touch /usr/bin/bash 等による誤コピーアップ /usr の ro mount で防止
シェバンスクリプトの直接 execve ブロック+audit ログ

対応しない範囲

攻撃手法 理由
bash ./evil.sh 等インタープリタ経由のスクリプト実行 スクリプトは execve されない(意図的な設計)
mmap(PROT_READ)mprotect(+EXEC) の 2 ステップ mmap_file フックで捕捉不可
カーネル脆弱性によるページキャッシュ改ざん カーネル自体の信頼が前提
anonymous mmap(PROT_EXEC) へのシェルコード書き込み・実行 ファイルを持たない匿名マッピングは mmap_file フックの対象外。塞ぐことは技術的には可能だが、Python・Java・Node.js 等の JIT コンパイラが同じ仕組みを正当な用途で使っており、どのパッケージが JIT を使うか実行前に把握することが難しいため、現実的ではない

適用できないアーティファクト

以下のようなソフトウェアを含むアーティファクトには exec-guard を適用できません。

これらは exec-guard の仕組みそのものと根本的に相容れません。exec-guard は「イメージ外から持ち込まれた ELF バイナリは信頼しない」という原則で動作しているため、正規の動作としてバイナリを外部から取り込むソフトウェアは必然的にブロックされます。

スクリプト(シェルスクリプト、Python スクリプトなど)をダウンロードして実行するだけであれば exec-guard の制約を受けないため、そのようなアーティファクトには適用可能です。

リカバリー

exec-guard が有効な状態で誤操作によりシステムが起動不能になった場合、/usr が read-only マウントされているため通常の操作による新たな問題の発生は防がれています。

それでも起動に問題が生じた場合は、ブートパーティション(FAT32)上の system.iniexec_guard = false を追記してください。ブートパーティションは他の OS や Live 環境からマウントできるため、システムが起動しない状態でも編集可能です。

# system.ini に追記
exec_guard = false

必要なカーネル設定

以下のカーネルオプションが必要です。Gentoo の標準カーネルでは通常すべて有効になっています。

オプション 用途
CONFIG_BPF_LSM=y BPF LSM サポート
CONFIG_LSM="...,bpf" BPF を LSM リストに含める
CONFIG_DEBUG_INFO_BTF=y BTF(BPF 型情報)生成
CONFIG_DEBUG_INFO_BTF_MODULES=y カーネルモジュールの BTF(overlay BTF に必要)
CONFIG_OVERLAY_FS=m または =y overlayfs(genpack の動作要件)

当社代表のデスクトップ(※)を常時ライブ配信中

※ライブ配信専用PC

OSSの検証や自社用ツールの開発といった公開できる作業に限り、 ライブ配信専用PC上で行っています。常時配信ですのでいつでもお気軽にチャットメッセージ(公開)を残していって下さい。