
Un linguaggio e una libreria per specificare politiche di filtraggio delle syscall.
Kafel è un linguaggio e una libreria per specificare politiche di filtraggio delle syscall. Le politiche vengono compilate in codice BPF che può essere utilizzato con seccomp-filter.
Questo NON è un prodotto ufficiale di Google.
struct sock_fprog prog;
kafel_ctxt_t ctxt = kafel_ctxt_create();
kafel_set_input_string(ctxt, seccomp_policy);
if (kafel_compile(ctxt, &prog)) {
fprintf(stderr, "policy compilation failed: %s", kafel_error_msg(ctxt));
kafel_ctxt_destroy(&ctxt);
exit(-1);
}
kafel_ctxt_destroy(&ctxt);
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
free(prog.filter);
struct sock_fprog prog;
if (kafel_compile_string(seccomp_policy, &prog)) {
fputs("policy compilation failed", stderr);
exit(-1);
}
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0);
free(prog.filter);
Viene utilizzato un linguaggio semplice per definire le politiche.
Un file di politica è composto da istruzioni.
Un'istruzione può essere:
Le istruzioni di definizione di politica poste nell'ambito del file saranno aggiunte alla politica implicita di livello superiore. Questa politica di livello superiore verrà compilata.
DEFAULT the_action
Specifica che l'azione the_action deve essere eseguita quando nessuna regola corrisponde.
L'azione predefinita deve essere specificata una sola volta.
Se il file di politica non specifica azioni predefinite, l'azione predefinita sarà KILL
Kafel supporta le seguenti notazioni numeriche:
420xfa107770b10101Puoi definire costanti numeriche per rendere le tue politiche più leggibili. Le definizioni di costanti possono essere poste quasi ovunque nel file di politica. Una definizione di costante non può essere posta all'interno di una definizione di politica. Le costanti definite possono quindi essere utilizzate ovunque ci si aspetti un numero.
#define MYCONST 123
Una definizione di politica è un elenco di blocchi di azione e istruzioni use separati da virgole.
samples/ contiene alcune politiche di esempio che dimostrano le funzionalità supportate.
Un USE someOtherPolicy si comporta come se il corpo di someOtherPolicy fosse incollato al suo posto.
Puoi utilizzare solo politiche definite prima dell'istruzione use.
Con le istruzioni use puoi creare gruppi significativi di regole di filtraggio che sono elementi costitutivi di politiche più grandi.
Un blocco di azione consiste in un target e un elenco di regole di corrispondenza delle syscall separate da virgole.
Il target della prima regola corrispondente è la decisione della politica.
La tabella seguente elenca i target Kafel e i corrispondenti valori di ritorno di seccomp-filter.
Una regola consiste in un nome di syscall e un elenco opzionale di espressioni booleane.
Elenco di espressioni booleane separate da virgole.
Una virgola è semanticamente equivalente a || ma ha la precedenza più bassa, quindi può essere più facile da leggere.
Normalmente le syscall sono specificate dai loro nomi come definiti nel kernel Linux.
Tuttavia, puoi anche filtrare syscall personalizzate che non sono nell'elenco standard delle syscall.
Puoi definire una costante e utilizzarla al posto del nome della syscall o utilizzare la parola chiave SYSCALL.
#define mysyscall -1
POLICY my_const {
ALLOW {
mysyscall
}
}
POLICY my_literal {
ALLOW {
SYSCALL[-1]
}
}
Puoi limitare una regola di syscall a un sottoinsieme di architetture utilizzando il guard ON.
Il guard accetta un singolo nome di architettura o un elenco separato da virgole racchiuso tra parentesi graffe.
I nomi corrispondono ai target riconosciuti da kafel_set_target_archs (ad esempio x86_64, x86, arm, aarch64, mips64, riscv64, m68k).
ALLOW {
io_uring_setup ON x86_64,
arm_fadvise64_64 ON arm
}
Quando si compila per un'architettura al di fuori del guard, la regola di syscall viene ignorata, quindi le politiche cross-architettura non devono più duplicare intere politiche solo per tenere conto delle differenze di disponibilità delle syscall.
Le espressioni booleane vengono utilizzate per filtrare le syscall in base ai loro argomenti. Un'espressione assomiglia alla sintassi del linguaggio C, tranne per il fatto che non ci sono operatori aritmetici.
some_syscall(first_arg, my_arg_name) { first_arg == 42 && my_arg_name != 42 }
Gli operatori bitwise and (&) e or ('|') possono essere utilizzati per testare i flag.
mmap { (prot & PROT_EXEC) == 0 },
open { flags == O_RDONLY|O_CLOEXEC }
Non è necessario dichiarare gli argomenti per syscall ben note, ma puoi semplicemente usare i loro nomi regolari come specificato nel kernel Linux e nelle pagine man.
write { fd == 1 }
Per semplificare il riutilizzo e la composizione delle politiche, kafel fornisce il supporto per l'inclusione.
#include "some_other_file.policy"
Kafel cerca i file inclusi solo nelle directory aggiunte esplicitamente ai percorsi di ricerca.
kafel_add_include_search_path(ctxt, "includes/path");
Aggiunge includes/path ai percorsi di ricerca - la direttiva include di esempio farà quindi riferimento a includes/path/some_other_file.policy.
La direttiva include termina con un newline o un punto e virgola. È possibile specificare più file, separati da spazi bianchi, in un'unica direttiva.
#include "first.policy" "second.policy"; #include "third.policy"
Quando utilizzato con nsjail, il seguente comando consente di creare un ambiente abbastanza vincolato per la tua shell
$ ./nsjail --chroot / --seccomp_string 'POLICY a { ALLOW { write, execve, brk, access, mmap, open, newfstat, close, read, mprotect, arch_prctl, munmap, getuid, getgid, getpid, rt_sigaction, geteuid, getppid, getcwd, getegid, ioctl, fcntl, newstat, clone, wait4, rt_sigreturn, exit_group } } USE a DEFAULT KILL' -- /bin/sh -i
[2017-01-15T21:53:08+0100] Mode: STANDALONE_ONCE
[2017-01-15T21:53:08+0100] Jail parameters: hostname:'NSJAIL', chroot:'/', process:'/bin/sh', bind:[::]:0, max_conns_per_ip:0, uid:(ns:1000, global:1000), gid:(ns:1000, global:1000), time_limit:0, personality:0, daemonize:false, clone_newnet:true, clone_newuser:true, clone_newns:true, clone_newpid:true, clone_newipc:true, clonew_newuts:true, clone_newcgroup:false, keep_caps:false, tmpfs_size:4194304, disable_no_new_privs:false, pivot_root_only:false
[2017-01-15T21:53:08+0100] Mount point: src:'/' dst:'/' type:'' flags:0x5001 options:''
[2017-01-15T21:53:08+0100] Mount point: src:'(null)' dst:'/proc' type:'proc' flags:0x0 options:''
[2017-01-15T21:53:08+0100] PID: 18873 about to execute '/bin/sh' for [STANDALONE_MODE]
/bin/sh: 0: can't access tty; job control turned off
$ set
IFS='
'
OPTIND='1'
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PPID='0'
PS1='$ '
PS2='> '
PS4='+ '
PWD='/'
$ id
Bad system call
$ exit
[2017-01-15T21:53:17+0100] PID: 18873 exited with status: 159, (PIDs left: 0)
| Kafel | seccomp-filter |
|---|
ALLOW | SECCOMP_RET_ALLOW |
LOG | SECCOMP_RET_LOG |
KILL, KILL_THREAD, DENY | SECCOMP_RET_KILL |
KILL_PROCESS | SECCOMP_RET_KILL_PROCESS |
USER_NOTIF | SECCOMP_RET_USER_NOTIF |
ERRNO(number) | SECCOMP_RET_ERRNO+number |
TRAP(number) | SECCOMP_RET_TRAP+number |
TRACE(number) | SECCOMP_RET_TRACE+number |