From 39f9b1a2229f8624f92bdcf823ef755c15e28de2 Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Sun, 25 Aug 2019 18:37:05 +0300 Subject: Allow exceptions to seccomp lists Prefix ! can be used to make exceptions to system call blacklists and whitelists used by seccomp, seccomp.drop and seccomp.keep. Closes #1366 --- src/firejail/seccomp.c | 4 ++-- src/fseccomp/fseccomp.h | 2 ++ src/fseccomp/seccomp.c | 12 ++++++++++++ src/fseccomp/seccomp_file.c | 48 +++++++++++++++++++++++++++++++++++++-------- src/fseccomp/syscall.c | 10 +++++++++- src/man/firejail.txt | 23 +++++++++++++--------- 6 files changed, 79 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 81ab18aa1..50fc0384c 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c @@ -48,10 +48,10 @@ char *seccomp_check_list(const char *str) { const char *ptr1 = str; char *ptr2 = rv; while (*ptr1 != '\0') { - if (isalnum(*ptr1) || *ptr1 == '_' || *ptr1 == ',' || *ptr1 == ':' || *ptr1 == '@' || *ptr1 == '-') + if (isalnum(*ptr1) || *ptr1 == '_' || *ptr1 == ',' || *ptr1 == ':' || *ptr1 == '@' || *ptr1 == '-' || *ptr1 == '!') *ptr2++ = *ptr1++; else { - fprintf(stderr, "Error: invalid syscall list\n"); + fprintf(stderr, "Error: invalid syscall list entry %s\n", str); exit(1); } } diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index 593963e76..e1579d098 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h @@ -52,7 +52,9 @@ void seccomp_secondary_block(const char *fname); void write_to_file(int fd, const void *data, int size); void filter_init(int fd); void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg); +void filter_add_whitelist_for_excluded(int fd, int syscall, int arg, void *ptrarg); void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg); +void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg); void filter_add_errno(int fd, int syscall, int arg, void *ptrarg); void filter_end_blacklist(int fd); void filter_end_whitelist(int fd); diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c index 2a719725e..95c20d388 100644 --- a/src/fseccomp/seccomp.c +++ b/src/fseccomp/seccomp.c @@ -80,6 +80,10 @@ void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_ // build pre-exec filter: don't blacklist any syscalls in @default-keep filter_init(fd); + + // allow exceptions in form of !syscall + syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); + char *prelist, *postlist; syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); if (prelist) @@ -128,6 +132,10 @@ void seccomp_default_drop(const char *fname1, const char *fname2, char *list, in // build pre-exec filter: blacklist @default, don't blacklist // any listed syscalls in @default-keep filter_init(fd); + + // allow exceptions in form of !syscall + syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); + add_default_list(fd, allow_debuggers); char *prelist, *postlist; syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); @@ -175,6 +183,10 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) { // build pre-exec filter: whitelist also @default-keep filter_init(fd); + + // allow exceptions in form of !syscall + syscall_check_list(list, filter_add_blacklist_for_excluded, fd, 0, NULL); + // these syscalls are used by firejail after the seccomp filter is initialized int r; r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0, NULL); diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c index 2e1f317ed..266ef0c55 100644 --- a/src/fseccomp/seccomp_file.c +++ b/src/fseccomp/seccomp_file.c @@ -60,26 +60,58 @@ void filter_init(int fd) { write_to_file(fd, filter, sizeof(filter)); } -void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg) { - (void) arg; - (void) ptrarg; - +static void write_whitelist(int fd, int syscall) { struct sock_filter filter[] = { WHITELIST(syscall) }; write_to_file(fd, filter, sizeof(filter)); } -void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg) { - (void) arg; - (void) ptrarg; - +static void write_blacklist(int fd, int syscall) { struct sock_filter filter[] = { BLACKLIST(syscall) }; write_to_file(fd, filter, sizeof(filter)); } +void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg) { + (void) arg; + (void) ptrarg; + + if (syscall >= 0) { + write_whitelist(fd, syscall); + } +} + +// handle seccomp list exceptions (seccomp x,y,!z) +void filter_add_whitelist_for_excluded(int fd, int syscall, int arg, void *ptrarg) { + (void) arg; + (void) ptrarg; + + if (syscall < 0) { + write_whitelist(fd, -syscall); + } +} + +void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg) { + (void) arg; + (void) ptrarg; + + if (syscall >= 0) { + write_blacklist(fd, syscall); + } +} + +// handle seccomp list exceptions (seccomp x,y,!z) +void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg) { + (void) arg; + (void) ptrarg; + + if (syscall < 0) { + write_blacklist(fd, -syscall); + } +} + void filter_add_errno(int fd, int syscall, int arg, void *ptrarg) { (void) ptrarg; struct sock_filter filter[] = { diff --git a/src/fseccomp/syscall.c b/src/fseccomp/syscall.c index 3b698d2dd..d31b719d6 100644 --- a/src/fseccomp/syscall.c +++ b/src/fseccomp/syscall.c @@ -497,9 +497,17 @@ int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, syscall_check_list(new_list, callback, fd, arg, ptrarg); } else { + bool negate = false; + if (*ptr == '!') { + negate = true; + ptr++; + } syscall_process_name(ptr, &syscall_nr, &error_nr); if (syscall_nr == -1) {;} else if (callback != NULL) { + if (negate) { + syscall_nr = -syscall_nr; + } if (error_nr != -1 && fd != 0) { filter_add_errno(fd, syscall_nr, error_nr, ptrarg); } @@ -522,7 +530,7 @@ static void find_syscall(int fd, int syscall, int arg, void *ptrarg) { (void)fd; (void) arg; SyscallCheckList *ptr = ptrarg; - if (syscall == ptr->syscall) + if (abs(syscall) == ptr->syscall) ptr->found = true; } diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 86b76f58f..afff3d5fa 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -1780,7 +1780,8 @@ system call groups are defined: @clock, @cpu-emulation, @debug, @default, @default-nodebuggers, @default-keep, @module, @obsolete, @privileged, @raw-io, @reboot, @resources and @swap. In addition, a system call can be specified by its number instead of name with prefix -$, so for example $165 would be equal to mount on i386. +$, so for example $165 would be equal to mount on i386. Exceptions +can be allowed with prefix !. .br System architecture is strictly imposed only if flag @@ -1798,8 +1799,10 @@ Example: .br $ firejail \-\-seccomp .TP -\fB\-\-seccomp=syscall,@group -Enable seccomp filter, blacklist the default list (@default) and the syscalls or syscall groups specified by the command. +\fB\-\-seccomp=syscall,@group,!syscall2 +Enable seccomp filter, whitelist "syscall2", but blacklist the default +list (@default) and the syscalls or syscall groups specified by the +command. .br .br @@ -1863,8 +1866,9 @@ domain with personality(2) system call. .br .TP -\fB\-\-seccomp.drop=syscall,@group -Enable seccomp filter, and blacklist the syscalls or the syscall groups specified by the command. +\fB\-\-seccomp.drop=syscall,@group,!syscall2 +Enable seccomp filter, whitelist "syscall2" but blacklist the +syscalls or the syscall groups specified by the command. .br .br @@ -1899,10 +1903,11 @@ rm: cannot remove `testfile': Operation not permitted .TP -\fB\-\-seccomp.keep=syscall,syscall,syscall -Enable seccomp filter, and whitelist the syscalls specified by the -command. The system calls needed by Firejail (group @default-keep: -prctl, execve) are handled with the preload library. +\fB\-\-seccomp.keep=syscall,@group,!syscall2 +Enable seccomp filter, blacklist "syscall2" but whitelist the +syscalls or the syscall groups specified by the command. The system +calls needed by Firejail (group @default-keep: prctl, execve) are +handled with the preload library. .br .br -- cgit v1.2.3-70-g09d2