From bd3641981c23f5f3036a2096442385bf724cd5f2 Mon Sep 17 00:00:00 2001 From: Albert S Date: Mon, 6 Jun 2022 10:07:11 +0200 Subject: [PATCH] Introduce EXILE_SYSCALL_DENY_RET_NOSYS for syscalls like clone3() clone3() is used more and more, but we cannot filter it. We can either allow it fully or return ENONYS. Some libraries perform fallbacks to the older clone() in that case, which we can filter again. --- exile.c | 12 ++++++++---- exile.h | 2 ++ test.c | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/exile.c b/exile.c index 77d7fd9..067b7ad 100644 --- a/exile.c +++ b/exile.c @@ -280,7 +280,7 @@ static struct syscall_vow_map exile_vow_map[] = {EXILE_SYS(copy_file_range), EXILE_SYSCALL_VOW_STDIO}, {EXILE_SYS(statx), EXILE_SYSCALL_VOW_RPATH}, {EXILE_SYS(rseq), EXILE_SYSCALL_VOW_THREAD}, - {EXILE_SYS(clone3), EXILE_SYSCALL_VOW_CLONE}, + {EXILE_SYS(clone3), EXILE_SYSCALL_VOW_CLONE|EXILE_SYSCALL_VOW_THREAD}, {EXILE_SYS(close_range), EXILE_SYSCALL_VOW_STDIO}, {EXILE_SYS(openat2), EXILE_SYSCALL_VOW_RPATH|EXILE_SYSCALL_VOW_WPATH}, {EXILE_SYS(faccessat2), EXILE_SYSCALL_VOW_RPATH}, @@ -521,7 +521,7 @@ int get_vow_argfilter(long syscall, uint64_t vow_promises, struct sock_filter *f current_count = COUNT_EXILE_SYSCALL_FILTER(open_filter); break; case EXILE_SYS(openat2): - *policy = EXILE_SYSCALL_DENY_RET_ERROR; + *policy = EXILE_SYSCALL_DENY_RET_NOSYS; return 0; break; case EXILE_SYS(socket): @@ -539,7 +539,7 @@ int get_vow_argfilter(long syscall, uint64_t vow_promises, struct sock_filter *f case EXILE_SYS(clone3): if((vow_promises & EXILE_SYSCALL_VOW_CLONE) == 0) { - *policy = EXILE_SYSCALL_DENY_RET_ERROR; + *policy = EXILE_SYSCALL_DENY_RET_NOSYS; return 0; } break; @@ -1075,6 +1075,10 @@ static struct sock_filter *append_syscall_to_bpf(struct exile_syscall_policy *sy { action = SECCOMP_RET_ERRNO|EACCES; } + if(action == EXILE_SYSCALL_DENY_RET_NOSYS) + { + action = SECCOMP_RET_ERRNO|ENOSYS; + } long syscall = syscallpolicy->syscall; struct sock_filter syscall_load = BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)); @@ -1141,7 +1145,7 @@ static struct sock_filter *append_syscall_to_bpf(struct exile_syscall_policy *sy static int is_valid_syscall_policy(unsigned int policy) { - return policy == EXILE_SYSCALL_ALLOW || policy == EXILE_SYSCALL_DENY_RET_ERROR || policy == EXILE_SYSCALL_DENY_KILL_PROCESS; + return policy == EXILE_SYSCALL_ALLOW || policy == EXILE_SYSCALL_DENY_RET_ERROR || policy == EXILE_SYSCALL_DENY_KILL_PROCESS || policy == EXILE_SYSCALL_DENY_RET_NOSYS; } /* diff --git a/exile.h b/exile.h index d395851..4898f17 100644 --- a/exile.h +++ b/exile.h @@ -75,6 +75,7 @@ #define EXILE_UNSHARE_NETWORK 1<<1 #define EXILE_UNSHARE_USER 1<<2 #define EXILE_UNSHARE_MOUNT 1<<3 +#define EXILE_UNSHARE_AUTOMATIC 1<<4 #ifndef EXILE_LOG_ERROR #define EXILE_LOG_ERROR(...) do { fprintf(stderr, "exile.h: %s(): Error: ", __func__); fprintf(stderr, __VA_ARGS__); } while(0) @@ -273,6 +274,7 @@ struct exile_path_policy #define EXILE_SYSCALL_ALLOW 1 #define EXILE_SYSCALL_DENY_KILL_PROCESS 2 #define EXILE_SYSCALL_DENY_RET_ERROR 3 +#define EXILE_SYSCALL_DENY_RET_NOSYS 4 #define EXILE_BPF_NOP \ BPF_STMT(BPF_JMP+BPF_JA,0) diff --git a/test.c b/test.c index 592a174..d1e0dd5 100644 --- a/test.c +++ b/test.c @@ -643,6 +643,24 @@ int test_vows_from_str() return 0; } +int test_clone3_nosys() +{ + struct exile_policy *policy = exile_init_policy(); + policy->vow_promises = exile_vows_from_str("stdio rpath wpath cpath thread error"); + + exile_enable_policy(policy); + /* While args are invalid, it should never reach clone3 syscall handler, so it's irrelevant for + our test*/ + long ret = syscall(__NR_clone3, NULL, 0); + + if(ret == -1 && errno != ENOSYS) + { + LOG("clone3() was not allowed but did not return ENOSYS. It returned: %li, errno: %i\n", ret, errno); + return 1; + } + return 0; +} + struct dispatcher { char *name; @@ -670,6 +688,7 @@ struct dispatcher dispatchers[] = { { "launch", &test_launch}, { "launch-get", &test_launch_get}, { "vow_from_str", &test_vows_from_str}, + { "clone3_nosys", &test_clone3_nosys}, }; int main(int argc, char *argv[])