Torna agli aggiornamenti
New releaseJul 27, 2026

Z-Jail v1.1.0

Un sandbox Linux leggero e multilivello che combina namespace, pivot_root, seccomp-bpf, riduzione delle capacità e un motore di verdetto basato su prove (Versione Pubblica di Truthimatics) per un'esecuzione sicura e verificabile del codice.

Condividi
Z-Jail

Z-Jail

Sandbox multistrato per l'esecuzione di codice nativo su Linux.
Sette livelli di difesa indipendenti — nessuna dipendenza esterna, binario PIE di circa 73 KiB.


┌──────────────────────────────────────────────────────┐
│                    Z-Jail                            │
├──────────────────────────────────────────────────────┤
│  Truthimatics PV  (motore di verdetto basato su prove) │
│  Namespaces       (mount, pid, net, ipc, uts)        │
│  pivot_root       (chroot potenziato)                │
│  Capacità         (elimina tutto, blocca securebits) │
│  NO_NEW_PRIVS     (nessuna escalation di privilegi)  │
│  seccomp-BPF      (whitelist: solo 15 syscall)       │
│  Audit            (logging JSON + hashing BLAKE2b)   │
└──────────────────────────────────────────────────────┘

Indice


Avvio Rapido

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

La directory --root deve contenere un filesystem minimo con il binario target e le sue dipendenze (per binari statici è sufficiente il binario stesso).


Perché Z-Jail

Le soluzioni di sandboxing esistenti fanno compromessi:

Z-JailFirecrackergVisorbwrapnsjail
Dipendenze esternezerolibc, seccompruntime Golibclibc, protobuf
Dimensione binario~73 KiB20+ MiB40+ MiB~70 KiB~1 MiB
Isolamento VMnosì (microVM)no (sandbox)nono
whitelist seccompnoopzionale
Hashing contenutonononono
Audit JSONnonoparziale
Complessità buildun makecomplessacomplessabanalemoderata

Z-Jail colma il divario tra bwrap (minimale, nessun seccomp di default) e nsjail (ricco di funzionalità, dipendenze pesanti). È progettato per pipeline CI, sfide CTF jail e valutazione leggera di codice dove serve difesa in profondità senza tirare dentro un runtime container.


Architettura

Flusso Dati

flowchart LR
    CLI[argomenti CLI] --> P[parse_args]
    P --> C{clone namespaces}
    C -->|figlio| CR[child_run]
    C -->|genitore| W[waitpid]
    CR --> RL[setrlimit]
    RL --> FD[chiudi fd >= 3]
    FD --> DUMP[PR_SET_DUMPABLE=0]
    DUMP --> PV[pivot_root]
    PV --> NNP[PR_SET_NO_NEW_PRIVS]
    NNP --> CAP[elimina capacità]
    CAP --> SC[seccomp-BPF]
    SC --> SIG[segnala genitore]
    SIG --> EX[execve target]
    W --> A[audit JSON]
    A --> EXIT[exit]

Ordine dei Livelli

Ogni livello è ordinato in modo che un livello successivo non possa essere annullato da uno precedente:

  1. setrlimit — limita CPU, spazio di indirizzi, numero di file, processi prima di qualsiasi altra cosa
  2. fd scrub — chiude tutti i fd ereditati tranne il pipe di report
  3. PR_SET_DUMPABLE=0 — disabilita core dump, blocca /proc/self/mem
  4. pivot_root — si distacca dal filesystem host; la vecchia root viene smontata lazy
  5. PR_SET_NO_NEW_PRIVS — niente setuid, niente escalation capset dopo questo punto
  6. drop_caps — azzera tutte le capacità, blocca securebits
  7. seccomp-BPF — limita le syscall alla sola whitelist
  8. segnala genitore — dice al genitore che la sandbox è pronta
  9. execve — sostituisce il processo con il binario target
