
Jailerは、eBPFベースのプロセス隔離システムであり、Linuxに強制アクセス制御(MAC)を提供します。BPF task_storageマップを使用してプロセスを追跡し、ファイルアクセス、ネットワーク操作、プロセス実行に対するロールベースのポリシーを適用します。
警告: このプロジェクトは活発に開発中であり、本番環境での使用には適していません。API、ポリシー形式、動作は予告なく変更される可能性があります。テストおよび実験目的でのみ使用してください。
注記: これは独立した実装であり、Metaのソリューションと同じプロジェクトではありません。BpfJailerは機能的に類似しており、Meta の Liam Wisehart、Justin Nga、Carl El Khoury、Mansee Chadha による元のアイデアと設計に触発されていますが、これは独立して開発された別のコードベースです。この作品に影響を与えたビジョンと基礎概念に感謝の意を表します。
Jailerは、Linux向けの強制アクセス制御(MAC)を提供するeBPFベースのプロセス隔離システムです。BPF task_storageマップを使用してプロセスを追跡し、ファイルアクセス、ネットワーク操作、プロセス実行に関するロールベースのポリシーを適用します。
| 機能 | ステータス | 説明 |
|---|---|---|
| プロセス追跡 | ✅ 動作中 | task_storage BPFマップを使用してプロセスを追跡 |
| ソケット登録 | ✅ 動作中 | UnixソケットAPIを介してプロセスが登録 |
| ロールベースのポリシー | ✅ 動作中 | 制限ロールと許可ロール |
| ファイルアクセス制御 | ✅ 動作中 | ファイルオープン操作のブロック/許可 |
| 隔離の継承 | ✅ 動作中 | 子プロセスは親の隔離を継承 |
| ネットワーク制御 | ✅ 動作中 | ソケットbind/connectのブロック/許可 |
| ポート/プロトコルフィルタリング | ✅ 動作中 | ポート単位のTCP/UDP許可/拒否ルール |
| 実行制御 | ✅ 動作中 | プロセス実行のブロック/許可 |
| パス一致 | ✅ 動作中 | キャッシュ無効化を伴うdentryウォーク |
| 署名済みバイナリ | 🚧 スタブ | バイナリ署名検証(未実装) |
| 代替登録 | ✅ 動作中 | 実行ファイル、cgroup、またはxattrによる自動登録 |
| デーモンレスモード | ✅ 動作中 | ブートストラップバイナリが早期ブート時にプログラムをピン留め |
| 監査イベント | ✅ 動作中 | systemd-journald統合用のperfバッファ |

