
Kafel は、システムコールフィルタリングポリシーを指定するための言語とライブラリです。 ポリシーは BPF コードにコンパイルされ、seccomp-filter と共に使用できます。
これは 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);
ポリシーを定義するために、シンプルな言語が使用されます。
ポリシーファイルはステートメントで構成されます。
ステートメントは次のいずれかです:
ファイルスコープに配置されたポリシー定義ステートメントは、暗黙のトップレベルポリシーに追加されます。 このトップレベルポリシーがコンパイルされます。
DEFAULT the_action
どのルールにも一致しなかった場合に the_action アクションを実行することを指定します。
デフォルトアクションは一度だけ指定する必要があります。
ポリシーファイルでデフォルトアクションが指定されていない場合、デフォルトアクションは KILL になります。
Kafel は以下の数値表記をサポートしています:
420xfa107770b10101ポリシーをより読みやすくするために、数値定数を定義できます。 定数定義はポリシーファイルのほぼどこにでも配置できます。 定数定義はポリシー定義の内部には配置できません。 定義された定数は、数値が期待される場所であればどこでも使用できます。
#define MYCONST 123
ポリシー定義は、アクションブロックと use ステートメントのリストをカンマで区切ったものです。
samples/ には、サポートされている機能を示すサンプルポリシーがいくつか含まれています。
USE someOtherPolicy は、someOtherPolicy の本体がその場所にペーストされたかのように動作します。use ステートメントより前に定義されたポリシーのみを使用できます。
use ステートメントを使用すると、より大きなポリシーの構成要素となる意味のあるフィルタリングルールのグループを作成できます。
アクションブロックは、ターゲットと、カンマで区切られたシステムコール一致ルールのリストで構成されます。
最初に一致したルールのターゲットがポリシーの決定となります。
次の表は、Kafel のターゲットとそれに対応する seccomp-filter の戻り値の一覧です。
ルールは、システムコール名と、オプションのブール式のリストで構成されます。
ブール式のリストはカンマで区切られます。カンマは意味的に || と同等ですが、優先順位が最も低いため、読みやすい場合があります。
通常、システムコールは Linux カーネルで定義された名前で指定されます。ただし、標準のシステムコールリストにない カスタムシステムコール をフィルタリングすることもできます。
定数を定義してシステムコール名の代わりに使用するか、SYSCALL キーワードを利用できます。
#define mysyscall -1
POLICY my_const {
ALLOW {
mysyscall
}
}
POLICY my_literal {
ALLOW {
SYSCALL[-1]
}
}
ON ガードを使用して、システムコールルールを一部のアーキテクチャに制限できます。ガードは単一のアーキテクチャ名、または波括弧で囲まれたカンマ区切りのリストを受け入れます。名前は kafel_set_target_archs が認識するターゲットに対応します(例:x86_64、x86、arm、aarch64、mips64、riscv64、m68k)。
ALLOW {
io_uring_setup ON x86_64,
arm_fadvise64_64 ON arm
}
ガード外のアーキテクチャ向けにコンパイルする場合、そのシステムコールルールは無視されるため、クロスアーキテクチャポリシーでシステムコールの可用性の違いを考慮してポリシー全体を複製する必要がなくなります。
ブール式は、引数に基づいてシステムコールをフィルタリングするために使用されます。式は C 言語の構文に似ていますが、算術演算子はありません。
some_syscall(first_arg, my_arg_name) { first_arg == 42 && my_arg_name != 42 }
ビット単位の AND (&) および OR (|) 演算子を使用してフラグをテストできます。
mmap { (prot & PROT_EXEC) == 0 },
open { flags == O_RDONLY|O_CLOEXEC }
よく知られたシステムコールの引数を宣言する必要はなく、Linux カーネルや man ページで指定されている通常の名前をそのまま使用できます。
write { fd == 1 }
ポリシーの再利用と構成を簡素化するために、kafel は include をサポートしています。
#include "some_other_file.policy"
Kafel は、検索パスに明示的に追加されたディレクトリ内のインクルードファイルのみを検索します。
kafel_add_include_search_path(ctxt, "includes/path");
includes/path を検索パスに追加します。上記の include ディレクティブは includes/path/some_other_file.policy を参照します。
include ディレクティブは改行またはセミコロンで終了します。1 つのディレクティブで、空白で区切られた複数のファイルを指定できます。
#include "first.policy" "second.policy"; #include "third.policy"
nsjail と組み合わせて使用すると、以下のコマンドでシェル用のかなり制限された環境を作成できます。
$ ./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 |