
Z-Jail v1.1.0
صندوق رمل لينكس خفيف الوزن ومتعدد الطبقات يجمع بين namespaces وpivot_root وseccomp-bpf وإسقاط الصلاحيات، ومحرك قرارات قائم على الأدلة (النسخة العامة من Truthimatics) لتنفيذ كود آمن وقابل للتدقيق.
Z-Jail
حاجز حماية متعدد الطبقات لتنفيذ الأكواد الأصلية على لينكس.
سبع طبقات دفاع مستقلة — لا تبعيات خارجية، ملف ثنائي PIE بحجم ~73 KiB.
┌──────────────────────────────────────────────────────┐
│ Z-Jail │
├──────────────────────────────────────────────────────┤
│ Truthimatics PV (evidence-based verdict engine) │
│ Namespaces (mount, pid, net, ipc, uts) │
│ pivot_root (chroot on steroids) │
│ Capabilities (drop all, lock securebits) │
│ NO_NEW_PRIVS (no privilege escalation) │
│ seccomp-BPF (whitelist: 15 syscalls only) │
│ Audit (JSON logging + BLAKE2b hashing) │
└──────────────────────────────────────────────────────┘
جدول المحتويات
- البداية السريعة
- لماذا Z-Jail
- البنية
- الطبقات
- الاستخدام
- البناء والتثبيت
- الاختبار
- الأداء
- نموذج التهديد
- التوثيق
- خارطة الطريق
- الترخيص
البداية السريعة
git clone https://github.com/Division-36/Z-Jail.git
cd Z-Jail
make
sudo ./z_jail --root=/path/to/rootfs --seccomp-enforce -- /bin/ls
يجب أن يحتوي دليل --root على نظام ملفات أدنى يتضمن الملف الثنائي المستهدف وتبعياته (بالنسبة للملفات الثنائية ثابتة الربط، يكفي الملف الثنائي وحده).
لماذا Z-Jail
حلول العزل الحالية تنطوي على مقايضات:
| Z-Jail | Firecracker | gVisor | bwrap | nsjail | |
|---|---|---|---|---|---|
| التبعيات الخارجية | صفر | libc, seccomp | Go runtime | libc | libc, protobuf |
| حجم الملف الثنائي | ~73 KiB | 20+ MiB | 40+ MiB | ~70 KiB | ~1 MiB |
| عزل الجهاز الافتراضي | لا | نعم (microVM) | لا (بيئة عزل) | لا | لا |
| القائمة البيضاء لـ seccomp | نعم | لا | نعم | اختياري | نعم |
| تجزئة المحتوى | نعم | لا | لا | لا | لا |
| تدقيق JSON | نعم | لا | نعم | لا | جزئي |
| تعقيد البناء | أمر make واحد | معقّد | معقّد | بسيط | متوسط |
يسدّ Z-Jail الفجوة بين bwrap (بسيط، بدون seccomp افتراضياً) وnsjail (غني بالميزات، تبعيات ثقيلة). وهو مصمم لـخطوط CI، وتحديات CTF jail، وتقييم الأكواد خفيف الوزن حيث تحتاج إلى دفاع متعمق دون سحب بيئة تشغيل حاويات.
البنية
تدفق البيانات
flowchart LR
CLI[CLI args] --> P[parse_args]
P --> C{clone namespaces}
C -->|child| CR[child_run]
C -->|parent| W[waitpid]
CR --> RL[setrlimit]
RL --> FD[close fds >= 3]
FD --> DUMP[PR_SET_DUMPABLE=0]
DUMP --> PV[pivot_root]
PV --> NNP[PR_SET_NO_NEW_PRIVS]
NNP --> CAP[drop capabilities]
CAP --> SC[seccomp-BPF]
SC --> SIG[signal parent]
SIG --> EX[execve target]
W --> A[audit JSON]
A --> EXIT[exit]
ترتيب الطبقات
تُرتَّب الطبقات بحيث لا يمكن لطبقة لاحقة أن تُبطَل بواسطة طبقة سابقة:
- setrlimit — وضع سقف لوحدة المعالجة المركزية، ومساحة العناوين، وعدد الملفات، والعمليات قبل أي شيء آخر
- fd scrub — إغلاق كل واصفات الملفات الموروثة باستثناء أنبوب التقرير
- PR_SET_DUMPABLE=0 — تعطيل ملفات التفريغ الأساسية، وتأمين /proc/self/mem
- pivot_root — الانفصال عن نظام ملفات المضيف؛ إلغاء تحميل الجذر القديم بشكل كسول
- PR_SET_NO_NEW_PRIVS — لا setuid، ولا تصعيد
capsetبعد هذه النقطة - drop_caps — تصفير جميع القدرات، وقفل securebits
- seccomp-BPF — تقييد استدعاءات النظام إلى القائمة البيضاء فقط
- signal parent — إخبار العملية الأم بأن بيئة العزل جاهزة
- execve — استبدال العملية بالملف الثنائي المستهدف
sequenceDiagram
participant P as Parent
participant C as Child
P->>C: clone (NEWNS|NEWPID|NEWNET|NEWIPC|NEWUTS)
Note over C: setrlimit(CPU, AS, NOFILE, NPROC)
Note over C: close(all fds > 2)
Note over C: PR_SET_DUMPABLE=0
Note over C: pivot_root → chdir("/") → umount -l
Note over C: PR_SET_NO_NEW_PRIVS
Note over C: capset(all zero) + securebits
Note over C: seccomp(SECCOMP_MODE_FILTER, whitelist)
C->>P: write(pipe, ready=1)
Note over C: execve(target)
P->>P: waitpid
P->>P: write audit JSON
الطبقات
1. النسخة العامة من Truthimatics
محرك أحكام قائم على الأدلة. يجمع ملاحظات موزونة حول الملف الثنائي المنفَّذ ويحدد حكماً نهائياً (DETERMINISTIC أو REJECT أو UNCERTAIN). تحمل كل ملاحظة وزناً؛ أي ملاحظة واحدة بوزن أكبر من 50% من الإجمالي تحسم الحكم.
2. مساحات الأسماء
تُنشأ خمس مساحات أسماء عبر clone():
| مساحة الاسم | العلامة | الغرض |
|---|---|---|
| Mount | CLONE_NEWNS | شجرة نظام ملفات معزولة |
| PID | CLONE_NEWPID | فضاء معرفات العمليات (الطفل هو pid 1) |
| Net | CLONE_NEWNET | لا واجهات شبكة |
| IPC | CLONE_NEWIPC | لا ذاكرة مشتركة / إشارات semaphores |
| UTS | CLONE_NEWUTS | اسم مضيف منفصل |
يتطلب CAP_SYS_ADMIN في مساحة الأسماء الأولية.
3. pivot_root
يستبدل جذر مساحة أسماء التركيب بدليل --root:
- ربط-تركيب دليل الجذر على نفسه (
MS_BIND|MS_REC) pivot_root(new_root, put_old)— مبادلة شجرة التركيبchdir("/")— الانتقال إلى الجذر الجديدumount2("/.pivot_old", MNT_DETACH)— فصل الجذر القديمrmdir("/.pivot_old")— التنظيف
هذا أقوى بصرامة من chroot(2) — لا توجد طريقة للعملية المعزولة للهروب عائدة إلى جذر المضيف، حتى مع CLONE_NEWNS من داخل بيئة العزل (وهو محظور أصلاً بواسطة seccomp).
4. القدرات
تُسقَط جميع القدرات عبر:
capset(hdr, data) // data = {0, 0, 0}
prctl(SECBIT_KEEP_CAPS_LOCKED | SECBIT_NO_SETUID_FIXUP | ...)
تُسقط العملية setuid/setgid قبل capset بحيث يسري تغيير uid بينما ما تزال CAP_SETUID محتفظاً بها. بعد capset، تختفي جميع القدرات ويُقفل securebits — لا يمكن إعادة التمكين.
5. NO_NEW_PRIVS
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
يمنع العملية أو عملياتها الفرعية من اكتساب امتيازات جديدة عبر الملفات الثنائية setuid، أو قدرات الملفات، أو انتقالات LSM. لا رجعة فيه.
6. seccomp-BPF (whitelist-v1)
قائمة سماح من 15 استدعاء نظام — أي شيء غير موجود في القائمة يحصل على SECCOMP_RET_KILL:
| استدعاء النظام | الرقم | ملاحظات |
|---|---|---|
read | 0 | stdin |
write | 1 | stdout/stderr + أنبوب التقرير |
openat | 257 | الوصول إلى الملفات (وليس open) |
close | 3 | — |
lseek | 8 | — |
brk | 12 | إدارة الكومة |
mmap | 9 | مقيد بالوسائط: flags & 4 == 0 (بدون MAP_SHARED)، flags == 0x22 (MAP_PRIVATE|MAP_ANONYMOUS) |
munmap | 11 | — |
execve | 59 | تنفيذ واحد عند الإقلاع |
exit_group | 231 | خروج نظيف للعملية |
rt_sigaction | 13 | معالجات الإشارات |
rt_sigprocmask | 14 | حجب الإشارات |
getrandom | 318 | مصدر أرقام عشوائية |
clock_gettime | 228 | التوقيت |
fstat | 5 | بيانات الملف الوصفية |
يُولَّد مرشح BPF ديناميكياً: لكل إدخال في القائمة البيضاء، تُصدَر سلسلة قفزات تسمح بالاستدعاء (إذا تطابق استدعاء النظام) أو تصل إلى KILL. تُفحص البنية أولاً (AUDIT_ARCH_X86_64).
يُتحقَّق من المرشح بشكل مستقل عبر اختبار قائم بذاته (tests/seccomp_filter_test.c، نجاح 8/8) ينفّذ fork+execve لحالات اختبار مقابل prctl(PR_SET_SECCOMP) حقيقي دون الحاجة إلى صلاحيات الجذر.
7. التدقيق
كل عملية تنفيذ تُنتج سجلاً بتنسيق JSON:
{
"schema": "z-jail.audit/v1",
"build_id": "Z-Jail/v1+dev",
"timestamp": 1749000000,
"duration_ns": 8500000,
"executable": "/bin/ls",
"verdict": "DETERMINISTIC",
"exit_code": 0,
"sandbox": {
"seccomp_filter": "whitelist-v1",
"seccomp_whitelist_size": 15,
"seccomp_arg_rules_size": 2,
"namespaces": ["mount","pid","net","ipc","uts"],
"pivot_root": "/var/run/z-jail/roots/default",
"no_new_privs": true,
"capabilities_dropped": true
},
"content_fingerprint": "0e5751c026e543b2e8ab2eb06099daa1..."
}
يُكتب إلى build/audits/<binary-name>.audit.json. إن content_fingerprint هو تجزئة BLAKE2b-256 للملف الثنائي المستهدف، تُحسب بواسطة العملية الأم بعد انتهاء العملية الفرعية.
الاستخدام
z_jail --root=<dir> [--seccomp-enforce] [--self-hash=<hex>]
[--quiet] [--verbose] -- <program> [args...]
| العلامة | الوصف |
|---|---|
--root=<dir> | دليل جذر بيئة العزل (مطلوب) |
--seccomp-enforce | تفعيل القائمة البيضاء لاستدعاءات النظام seccomp-BPF |
--self-hash=<hex> | التحقق من تطابق الملف الثنائي مع تجزئة BLAKE2b-256 المتوقعة |
--quiet | إخفاء مخرجات التدقيق |
--verbose | تفعيل تسجيل التصحيح |
--version | إظهار معرّف البناء (Z-Jail/v1+dev) |
--help | إظهار الاستخدام والخروج |
أمثلة
# Run a static binary with all protections
sudo z_jail --root=./roots --seccomp-enforce -- bin/hello_static
# Run with binary integrity verification
sudo z_jail --root=./roots --seccomp-enforce \
--self-hash=$(sha256sum z_jail | cut -c1-64) -- bin/program
# Quiet mode (no audit JSON)
sudo z_jail --root=./roots --quiet -- bin/program
رموز الخروج
| الرمز | المعنى |
|---|---|
| 0 | خرجت العملية الفرعية بشكل طبيعي (الحكم: DETERMINISTIC) |
| 1 | قُتلت العملية الفرعية بإشارة (الحكم: REJECT) |
| 2 | التجزئة الذاتية: سلسلة hex غير صالحة أو ملف غير قابل للقراءة |
| 3 | التجزئة الذاتية: عدم تطابق (تم العبث بالملف الثنائي) |
| 101 | خطأ في إعداد العملية الفرعية (rlimit، إلخ) |
| 102 | فشل تثبيت مرشح seccomp لدى العملية الفرعية |
| 103 | فشل execve لدى العملية الفرعية (الملف الثنائي غير موجود، لا صلاحية تنفيذ) |
| 104 | فشل pivot_root لدى العملية الفرعية |
| 105 | فشل إسقاط القدرات لدى العملية الفرعية |
| 125 | فشل إنشاء مساحة الأسماء (هل تعمل بصلاحيات الجذر؟ هل يدعم النواة؟) |
البناء والتثبيت
المتطلبات
- نواة لينكس ≥ 5.4 (مساحات الأسماء، seccomp-BPF، pivot_root)
- GCC ≥ 11 (مُختبَر على 11.4، 13.2، 15.2)
- لا مكتبات خارجية — فقط سلسلة أدوات C القياسية
الأوامر
make # build z_jail (~130 KiB PIE binary)
make install # install to /usr/local/bin + man page
make clean # remove build artifacts
make dist # create release tarball
make check # smoke test (--version + --help)
يُبنى الملف الثنائي كملف تنفيذي مستقل عن الموقع (PIE) مع -fstack-protector-strong و-D_FORTIFY_SOURCE=2 وRELRO كامل و-z now.
خيارات زمن الترجمة
make CC=clang CFLAGS="-O3 -march=native" # custom compiler/flags
الاختبار
اختبار سريع (بدون صلاحيات الجذر)
# seccomp filter logic (8 tests)
tests/build/seccomp_filter_test
# BLAKE2b known-answer test
tests/build/blake2b_known
لا تحتاج هذه إلى صلاحيات الجذر وتُنجز في أقل من 100 ms.
مجموعة الاختبارات الكاملة
make -C tests setup # build payloads + test roots
sudo bash tests/run_tests.sh # 17 scenarios
يتطلب صلاحيات الجذر لإنشاء مساحات الأسماء. تغطي مجموعة الاختبارات:
| # | السيناريو | النوع | ماذا يختبر |
|---|---|---|---|
| 0 | blake2b_regress | known-answer | صحة تنفيذ BLAKE2b |
| 1 | seccomp_filter | standalone BPF | 8 اختبارات فرعية لمنطق مرشح BPF |
| 2 | hello_static | ok | تنفيذ ملف ثنائي ثابت أساسي |
| 3 | hello_dynamic | ok | ملف ثنائي ديناميكي مع ld-linux + libc |
| 4 | execve_replacement | ok | execve داخل بيئة العزل (محظور بواسطة seccomp) |
| 5 | fd_inherited_read | ok | stdin/stdout موروثان بشكل صحيح |
| 6 | mmap_bad_flags | killed | mmap مع MAP_SHARED محظور |
| 7 | mmap_good_allowed | ok | mmap مع MAP_PRIVATE|ANONYMOUS مسموح |
| 8 | mmap_prot_exec | killed | mmap مع PROT_EXEC محظور |
| 9 | mmap_self_modify | killed | الكود ذاتي التعديل محظور |
| 10 | ptrace | killed | ptrace محظور |
| 11 | socket | killed | إنشاء socket محظور |
| 12 | chroot_escape | killed | استدعاء نظام chroot محظور |
| 13 | double_chroot | killed | chroot المزدوج محظور |
| 14 | mount_replay | killed | استدعاء نظام mount محظور |
| 15 | cpu_exhaust | killed | RLIMIT_NPROC يمنع قنبلة fork |
| 16 | signal_parent | killed | الإشارة إلى العملية الأم محظورة |
| 17 | self_hash | ok | التحقق من سلامة الملف الثنائي |
الأداء
قِيس على WSL2 (النواة 6.18.x-microsoft-standard-WSL2، Kali Linux)، 50 عينة لكل أداة، حمولة موحدة (ملف ثنائي ثابت مستقل نصُّه exit_group(0))، مع ضبط الوقت عبر أداة getrusage. راجع docs/BENCHMARKS.md للمنهجية.
| المقياس | القيمة |
|---|---|
| حجم الملف الثنائي | ~73 KiB غير مجرد (~28 KiB مجرد) |
| متوسط زمن استجابة بيئة العزل | 5.85 ± 1.45 ms (فاصل ثقة 95% [5.45, 6.25]) |
| ذروة RSS | 1.62 MiB |
| أسطر الكود (الأساسي) | ~900 |
مقارنة مباشرة (نفس المضيف، نفس المنهجية)
| الأداة | متوسط زمن الاستجابة ± الانحراف المعياري | ذروة RSS | seccomp الافتراضي |
|---|---|---|---|
| Z-Jail | 5.85 ± 1.45 ms | 1.62 MiB | نعم |
| bwrap | 3.56 ± 0.40 ms | 2.19 MiB | لا |
| nsjail | 8.98 ± 1.68 ms | 7.91 MiB | نعم |
في الظروف المختبرة، يمتلك Z-Jail أصغر مجموعة مقيمة بين بيئات العزل الثلاث على مستوى العمليات، وزمن استجابة بين bwrap وnsjail. Bubblewrap هو الأسرع لكنه لا يجري أي ترشيح seccomp افتراضياً، لذا يؤدي عملاً تحضيرياً أقل؛ يثبّت Z-Jail قائمة seccomp بيضاء، ويسقط القدرات، وينفّذ pivot_root في كل تشغيل. يتعطل gVisor (runsc) بخطأ segfault على نواة WSL2 هذه ولم يمكن قياسه؛ يعزل Firecracker عبر microVM (إقلاع بارد للجهاز الافتراضي، وهو مقياس مختلف) ويُستبعد من جدول fork-to-exec. هذه أرقام من مضيف واحد — تعامل معها على أنها نسبية.
ملاحظة: الأرقام الموثقة سابقاً (~8 ms، ~4 MiB، ~130 KiB) لا تطابق بناء
makeحالياً (~73 KiB، ~5.9 ms) ويبدو أنها كانت غير دقيقة؛ أُعيد قياس الأرقام أعلاه على قاعدة الأكواد هذه. ما تزال Truthimatics جزءاً من الكود ولم تُحذف (تقاريرaxiom_jailالقديمة استخدمت ببساطة اسم ملف ثنائي وأداة مختلفة). أُصلح خطأ في انتشار التركيب (mount propagation) اكتُشف أثناء القياس فيsrc/sandbox.c(MS_REC|MS_PRIVATEقبل ربط-التركيب)؛ تساهم إعادة التركيب العودية بجزء من زمن الاستجابة المقاس.
نموذج التهديد
ضمن النطاق
- تنفيذ كود أصلي عشوائي بواسطة حمولة غير موثوقة
- الهروب عبر
chroot،mount،ptrace،socket،process_vm_writev - قنابل fork، واستنزاف وحدة المعالجة المركزية (
RLIMIT_CPU)، واستنزاف الذاكرة (RLIMIT_AS) - تسريب واصفات الملفات عبر
execve - تصعيد
setuid/ الموصول الديناميكي /LD_PRELOAD - إزالة مرشح seccomp أو إعادة تمكين القدرات
خارج النطاق
- ثغرات اليوم صفر في النواة خارج سطح استدعاءات النظام المسموح
- القنوات الجانبية للعتاد (Spectre، Meltdown)
- هروب جهاز افتراضي متجاور عبر تركيبات
/procو/sysالمشتركة - خروج الشبكة بما يتجاوز ما توفره
CLONE_NEWNET+ حظرsocket - تجويع الموارد لبيئات العزل الشقيقة (يتطلب دعم cgroup)
الافتراضات
- نواة المضيف لينكس غير معدَّلة ≥ 5.4
- نجاح
clone(CLONE_NEWNS|CLONE_NEWPID|...)(يتطلبCAP_SYS_ADMIN) - الملف الثنائي المستهدف مرتبط ثابتاً (أو المكتبات الديناميكية متوفرة في
--root) - ضبط
--self-hash=<hex>في عمليات النشر الإنتاجية
التوثيق
| الملف | الوصف |
|---|---|
README.md | هذا الملف |
docs/ARCHITECTURE.md | نظرة عامة على البنية |
docs/SANDBOX.md | دواخل بيئة العزل طبقة بطبقة |
docs/SECCOMP.md | تصميم القائمة البيضاء seccomp-BPF |
docs/AUDIT_SCHEMA.md | مرجع مخطط JSON للتدقيق |
docs/THREAT_MODEL.md | الافتراضات الأمنية والنطاق |
docs/BLAKE2B.md | تفاصيل تنفيذ BLAKE2b |
docs/BENCHMARKS.md | معايير الأداء |
docs/BUILD.md | تعليمات البناء |
docs/adr/ | سجلات القرارات المعمارية (4 مستندات) |
man/z_jail.1 | صفحة الدليل |
SECURITY.md | السياسة الأمنية والإبلاغ |
CONTRIBUTING.md | كيفية المساهمة |
CHANGELOG.md | سجل الإصدارات |
ROADMAP.md | الخطط المستقبلية |
TODO.md | الفجوات المعروفة والعمل المخطط |
خارطة الطريق
v1 (الحالي)
- بيئة عزل ذات دفاع متعمق من 7 طبقات
- بصمة محتوى BLAKE2b-256
- مخرجات تدقيق JSON
- 17 سيناريو اختبار
- صفحة دليل، وإكمال تلقائي (bash، zsh، fish)
v2 (المخطط)
- ملف سياسة seccomp خارجي (JSON أو مصدر BPF)
- علامات مساحة أسماء مخصصة لكل مثيل بيئة عزل
- قائمة بيضاء قابلة للضبط لاستدعاءات النظام عبر CLI
- خطافات قياس أداء لتكامل CI
- توقيع الإصدارات (minisign/signify)
الحالة
الترخيص
MIT — راجع LICENSE للنص الكامل.
بُني Z-Jail على WSL2 (Kali Linux، GCC 15.2.0)، مستهدفاً لينكس 5.4+. تتم الصيانة بواسطة Division-36. أبلغ عن المشكلات في متتبع المشكلات.