BPF_MAP_TYPE_TASK_STORAGEサポートのため)# 現在のカーネル設定を確認
zcat /proc/config.gz 2>/dev/null || cat /boot/config-$(uname -r)
必要なオプション:
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_LSM=y
CONFIG_DEBUG_INFO_BTF=y
BPF LSMはカーネルブートパラメータで有効にする必要があります:
# BPF LSMがアクティブか確認
cat /sys/kernel/security/lsm
# リストに "bpf" が含まれている必要があります
# 含まれていない場合、カーネルブートパラメータに追加:
# /etc/default/grub を編集し、GRUB_CMDLINE_LINUX に以下を追加:
# lsm=lockdown,capability,landlock,yama,apparmor,bpf
# その後grubを更新して再起動:
sudo update-grub
sudo reboot
Ubuntu/Debianシステムでは、以下も使用できます:
# BPF LSMを有効化するスクリプトを作成
cat > /tmp/enable_bpf_lsm.sh << 'EOF'
#!/bin/bash
GRUB_FILE="/etc/default/grub"
if grep -q "lsm=" "$GRUB_FILE"; then
sudo sed -i 's/lsm=[^""]*/lsm=lockdown,capability,landlock,yama,apparmor,bpf/' "$GRUB_FILE"
else
sudo sed -i 's/GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 lsm=lockdown,capability,landlock,yama,apparmor,bpf"/' "$GRUB_FILE"
fi
sudo update-grub
echo "BPF LSMが有効化されました。再起動してください。"
EOF
chmod +x /tmp/enable_bpf_lsm.sh
sudo /tmp/enable_bpf_lsm.sh
# Rustをインストール
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# ビルド依存関係をインストール(Ubuntu/Debian)
sudo apt-get install -y clang llvm libelf-dev linux-headers-$(uname -r)
# RustにBPFターゲットを追加
rustup target add bpfel-unknown-none
cd bpfjail
# BPFプログラムをビルド
cd bpfjailer-bpf && cargo build --release && cd ..
# デーモンとクライアントをビルド
cargo build --release
# rootとして実行(存在すれば config/policy.json を読み込み)
sudo RUST_LOG=info ./target/release/bpfjailer-daemon
期待される出力:
[INFO] BpfJailer daemon starting...
[INFO] Loading BpfJailer eBPF programs with libbpf-rs...
[INFO] ✓ pending_enrollments map available for enrollment
[INFO] ✓ network_rules map available for port/protocol filtering
[INFO] ✓ task_storage map created successfully
[INFO] ✓ Program task_alloc attached
[INFO] ✓ Program file_open attached
[INFO] ✓ Program socket_bind attached
[INFO] ✓ Program socket_connect attached
[INFO] ✓ Program bprm_check_security attached
[INFO] Initialized with default roles: restricted (1), permissive (2)
[INFO] Loaded policy from config/policy.json
[INFO] Loaded 5 roles
[INFO] Enrollment server listening on /run/bpfjailer/enrollment.sock
# 隔離なしで脆弱性テストを実行(攻撃が成功することを確認)
sudo python3 tests/vulnerable_apps/run_tests.py
# 制限ロールで脆弱性テストを実行(攻撃がブロックされることを確認)
sudo python3 tests/vulnerable_apps/run_tests.py --role 1
# 特定のテストを実行
sudo python3 tests/vulnerable_apps/run_tests.py --role 1 --test path
# 利用可能なテストとロールを一覧表示
sudo python3 tests/vulnerable_apps/run_tests.py --list
制限ロールでの出力例:
============================================================
TEST: Path Traversal / Arbitrary File Read
============================================================
Attempting to read /etc/passwd via path traversal...
BLOCKED - Permission denied (BpfJailer blocked file access)
============================================================
TEST: Command Injection
============================================================
Attempting command injection...
BLOCKED - Permission denied (BpfJailer blocked exec)
============================================================
TEST: Reverse Shell / Data Exfiltration
============================================================
Test 1: Reverse shell connection to 127.0.0.1:4444
BLOCKED - Permission denied (BpfJailer blocked connect)
#!/usr/bin/env python3
import socket
import json
import os
# デーモンに接続
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/run/bpfjailer/enrollment.sock")
# 制限ロール(ID 1)で登録
request = {"Enroll": {"pod_id": 1, "role_id": 1}}
sock.send((json.dumps(request) + "\n").encode())
response = sock.recv(4096).decode()
print(f"登録: {response}")
sock.close()
# ファイルを読み取ろうとする(ブロックされるはず)
try:
open("/etc/passwd").read()
print("ファイルアクセス: 許可")
except PermissionError:
print("ファイルアクセス: ブロック")
BpfJailerはJSONポリシーファイルからロールを読み込みます。デーモンは次の順序でポリシーファイルを検索します:
$BPFJAILER_POLICY 環境変数/etc/bpfjailer/policy.jsonconfig/policy.json(ワーキングディレクトリからの相対パス){
"roles": {
"restricted": {
"id": 1,
"name": "restricted",
"flags": {
"allow_file_access": false,
"allow_network": false,
"allow_exec": false
},
"network_rules": []
},
"webserver": {
"id": 3,
"name": "webserver",
"flags": {
"allow_file_access": true,
"allow_network": true,
"allow_exec": false
},
"network_rules": [
{"protocol": "tcp", "port": 80, "allow": true},
{"protocol": "tcp", "port": 443, "allow": true}
]
}
},
"pods": []
}
BpfJailerはポート単位のTCP/UDPルールによる細かいネットワーク制御をサポートしています。
network_rules マップ:
キー: { role_id, port, protocol, direction }
値: allowed (1) または denied (0)
// デーモンコード内:
use bpfjailer_daemon::process_tracker::{PROTO_TCP, DIR_CONNECT};
// TCP接続をポート80と443のみ許可
process_tracker.add_network_rule(RoleId(1), 80, PROTO_TCP, DIR_CONNECT, true)?;
process_tracker.add_network_rule(RoleId(1), 443, PROTO_TCP, DIR_CONNECT, true)?;
ポート範囲は port_start と port_end を使用してpolicy.jsonで指定できます:
{
"network_rules": [
{"protocol": "tcp", "port": 443, "allow": true},
{"protocol": "tcp", "port_start": 8000, "port_end": 8100, "allow": true}
]
}
| フィールド | 説明 |
|---|---|
port | 単一ポート(例: 80) |
port_start + port_end | ポート範囲(例: 8000-8100) |
注記: 大きな範囲(1000ポート超)は多くのBPFマップエントリを消費します。1000ポートを超える範囲に対しては警告が記録されます。
┌─────────────────────────────────────────────────────────────┐
│ ユーザ空間 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ クライアント │───▶│ bpfjailer-daemon │ │
│ │ (登録) │ │ │ │
│ └─────────────┘ │ - PolicyManager │ │
│ │ - ProcessTracker│ │
│ │ - EnrollmentSvr │ │
│ └────────┬─────────┘ │
│ │ 書き込み │
│ ▼ │
├─────────────────────────────────────────────────────────────┤
│ BPFマップ │
│ ┌──────────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │pending_enrollments│ │ role_flags │ │ task_storage │ │
│ │ (PID → info) │ │ (role→flags)│ │(task→info) │ │
│ └──────────────────┘ └─────────────┘ └──────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ BPF LSMフック │
│ ┌────────────┐ ┌───────────┐ ┌─────────────┐ ┌──────────┐ │
│ │ task_alloc │ │ file_open │ │socket_bind/ │ │bprm_check│ │
│ │(継承 │ │(移行 │ │ connect │ │_security │ │
│ │ + 初期化) │ │ + 検査) │ │ (検査) │ │ (検査) │ │
│ └────────────┘ └───────────┘ └─────────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
/run/bpfjailer/enrollment.sock に接続{"Enroll": {"pod_id": N, "role_id": M}}pending_enrollments[PID] と role_flags[role_id] に書き込みtask_storage に移行task_storage + role_flags を検査task_alloc フックを介して継承BpfJailerは2つのインストールモードをサポートしています:
実行中のデーモンを使用して登録とポリシー管理を行います:
# systemdサービスのインストール
sudo cp config/bpfjailer-daemon.service /etc/systemd/system/
sudo cp target/release/bpfjailer-daemon /usr/sbin/
sudo mkdir -p /etc/bpfjailer
sudo cp config/policy.json /etc/bpfjailer/
# 有効化して起動
sudo systemctl daemon-reload
sudo systemctl enable bpfjailer-daemon
sudo systemctl start bpfjailer-daemon
特長:
早期ブート時にBPFプログラムをロードして終了します。プログラムは再起動までアクティブのままです:
# ブートストラップサービスのインストール
sudo cp config/bpfjailer-bootstrap.service /etc/systemd/system/
sudo cp target/release/bpfjailer-bootstrap /usr/sbin/
sudo mkdir -p /etc/bpfjailer
sudo cp config/policy.json /etc/bpfjailer/
# 有効化(次のブートで実行)
sudo systemctl daemon-reload
sudo systemctl enable bpfjailer-bootstrap
# または今すぐ手動で実行
sudo bpfjailer-bootstrap
特長:
/sys/fs/bpf/bpfjailer/ にピン留めピン留めされたプログラムの確認:
ls -la /sys/fs/bpf/bpfjailer/
ls -la /sys/fs/bpf/bpfjailer/maps/
ls -la /sys/fs/bpf/bpfjailer/progs/
監査イベントの表示:
# イベントはperfバッファに出力され、journaldが取得
journalctl -f | grep bpfjailer
# カーネルバージョンの確認(5.11以上が必要)
uname -r
# BPF LSMがアクティブか確認
cat /sys/kernel/security/lsm | grep bpf
# BTFが利用可能か確認
ls -la /sys/kernel/btf/vmlinux
# BPFプログラムをロードできるか確認
sudo bpftool prog list
# ケーパビリティの確認
sudo capsh --print | grep cap_bpf
# デーモンがrootとして実行されていることを確認
ps aux | grep bpfjailer
# ソケットのパーミッション確認
ls -la /run/bpfjailer/enrollment.sock
Unixソケット登録に加えて、BpfJailerは以下に基づく自動登録をサポートしています:
特定のバイナリを実行するすべてのプロセスを自動登録:
{
"exec_enrollments": [
{
"executable_path": "/usr/bin/nginx",
"pod_id": 1000,
"role": "webserver"
}
]
}
任意のプロセスが /usr/bin/nginx を実行すると、自動的に webserver ロールで登録されます。これは実行ファイルのinodeで照合されるため、シンボリックリンクやハードリンクも正しく処理されます。
特定のcgroup内のすべてのプロセスを自動登録:
{
"cgroup_enrollments": [
{
"cgroup_path": "/sys/fs/cgroup/bpfjailer/sandbox",
"pod_id": 2000,
"role": "sandbox"
}
]
}
cgroupを作成し、プロセスをその中に移動:
# cgroupを作成
sudo mkdir -p /sys/fs/cgroup/bpfjailer/sandbox
# プロセスをcgroupに移動
echo $$ | sudo tee /sys/fs/cgroup/bpfjailer/sandbox/cgroup.procs
# プロセスは自動的にsandboxロールで登録される
実行ファイルに拡張属性を設定して登録情報を付加:
# 登録xattrを設定
sudo setfattr -n user.bpfjailer.pod_id -v $(printf '\x01\x00\x00\x00\x00\x00\x00\x00') /path/to/binary
sudo setfattr -n user.bpfjailer.role_id -v $(printf '\x03\x00\x00\x00') /path/to/binary
# xattrを確認
getfattr -d /path/to/binary
exec時(bprm_check_security LSMフック):
exec_enrollment マップにあるかチェックcgroup_enrollment マップにあるかチェックtask_storage に pod_id と role_id を設定登録は task_alloc フックを介してfork/execを通じて永続化
ポリシールール(ネットワーク、パス、exec)は role_id に基づいて適用
GPL-2.0(BPFプログラムに必要なライセンス)
| テスト | 脆弱性 | 緩和するロール |
|---|
path_traversal | ../ による任意ファイル読み取り | restricted, isolated |
command_injection | シェルコマンド実行 | restricted, webserver, isolated |
reverse_shell | 攻撃者へのアウトバウンド接続 | restricted, isolated |
ssrf | 内部サービス/クラウドメタデータへのアクセス | restricted, isolated |
arbitrary_write | 機密パスへの書き込み | restricted |
crypto_miner | ダウンロード + 実行 + プールへの接続 | restricted, webserver |
privilege_escalation | shadow読み取り、sudoers書き込み | restricted |
| フラグ | 説明 |
|---|
allow_file_access | ファイルオープン操作を許可 |
allow_network | ソケットbind/connectを許可 |
allow_exec | プロセス実行を許可 |
allow_setuid | setuid操作を許可 |
allow_ptrace | ptrace操作を許可 |
| ロールID | 名前 | ファイルアクセス | ネットワーク | 実行 |
|---|
| 1 | restricted | ブロック | ブロック | ブロック |
| 2 | permissive | 許可 | 許可 | 許可 |
| 3 | webserver | 許可 | ポート80, 443, 8080 | ブロック |
| 4 | database | 許可 | ポート5432, 6379 | ブロック |
| 5 | isolated | 許可 | ブロック | ブロック |
| 6 | web_with_db | 許可 | ポート80, 443, 5432, 3306, 6379 | ブロック |
| 7 | worker | 許可 | ポート443, 5432, 6379, 5672 | 許可 |
| 定数 | 値 | 説明 |
|---|
PROTO_TCP | 6 | TCPプロトコル |
PROTO_UDP | 17 | UDPプロトコル |
DIR_BIND | 0 | socket bind() |
DIR_CONNECT | 1 | socket connect() |
| 項目 | デーモンモード | デーモンレスモード |
|---|
| 攻撃対象領域 | デーモン実行中 | 実行中のプロセスなし |
| 登録 | Unixソケット + 代替 | 代替のみ |
| ポリシー更新 | ホットリロード | 再起動が必要 |
| 監査ログ | デーモンがringbufを読み取り | perfバッファ経由のjournald |
| プログラム削除 | デーモン停止 | 再起動のみ |
| ブート順序 | network.target 後 | basic.target 前 |