
Eine Sprache und Bibliothek zur Festlegung von Syscall-Filterungsrichtlinien.
Kafel ist eine Sprache und Bibliothek zur Angabe von Syscall-Filterrichtlinien. Die Richtlinien werden in BPF-Code kompiliert, der mit seccomp-filter verwendet werden kann.
Dies ist KEIN offizielles Google-Produkt.
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);
Zur Definition von Richtlinien wird eine einfache Sprache verwendet.
Eine Richtliniendatei besteht aus Anweisungen.
Eine Anweisung kann sein:
Richtliniendefinitionsanweisungen, die auf Dateiebene platziert werden, werden der impliziten obersten Richtlinie hinzugefügt. Diese oberste Richtlinie wird kompiliert.
DEFAULT the_action
Legt fest, dass die Aktion the_action ausgeführt werden soll, wenn keine Regel zutrifft.
Die Standardaktion darf nur einmal angegeben werden.
Wenn die Richtliniendatei keine Standardaktionen angibt, ist die Standardaktion KILL
Kafel unterstützt die folgenden Zahlenschreibweisen:
420xfa107770b10101Sie können numerische Konstanten definieren, um Ihre Richtlinien lesbarer zu machen. Konstantendefinitionen können fast überall in der Richtliniendatei platziert werden. Eine Konstantendefinition darf nicht innerhalb einer Richtliniendefinition platziert werden. Die definierten Konstanten können dann überall dort verwendet werden, wo eine Zahl erwartet wird.
#define MYCONST 123
Eine Richtliniendefinition ist eine Liste von Aktionsblöcken und Verwende-Anweisungen, getrennt durch Kommas.
samples/ enthält einige Beispielrichtlinien, die die unterstützten Funktionen demonstrieren.
Ein USE someOtherPolicy verhält sich so, als ob der Rumpf von someOtherPolicy an dieser Stelle
eingefügt worden wäre. Sie dürfen nur Richtlinien verwenden, die vor der Verwende-Anweisung definiert wurden.
Mit Verwende-Anweisungen können Sie sinnvolle Gruppen von Filterregeln erstellen, die Bausteine für größere Richtlinien sind.
Ein Aktionsblock besteht aus einem Ziel und einer Liste von Syscall-Übereinstimmungsregeln, getrennt durch Kommas.
Das Ziel der ersten übereinstimmenden Regel ist die Richtlinienentscheidung.
Die folgende Tabelle listet die Kafel-Ziele und ihre entsprechenden seccomp-filter Rückgabewerte auf.
Eine Regel besteht aus einem Syscall-Namen und einer optionalen Liste von booleschen Ausdrücken.
Liste von booleschen Ausdrücken, getrennt durch Kommas.
Ein Komma ist semantisch äquivalent zu ||, hat aber die niedrigste Priorität,
daher kann es leichter zu lesen sein.
Normalerweise werden Syscalls durch ihre Namen angegeben, wie im Linux-Kernel definiert.
Sie können jedoch auch benutzerdefinierte Syscalls filtern, die nicht in der standardmäßigen
Syscall-Liste enthalten sind.
Sie können entweder eine Konstante definieren und sie anstelle des Syscall-Namens verwenden oder
das Schlüsselwort SYSCALL nutzen.
#define mysyscall -1
POLICY my_const {
ALLOW {
mysyscall
}
}
POLICY my_literal {
ALLOW {
SYSCALL[-1]
}
}
Sie können eine Syscall-Regel auf eine Teilmenge von Architekturen beschränken, indem Sie den ON-Guard
verwenden. Der Guard akzeptiert entweder einen einzelnen Architekturnamen oder eine durch Kommas getrennte,
in geschweifte Klammern eingeschlossene Liste. Die Namen entsprechen den Zielen, die von
kafel_set_target_archs erkannt werden (z. B. x86_64, x86, arm, aarch64,
mips64, riscv64, m68k).
ALLOW {
io_uring_setup ON x86_64,
arm_fadvise64_64 ON arm
}
Wenn für eine Architektur außerhalb des Guards kompiliert wird, wird die Syscall-Regel ignoriert, sodass architekturübergreifende Richtlinien nicht mehr ganze Richtlinien duplizieren müssen, nur um Unterschiede in der Syscall-Verfügbarkeit zu berücksichtigen.
Boolesche Ausdrücke werden verwendet, um Syscalls basierend auf ihren Argumenten zu filtern. Ein Ausdruck ähnelt der C-Syntax, außer dass es keine arithmetischen Operatoren gibt.
some_syscall(first_arg, my_arg_name) { first_arg == 42 && my_arg_name != 42 }
Bitweise Und- (&) und Oder-Operatoren („|“) können verwendet werden, um Flags zu testen.
mmap { (prot & PROT_EXEC) == 0 },
open { flags == O_RDONLY|O_CLOEXEC }
Sie müssen Argumente für bekannte Syscalls nicht deklarieren, sondern können einfach deren
reguläre Namen verwenden, wie im Linux-Kernel und in den man-Seiten angegeben.
write { fd == 1 }
Um die Wiederverwendung und Zusammensetzung von Richtlinien zu vereinfachen, bietet Kafel Include-Unterstützung.
#include "some_other_file.policy"
Kafel sucht nach enthaltenen Dateien nur in Verzeichnissen, die explizit zu den Suchpfaden hinzugefügt wurden.
kafel_add_include_search_path(ctxt, "includes/path");
Fügt includes/path zu den Suchpfaden hinzu – die Beispiel-Include-Direktive bezieht sich dann
auf includes/path/some_other_file.policy.
Die Include-Direktive wird durch einen Zeilenumbruch oder ein Semikolon beendet. Mehrere Dateien, getrennt durch Leerzeichen, können in einer Direktive angegeben werden.
#include "first.policy" "second.policy"; #include "third.policy"
Bei Verwendung mit nsjail ermöglicht der folgende Befehl die Erstellung einer ziemlich eingeschränkten Umgebung für Ihre 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 |