sequenceDiagram
    participant P as Genitore
    participant C as Figlio
    P->>C: clone (NEWNS|NEWPID|NEWNET|NEWIPC|NEWUTS)
    Note over C: setrlimit(CPU, AS, NOFILE, NPROC)
    Note over C: close(tutti i fd > 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(tutti 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: scrivi audit JSON

Livelli

1. Truthimatics Public Version

Motore di verdetto basato su prove. Raccoglie osservazioni pesate sul binario eseguito e determina un verdetto finale (DETERMINISTIC, REJECT o UNCERTAIN). Ogni osservazione ha un peso; ogni singola osservazione con peso >50% del totale decide il verdetto.

2. Namespace

Vengono creati cinque namespace tramite clone():

NamespaceFlagScopo
MountCLONE_NEWNSAlbero del filesystem isolato
PIDCLONE_NEWPIDSpazio degli ID dei processi (il figlio è pid 1)
NetCLONE_NEWNETNessuna interfaccia di rete
IPCCLONE_NEWIPCNessuna memoria condivisa / semafori
UTSCLONE_NEWUTSHostname separato

Richiede CAP_SYS_ADMIN nel namespace iniziale.

3. pivot_root

Sostituisce la root del mount namespace con la directory --root:

  1. Bind-mount della directory root su se stessa (MS_BIND|MS_REC)
  2. pivot_root(new_root, put_old) — scambia l'albero dei mount
  3. chdir("/") — si sposta nella nuova root
  4. umount2("/.pivot_old", MNT_DETACH) — distacca la vecchia root
  5. rmdir("/.pivot_old") — pulizia

Questo è strettamente più forte di chroot(2) — non c'è modo per il processo in sandbox di scappare di nuovo alla root host, nemmeno con CLONE_NEWNS dall'interno della sandbox (cosa già bloccata da seccomp).

4. Capacità

Tutte le capacità vengono eliminate tramite:

capset(hdr, data)  // data = {0, 0, 0}
prctl(SECBIT_KEEP_CAPS_LOCKED | SECBIT_NO_SETUID_FIXUP | ...)

Il processo elimina setuid/setgid prima di capset in modo che il cambio di uid avvenga mentre CAP_SETUID è ancora attiva. Dopo capset, tutte le capacità sono sparite e i securebits sono bloccati — nessuna riattivazione è possibile.

5. NO_NEW_PRIVS

prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);

Impedisce al processo o ai suoi figli di ottenere nuovi privilegi tramite binari setuid, capacità dei file o transizioni LSM. Irreversibile.

6. seccomp-BPF (whitelist-v1)

Lista di consenso di 15 syscall — tutto ciò che non è nella lista riceve SECCOMP_RET_KILL:

SyscallNumeroNote
read0stdin
write1stdout/stderr + pipe di report
openat257accesso ai file (non open)
close3
lseek8
brk12gestione heap
mmap9argomenti limitati: flags & 4 == 0 (no MAP_SHARED), flags == 0x22 (MAP_PRIVATE|MAP_ANONYMOUS)
munmap11
execve59singola exec all'avvio
exit_group231uscita pulita del processo
rt_sigaction13gestori di segnali
rt_sigprocmask14mascheramento segnali
getrandom318fonte di numeri casuali
clock_gettime228temporizzazione
fstat5metadati file

Il filtro BPF viene generato dinamicamente: per ogni voce della whitelist, viene emessa una catena di salti che o permette (se la syscall corrisponde) o cade in KILL. L'architettura viene controllata prima (AUDIT_ARCH_X86_64).

Il filtro è verificato indipendentemente da un test standalone (tests/seccomp_filter_test.c, 8/8 passati) che fork+exec dei casi di test contro un vero prctl(PR_SET_SECCOMP) senza bisogno di root.

7. Audit

Ogni esecuzione produce un record JSON di audit:

{
  "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..."
}

Scritto in build/audits/<binary-name>.audit.json. Il content_fingerprint è un hash BLAKE2b-256 del binario target, calcolato dal genitore dopo che il figlio ha finito.


Utilizzo

z_jail --root=<dir> [--seccomp-enforce] [--self-hash=<hex>]
       [--quiet] [--verbose] -- <program> [args...]
FlagDescrizione
--root=<dir>Directory root della sandbox (obbligatorio)
--seccomp-enforceAbilita la whitelist di syscall seccomp-BPF
--self-hash=<hex>Verifica che il binario corrisponda all'hash BLAKE2b-256 atteso
--quietSopprime l'output di audit
--verboseAbilita il logging di debug
--versionMostra build ID (Z-Jail/v1+dev)
--helpMostra l'utilizzo ed esce

Esempi

# Esegue un binario statico con tutte le protezioni
sudo z_jail --root=./roots --seccomp-enforce -- bin/hello_static

# Esecuzione con verifica di integrità del binario
sudo z_jail --root=./roots --seccomp-enforce \
  --self-hash=$(sha256sum z_jail | cut -c1-64) -- bin/program

# Modalità silenziosa (nessun JSON di audit)
sudo z_jail --root=./roots --quiet -- bin/program

Codici di Uscita

CodiceSignificato
0Figlio uscito normalmente (verdetto: DETERMINISTIC)
1Figlio ucciso da segnale (verdetto: REJECT)
2Self-hash: stringa esadecimale errata o file illeggibile
3Self-hash: mismatch (binario manomesso)
101Errore di setup del figlio (rlimit, ecc.)
102Installazione del filtro seccomp del figlio fallita
103execve del figlio fallita (binario non trovato, nessun permesso di exec)
104pivot_root del figlio fallito
105Eliminazione capacità del figlio fallita
125Creazione namespace fallita (eseguito come root? supporto kernel?)

Build e Installazione

Requisiti

  • Kernel Linux ≥ 5.4 (namespace, seccomp-BPF, pivot_root)
  • GCC ≥ 11 (testato su 11.4, 13.2, 15.2)
  • Nessuna libreria esterna — solo la toolchain C standard

Comandi

make              # builda z_jail (~130 KiB binario PIE)
make install      # installa in /usr/local/bin + pagina man
make clean        # rimuove artefatti di build
make dist         # crea tarball di rilascio
make check        # test fumogeno (--version + --help)

Il binario è compilato come Position Independent Executable con -fstack-protector-strong, -D_FORTIFY_SOURCE=2, RELRO completo e -z now.

Opzioni di Compilazione

make CC=clang CFLAGS="-O3 -march=native"   # compilatore/flags personalizzati

Test

Test Rapido (senza root)

# logica del filtro seccomp (8 test)
tests/build/seccomp_filter_test

# test a risposta nota BLAKE2b
tests/build/blake2b_known

Questi non necessitano di root e girano in meno di 100 ms.

Suite di Test Completa

make -C tests setup          # builda payload + root di test
sudo bash tests/run_tests.sh # 17 scenari

Richiede root per la creazione dei namespace. La suite di test copre:

#ScenarioTipoCosa testa
0blake2b_regressrisposta notaCorrettezza implementazione BLAKE2b
1seccomp_filterBPF standalone8 sotto-test della logica del filtro BPF
2hello_staticokEsecuzione binario statico di base
3hello_dynamicokBinario dinamico con ld-linux + libc
4execve_replacementokexecve nella sandbox (bloccata da seccomp)
5fd_inherited_readokstdin/stdout ereditati correttamente
6mmap_bad_flagsuccisommap con MAP_SHARED bloccato
7mmap_good_allowedokmmap con MAP_PRIVATE|ANONYMOUS permesso
8mmap_prot_execuccisommap con PROT_EXEC bloccato
9mmap_self_modifyuccisoCodice auto-modificante bloccato
10ptraceuccisoptrace bloccato
11socketuccisoCreazione socket bloccata
12chroot_escapeuccisosyscall chroot bloccata
13double_chrootuccisoDoppio chroot bloccato
14mount_replayuccisoSyscall mount bloccata
15cpu_exhaustuccisoRLIMIT_NPROC blocca fork bomb
16signal_parentuccisoSegnale al genitore bloccato
17self_hashokVerifica integrità binario

Prestazioni

Misurate su WSL2 (kernel 6.18.x-microsoft-standard-WSL2, Kali Linux), 50 campioni per strumento, carico di lavoro uniforme (un binario statico standalone il cui corpo è exit_group(0)), temporizzato con un harness getrusage. Vedi docs/BENCHMARKS.md per la metodologia.

MetricaValore
Dimensione binario~73 KiB non strippato (~28 KiB strippato)
Latenza media sandbox5.85 ± 1.45 ms (95% CI [5.45, 6.25])
RSS di picco1.62 MiB
Linee di codice (core)~900

Confronto diretto (stesso host, stessa metodologia)

StrumentoLatenza media ± dev.st.RSS di piccoseccomp predefinito
Z-Jail5.85 ± 1.45 ms1.62 MiB
bwrap3.56 ± 0.40 ms2.19 MiBno
nsjail8.98 ± 1.68 ms7.91 MiB

Nelle condizioni testate, Z-Jail ha il resident set più piccolo dei tre sandbox a livello di processo e una latenza tra bwrap e nsjail. Bubblewrap è il più veloce ma non esegue alcun filtraggio seccomp per default, quindi fa meno lavoro di setup; Z-Jail installa una whitelist seccomp, elimina le capacità ed esegue pivot_root ad ogni esecuzione. gVisor (runsc) va in segfault su questo kernel WSL2 e non è stato possibile misurarlo; Firecracker isola tramite una microVM (cold-boot della VM, una metrica diversa) ed è escluso dalla tabella fork-to-exec. Questi sono numeri su singolo host — trattateli come relativi.

Nota: le cifre documentate in precedenza (~8 ms, ~4 MiB, ~130 KiB) non corrispondono a una build make corrente (~73 KiB, ~5.9 ms) e sembrano essere state inaccurate; i numeri sopra sono stati rimisurati su questo codebase. Truthimatics è ancora parte del codice e non è stata rimossa (i vecchi report axiom_jail usavano semplicemente un nome di binario diverso e un harness). Un bug di propagazione dei mount trovato durante il benchmarking è stato corretto in src/sandbox.c (MS_REC|MS_PRIVATE prima del bind mount); il rimount ricorsivo contribuisce parte della latenza misurata.


Modello di Minaccia

In Ambito

  • Esecuzione arbitraria di codice nativo da parte di un payload non fidato
  • Fuga tramite chroot, mount, ptrace, socket, process_vm_writev
  • Fork bomb, esaurimento CPU (RLIMIT_CPU), esaurimento memoria (RLIMIT_AS)
  • Perdita di descrittori di file attraverso execve
  • Escalation tramite setuid / linker dinamico / LD_PRELOAD
  • Rimozione del filtro seccomp o riattivazione delle capacità

Fuori Ambito

  • Zero-day del kernel al di fuori della superficie di syscall consentita
  • Canali laterali hardware (Spectre, Meltdown)
  • Fuga da VM co-locata tramite mount condivisi /proc, /sys
  • Egresso di rete oltre quanto fornisce CLONE_NEWNET + socket bloccato
  • Esaurimento di risorse di sandbox fratelli (serve supporto cgroup)

Assunzioni

  • Il kernel host è Linux non modificato ≥ 5.4
  • clone(CLONE_NEWNS|CLONE_NEWPID|...) ha successo (richiede CAP_SYS_ADMIN)
  • Il binario target è collegato staticamente (o le librerie dinamiche sono disponibili in --root)
  • --self-hash=<hex> è configurato nei deployment di produzione

Documentazione

FileDescrizione
README.mdQuesto file
docs/ARCHITECTURE.mdPanoramica dell'architettura
docs/SANDBOX.mdInterni della sandbox strato per strato
docs/SECCOMP.mdProgettazione whitelist seccomp-BPF
docs/AUDIT_SCHEMA.mdRiferimento schema JSON di audit
docs/THREAT_MODEL.mdAssunzioni e ambito di sicurezza
docs/BLAKE2B.mdDettagli implementazione BLAKE2b
docs/BENCHMARKS.mdBenchmark di prestazioni
docs/BUILD.mdIstruzioni di build
docs/adr/Decisioni di architettura (4 documenti)
man/z_jail.1Pagina man
SECURITY.mdPolitica di sicurezza e segnalazione
CONTRIBUTING.mdCome contribuire
CHANGELOG.mdCronologia dei rilasci
ROADMAP.mdPiani futuri
TODO.mdLacune note e lavoro pianificato

Roadmap

v1 (corrente)

  • Sandbox con difesa in profondità a 7 livelli
  • Impronta digitale del contenuto BLAKE2b-256
  • Output JSON di audit
  • 17 scenari di test
  • Pagina man, completamenti (bash, zsh, fish)

v2 (pianificato)

  • File di policy seccomp esterno (JSON o sorgente BPF)
  • Flag di namespace personalizzabili per istanza sandbox
  • Whitelist di syscall configurabile tramite CLI
  • Hook di profilazione delle prestazioni per integrazione CI
  • Firma dei rilasci (minisign/signify)

Stato

build coverage


Licenza

MIT — vedi LICENSE per il testo completo.


Z-Jail è stato costruito su WSL2 (Kali Linux, GCC 15.2.0), con target Linux 5.4+. Mantenuto da Division-36. Segnala problemi al issue tracker.

Categorie