
Jailer هو نظام عزل عمليات قائم على eBPF يوفر التحكم الإجباري في الوصول (MAC) لنظام Linux. يتتبع العمليات باستخدام خرائط تخزين المهام BPF ويفرض سياسات قائمة على الأدوار على الوصول إلى الملفات، وعمليات الشبكة، وتنفيذ العمليات.
تحذير: هذا المشروع قيد التطوير المكثف وليس جاهزًا للاستخدام في الإنتاج. قد تتغير واجهات برمجة التطبيقات وتنسيقات السياسات والسلوك دون إشعار مسبق. استخدمه للاختبار والتجربة فقط.
ملاحظة: هذا تطبيق مستقل وليس نفس مشروع حل Meta. بينما BpfJailer مشابه وظيفيًا ومستوحى من الفكرة والتصميم الأصلي من قبل Liam Wisehart وJustin Nga وCarl El Khoury وMansee Chadha في Meta، إلا أن هذه قاعدة كود منفصلة تم تطويرها بشكل مستقل. نعرب عن امتناننا للرؤية والمفاهيم الأساسية التي ألهمت هذا العمل.
Jailer هو نظام عزل العمليات قائم على eBPF يوفر التحكم الإلزامي في الوصول (MAC) لنظام Linux. يتتبع العمليات باستخدام خرائط BPF task_storage ويفرض سياسات قائمة على الأدوار للوصول إلى الملفات وعمليات الشبكة وتنفيذ العمليات.

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)
# تثبيت هدف BPF لـ Rust
rustup target add bpfel-unknown-none
cd bpfjail
# بناء برامج BPF
cd bpfjailer-bpf && cargo build --release && cd ..
# بناء الخادم والعميل
cargo build --release
# تشغيل كجذر (يقوم بتحميل 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
مثال على المخرجات مع دور مقيد:
============================================================
اختبار: تجاوز المسار / قراءة ملف عشوائي
============================================================
محاولة قراءة /etc/passwd عبر تجاوز المسار...
مُحظَر - تم رفض الإذن (BpfJailer منع الوصول إلى الملف)
============================================================
اختبار: حقن الأوامر
============================================================
محاولة حقن الأوامر...
مُحظَر - تم رفض الإذن (BpfJailer منع التنفيذ)
============================================================
اختبار: شل عكسي / تسريب بيانات
============================================================
الاختبار 1: اتصال شل عكسي إلى 127.0.0.1:4444
مُحظَر - تم رفض الإذن (BpfJailer منع الاتصال)
#!/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")
# التسجيل بدور مقيد (المعرف 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 }
القيمة: مسموح (1) أو ممنوع (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)?;
يمكن تحديد نطاقات المنافذ في policy.json باستخدام port_start و port_end:
{
"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_storagetask_storage + role_flags للتنفيذtask_allocيدعم BpfJailer وضعين للتثبيت:
يستخدم خادمًا قيد التشغيل للتسجيل وإدارة السياسة:
# تثبيت خدمة 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
# التأكد من تشغيل الخادم كجذر
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
تعيين سمات ممتدة على الملفات القابلة للتنفيذ لمعلومات التسجيل:
# تعيين xattrs للتسجيل
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
# التحقق من xattrs
getfattr -d /path/to/binary
عند وقت التنفيذ (خطاف LSM bprm_check_security):
exec_enrollmentcgroup_enrollmenttask_storage مع pod_id و role_idيستمر التسجيل من خلال fork/exec عبر خطاف task_alloc
يتم تطبيق قواعد السياسة (الشبكة، المسار، التنفيذ) بناءً على role_id
GPL-2.0 (مطلوب لبرامج BPF)
| الميزة | الحالة | الوصف |
|---|
| تتبع العمليات | ✅ يعمل | يتتبع العمليات باستخدام خريطة BPF task_storage |
| تسجيل المقابس | ✅ يعمل | تسجل العمليات عبر واجهة برمجة تطبيقات مقبس Unix |
| سياسات قائمة على الأدوار | ✅ يعمل | أدوار مقيدة ومتسامحة |
| التحكم في الوصول إلى الملفات | ✅ يعمل | حظر/السماح بعمليات فتح الملفات |
| وراثة العزل | ✅ يعمل | ترث العمليات الفرعية عزل العملية الأم |
| التحكم في الشبكة | ✅ يعمل | حظر/السماح بربط المقابس/الاتصال بها |
| تصفية المنافذ/البروتوكولات | ✅ يعمل | قواعد السماح/المنع لكل منفذ TCP/UDP |
| التحكم في التنفيذ | ✅ يعمل | حظر/السماح بتنفيذ العمليات |
| مطابقة المسار | ✅ يعمل | التجول عبر dentry مع إبطال التخزين المؤقت |
| الملفات الثنائية الموقعة | 🚧 إطار عمل | التحقق من توقيع الملفات الثنائية (غير مطبق) |
| التسجيل البديل | ✅ يعمل | التسجيل التلقائي بواسطة الملف القابل للتنفيذ أو cgroup أو xattr |
| وضع بدون خادم | ✅ يعمل | يقوم الملف الثنائي للتشغيل بتثبيت البرامج في وقت التشغيل المبكر |
| أحداث التدقيق | ✅ يعمل | مخزن perf للتكامل مع systemd-journald |
| الاختبار | الثغرة | يتم التخفيف بواسطة |
|---|
path_traversal | قراءة ملف عشوائي عبر ../ | مقيد، معزول |
command_injection | تنفيذ أوامر شل | مقيد، خادم ويب، معزول |
reverse_shell | اتصالات صادرة إلى المهاجم | مقيد، معزول |
ssrf | الوصول إلى الخدمات الداخلية/بيانات السحابة الوصفية | مقيد، معزول |
arbitrary_write | الكتابة إلى مسارات حساسة | مقيد |
crypto_miner | تنزيل + تنفيذ + اتصال بمجمع التعدين | مقيد، خادم ويب |
privilege_escalation | قراءة shadow، كتابة sudoers | مقيد |
| العلامة | الوصف |
|---|
allow_file_access | السماح بعمليات فتح الملفات |
allow_network | السماح بربط/الاتصال بالمقابس |
allow_exec | السماح بتنفيذ العمليات |
allow_setuid | السماح بعمليات setuid |
allow_ptrace | السماح بعمليات ptrace |
| معرف الدور | الاسم | الوصول إلى الملفات | الشبكة | التنفيذ |
|---|
| 1 | مقيد | محظور | محظور | محظور |
| 2 | متسامح | مسموح | مسموح | مسموح |
| 3 | خادم ويب | مسموح | المنافذ 80، 443، 8080 | محظور |
| 4 | قاعدة بيانات | مسموح | المنافذ 5432، 6379 | محظور |
| 5 | معزول | مسموح | محظور | محظور |
| 6 | ويب مع قاعدة بيانات | مسموح | المنافذ 80، 443، 5432، 3306، 6379 | محظور |
| 7 | عامل | مسموح | المنافذ 443، 5432، 6379، 5672 | مسموح |
| الثابت | القيمة | الوصف |
|---|
PROTO_TCP | 6 | بروتوكول TCP |
PROTO_UDP | 17 | بروتوكول UDP |
DIR_BIND | 0 | bind() المقبس |
DIR_CONNECT | 1 | connect() المقبس |
| الجانب | وضع الخادم | وضع بدون خادم |
|---|
| سطح الهجوم | خادم قيد التشغيل | لا توجد عملية قيد التشغيل |
| التسجيل | مقبس Unix + البدائل | البدائل فقط |
| تحديثات السياسة | إعادة تحميل ساخنة | يتطلب إعادة تشغيل |
| تسجيل التدقيق | يقرأ الخادم ringbuf | journald عبر مخزن perf |
| إزالة البرامج | إيقاف الخادم | إعادة تشغيل فقط |
| ترتيب الإقلاع | بعد network.target | قبل basic.target |