ここにあるのは、まさにseccompの使用例です。
seccompを使用すると、さまざまな方法でsyscallをフィルタリングできます。あなたはこのような状況でやりたいことは、右の後、あるfork()
インストールするには、seccomp
の使用を禁止するフィルタをopen(2)
、openat(2)
、socket(2)
(およびそれ以上)。これを行うには、次のようにします。
- まず、
seccomp_init(3)
のデフォルトの動作でを使用して、seccompコンテキストを作成しますSCMP_ACT_ALLOW
。
- 次に、
seccomp_rule_add(3)
拒否する各syscallを使用して、コンテキストにルールを追加します。を使用SCMP_ACT_KILL
して、syscallが試行された場合にプロセスをSCMP_ACT_ERRNO(val)
強制終了しerrno
たり、syscallを失敗させたりして、指定された値またはaction
マニュアルページで定義されている他の値を返すことができます。
- を使用
seccomp_load(3)
してコンテキストをロードして有効にします。
続行する前に、このようなブラックリストアプローチは一般にホワイトリストアプローチよりも弱いことに注意してください。これにより、明示的に許可されていないシステムコールが許可され、フィルターがバイパスされる可能性があります。実行したい子プロセスが悪意を持ってフィルターを回避しようとしていると思われる場合、またはどのsyscallが子に必要かをすでに知っている場合は、ホワイトリストアプローチの方が適切であり、上記の反対を行う必要があります。のデフォルトアクションでフィルタを作成しSCMP_ACT_KILL
、必要なsyscallsを許可しますSCMP_ACT_ALLOW
。コードに関しては、違いはごくわずかです(ホワイトリストはおそらく長くなりますが、手順は同じです)。
上記の例を次に示します(exit(-1)
単純にするために、エラーが発生した場合に備えています)。
#include <stdlib.h>
#include <seccomp.h>
static void secure(void) {
int err;
scmp_filter_ctx ctx;
int blacklist[] = {
SCMP_SYS(open),
SCMP_SYS(openat),
SCMP_SYS(creat),
SCMP_SYS(socket),
SCMP_SYS(open_by_handle_at),
// ... possibly more ...
};
// Create a new seccomp context, allowing every syscall by default.
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL)
exit(-1);
/* Now add a filter for each syscall that you want to disallow.
In this case, we'll use SCMP_ACT_KILL to kill the process if it
attempts to execute the specified syscall. */
for (unsigned i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
err = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i], 0);
if (err)
exit(-1);
}
// Load the context making it effective.
err = seccomp_load(ctx);
if (err)
exit(-1);
}
これで、プログラムで上記の関数を呼び出して、seccompフィルターを直後に適用できます。 fork()
。
child_pid = fork();
if (child_pid == -1)
exit(-1);
if (child_pid == 0) {
secure();
// Child code here...
exit(0);
} else {
// Parent code here...
}
seccompに関するいくつかの重要な注意事項:
- seccompフィルターは、一度適用されると、プロセスによって削除または変更することはできません。
- もし
fork(2)
またはclone(2)
フィルターによって許可されている許可されている、すべての子プロセスは同じフィルターによって制約されます。
- 場合は
execve(2)
許可され、既存のフィルタが呼び出しに渡って維持されますexecve(2)
。
- 場合は
prctl(2)
システムコールが許可され、プロセスは、さらにフィルタを適用することができます。