From 88eadbf31fe25dcd7c224a5d92f71c79ccf6c9d3 Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Sat, 14 Mar 2020 00:07:06 +0200 Subject: seccomp: allow defining separate filters for 32-bit arch System calls (names and numbers) are not exactly the same for 32 bit and 64 bit architectures. Let's allow defining separate filters for 32-bit arch using seccomp.32, seccomp.32.drop, seccomp.32.keep. This is useful for mixed 64/32 bit application environments like Steam and Wine. Implement protocol and mdwx filtering also for 32 bit arch. It's still better to block secondary archs completely if not needed. Lists of supported system calls are also updated. Warn if preload libraries would be needed due to trace, tracelog or postexecseccomp (seccomp.drop=execve etc), because a 32-bit dynamic linker does not understand the 64 bit preload libraries. Closes #3267. Signed-off-by: Topi Miettinen --- src/fseccomp/Makefile.in | 4 +- src/fseccomp/errno.c | 204 ------ src/fseccomp/fseccomp.h | 34 +- src/fseccomp/main.c | 41 +- src/fseccomp/protocol.c | 21 +- src/fseccomp/seccomp.c | 143 +++- src/fseccomp/seccomp_file.c | 33 +- src/fseccomp/syscall.c | 1632 ------------------------------------------- 8 files changed, 203 insertions(+), 1909 deletions(-) delete mode 100644 src/fseccomp/errno.c delete mode 100644 src/fseccomp/syscall.c (limited to 'src/fseccomp') diff --git a/src/fseccomp/Makefile.in b/src/fseccomp/Makefile.in index 67e074b3d..8623db6f8 100644 --- a/src/fseccomp/Makefile.in +++ b/src/fseccomp/Makefile.in @@ -5,8 +5,8 @@ include ../common.mk %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ -fseccomp: $(OBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) +fseccomp: $(OBJS) ../lib/errno.o ../lib/syscall.o + $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/errno.o ../lib/syscall.o $(LIBS) $(EXTRA_LDFLAGS) clean:; rm -fr *.o fseccomp *.gcov *.gcda *.gcno *.plist diff --git a/src/fseccomp/errno.c b/src/fseccomp/errno.c deleted file mode 100644 index 9c5aa770c..000000000 --- a/src/fseccomp/errno.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2014-2020 Firejail Authors - * - * This file is part of firejail project - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include "fseccomp.h" - -#include -//#include - -typedef struct { - char *name; - int nr; -} ErrnoEntry; - -static ErrnoEntry errnolist[] = { -// -// code generated using tools/extract-errnos -// - {"EPERM", EPERM}, - {"ENOENT", ENOENT}, - {"ESRCH", ESRCH}, - {"EINTR", EINTR}, - {"EIO", EIO}, - {"ENXIO", ENXIO}, - {"E2BIG", E2BIG}, - {"ENOEXEC", ENOEXEC}, - {"EBADF", EBADF}, - {"ECHILD", ECHILD}, - {"EAGAIN", EAGAIN}, - {"ENOMEM", ENOMEM}, - {"EACCES", EACCES}, - {"EFAULT", EFAULT}, - {"ENOTBLK", ENOTBLK}, - {"EBUSY", EBUSY}, - {"EEXIST", EEXIST}, - {"EXDEV", EXDEV}, - {"ENODEV", ENODEV}, - {"ENOTDIR", ENOTDIR}, - {"EISDIR", EISDIR}, - {"EINVAL", EINVAL}, - {"ENFILE", ENFILE}, - {"EMFILE", EMFILE}, - {"ENOTTY", ENOTTY}, - {"ETXTBSY", ETXTBSY}, - {"EFBIG", EFBIG}, - {"ENOSPC", ENOSPC}, - {"ESPIPE", ESPIPE}, - {"EROFS", EROFS}, - {"EMLINK", EMLINK}, - {"EPIPE", EPIPE}, - {"EDOM", EDOM}, - {"ERANGE", ERANGE}, - {"EDEADLK", EDEADLK}, - {"ENAMETOOLONG", ENAMETOOLONG}, - {"ENOLCK", ENOLCK}, - {"ENOSYS", ENOSYS}, - {"ENOTEMPTY", ENOTEMPTY}, - {"ELOOP", ELOOP}, - {"EWOULDBLOCK", EWOULDBLOCK}, - {"ENOMSG", ENOMSG}, - {"EIDRM", EIDRM}, - {"ECHRNG", ECHRNG}, - {"EL2NSYNC", EL2NSYNC}, - {"EL3HLT", EL3HLT}, - {"EL3RST", EL3RST}, - {"ELNRNG", ELNRNG}, - {"EUNATCH", EUNATCH}, - {"ENOCSI", ENOCSI}, - {"EL2HLT", EL2HLT}, - {"EBADE", EBADE}, - {"EBADR", EBADR}, - {"EXFULL", EXFULL}, - {"ENOANO", ENOANO}, - {"EBADRQC", EBADRQC}, - {"EBADSLT", EBADSLT}, - {"EDEADLOCK", EDEADLOCK}, - {"EBFONT", EBFONT}, - {"ENOSTR", ENOSTR}, - {"ENODATA", ENODATA}, - {"ETIME", ETIME}, - {"ENOSR", ENOSR}, - {"ENONET", ENONET}, - {"ENOPKG", ENOPKG}, - {"EREMOTE", EREMOTE}, - {"ENOLINK", ENOLINK}, - {"EADV", EADV}, - {"ESRMNT", ESRMNT}, - {"ECOMM", ECOMM}, - {"EPROTO", EPROTO}, - {"EMULTIHOP", EMULTIHOP}, - {"EDOTDOT", EDOTDOT}, - {"EBADMSG", EBADMSG}, - {"EOVERFLOW", EOVERFLOW}, - {"ENOTUNIQ", ENOTUNIQ}, - {"EBADFD", EBADFD}, - {"EREMCHG", EREMCHG}, - {"ELIBACC", ELIBACC}, - {"ELIBBAD", ELIBBAD}, - {"ELIBSCN", ELIBSCN}, - {"ELIBMAX", ELIBMAX}, - {"ELIBEXEC", ELIBEXEC}, - {"EILSEQ", EILSEQ}, - {"ERESTART", ERESTART}, - {"ESTRPIPE", ESTRPIPE}, - {"EUSERS", EUSERS}, - {"ENOTSOCK", ENOTSOCK}, - {"EDESTADDRREQ", EDESTADDRREQ}, - {"EMSGSIZE", EMSGSIZE}, - {"EPROTOTYPE", EPROTOTYPE}, - {"ENOPROTOOPT", ENOPROTOOPT}, - {"EPROTONOSUPPORT", EPROTONOSUPPORT}, - {"ESOCKTNOSUPPORT", ESOCKTNOSUPPORT}, - {"EOPNOTSUPP", EOPNOTSUPP}, - {"EPFNOSUPPORT", EPFNOSUPPORT}, - {"EAFNOSUPPORT", EAFNOSUPPORT}, - {"EADDRINUSE", EADDRINUSE}, - {"EADDRNOTAVAIL", EADDRNOTAVAIL}, - {"ENETDOWN", ENETDOWN}, - {"ENETUNREACH", ENETUNREACH}, - {"ENETRESET", ENETRESET}, - {"ECONNABORTED", ECONNABORTED}, - {"ECONNRESET", ECONNRESET}, - {"ENOBUFS", ENOBUFS}, - {"EISCONN", EISCONN}, - {"ENOTCONN", ENOTCONN}, - {"ESHUTDOWN", ESHUTDOWN}, - {"ETOOMANYREFS", ETOOMANYREFS}, - {"ETIMEDOUT", ETIMEDOUT}, - {"ECONNREFUSED", ECONNREFUSED}, - {"EHOSTDOWN", EHOSTDOWN}, - {"EHOSTUNREACH", EHOSTUNREACH}, - {"EALREADY", EALREADY}, - {"EINPROGRESS", EINPROGRESS}, - {"ESTALE", ESTALE}, - {"EUCLEAN", EUCLEAN}, - {"ENOTNAM", ENOTNAM}, - {"ENAVAIL", ENAVAIL}, - {"EISNAM", EISNAM}, - {"EREMOTEIO", EREMOTEIO}, - {"EDQUOT", EDQUOT}, - {"ENOMEDIUM", ENOMEDIUM}, - {"EMEDIUMTYPE", EMEDIUMTYPE}, - {"ECANCELED", ECANCELED}, - {"ENOKEY", ENOKEY}, - {"EKEYEXPIRED", EKEYEXPIRED}, - {"EKEYREVOKED", EKEYREVOKED}, - {"EKEYREJECTED", EKEYREJECTED}, - {"EOWNERDEAD", EOWNERDEAD}, - {"ENOTRECOVERABLE", ENOTRECOVERABLE}, - {"ERFKILL", ERFKILL}, - {"EHWPOISON", EHWPOISON}, - {"ENOTSUP", ENOTSUP}, -#ifdef ENOATTR - {"ENOATTR", ENOATTR}, -#endif -}; - -int errno_find_name(const char *name) { - int i; - int elems = sizeof(errnolist) / sizeof(errnolist[0]); - for (i = 0; i < elems; i++) { - if (strcasecmp(name, errnolist[i].name) == 0) - return errnolist[i].nr; - } - - return -1; -} - -char *errno_find_nr(int nr) { - int i; - int elems = sizeof(errnolist) / sizeof(errnolist[0]); - for (i = 0; i < elems; i++) { - if (nr == errnolist[i].nr) - return errnolist[i].name; - } - - return "unknown"; -} - - - -void errno_print(void) { - int i; - int elems = sizeof(errnolist) / sizeof(errnolist[0]); - for (i = 0; i < elems; i++) { - printf("%d\t- %s\n", errnolist[i].nr, errnolist[i].name); - } - printf("\n"); -} diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index bf55870f2..e8dd083b6 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h @@ -24,21 +24,11 @@ #include #include #include "../include/common.h" +#include "../include/syscall.h" // main.c extern int arg_quiet; -// syscall.c -void syscall_print(void); -int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg, void *ptrarg), int fd, int arg, void *ptrarg); -const char *syscall_find_nr(int nr); -void syscalls_in_list(const char *list, const char *slist, int fd, char **prelist, char **postlist); - -// errno.c -void errno_print(void); -int errno_find_name(const char *name); -char *errno_find_nr(int nr); - // protocol.c void protocol_print(void); void protocol_build_filter(const char *prlist, const char *fname); @@ -49,27 +39,27 @@ void seccomp_secondary_32(const char *fname); void seccomp_secondary_block(const char *fname); // seccomp_file.c -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 write_to_file(int fd, const void *data, size_t size); +void filter_init(int fd, bool native); +void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg, bool native); +void filter_add_whitelist_for_excluded(int fd, int syscall, int arg, void *ptrarg, bool native); +void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg, bool native); +void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg, bool native); void filter_end_blacklist(int fd); void filter_end_whitelist(int fd); // seccomp.c // default list -void seccomp_default(const char *fname, int allow_debuggers); +void seccomp_default(const char *fname, int allow_debuggers, bool native); // drop list -void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers); +void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers, bool native); // default+drop list -void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers); +void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers, bool native); // whitelisted filter -void seccomp_keep(const char *fname1, const char *fname2, char *list); +void seccomp_keep(const char *fname1, const char *fname2, char *list, bool native); // block writable and executable memory void memory_deny_write_execute(const char *fname); +void memory_deny_write_execute_32(const char *fname); // seccomp_print void filter_print(const char *fname); diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 82b96f476..b3161a6db 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c @@ -23,6 +23,7 @@ int arg_quiet = 0; static void usage(void) { printf("Usage:\n"); printf("\tfseccomp debug-syscalls\n"); + printf("\tfseccomp debug-syscalls32\n"); printf("\tfseccomp debug-errnos\n"); printf("\tfseccomp debug-protocols\n"); printf("\tfseccomp protocol build list file\n"); @@ -31,12 +32,20 @@ static void usage(void) { printf("\tfseccomp secondary block file\n"); printf("\tfseccomp default file\n"); printf("\tfseccomp default file allow-debuggers\n"); + printf("\tfseccomp default32 file\n"); + printf("\tfseccomp default32 file allow-debuggers\n"); printf("\tfseccomp drop file1 file2 list\n"); printf("\tfseccomp drop file1 file2 list allow-debuggers\n"); + printf("\tfseccomp drop32 file1 file2 list\n"); + printf("\tfseccomp drop32 file1 file2 list allow-debuggers\n"); printf("\tfseccomp default drop file1 file2 list\n"); printf("\tfseccomp default drop file1 file2 list allow-debuggers\n"); + printf("\tfseccomp default32 drop file1 file2 list\n"); + printf("\tfseccomp default32 drop file1 file2 list allow-debuggers\n"); printf("\tfseccomp keep file1 file2 list\n"); + printf("\tfseccomp keep32 file1 file2 list\n"); printf("\tfseccomp memory-deny-write-execute file\n"); + printf("\tfseccomp memory-deny-write-execute.32 file\n"); } int main(int argc, char **argv) { @@ -64,6 +73,8 @@ printf("\n"); } else if (argc == 2 && strcmp(argv[1], "debug-syscalls") == 0) syscall_print(); + else if (argc == 2 && strcmp(argv[1], "debug-syscalls32") == 0) + syscall_print_32(); else if (argc == 2 && strcmp(argv[1], "debug-errnos") == 0) errno_print(); else if (argc == 2 && strcmp(argv[1], "debug-protocols") == 0) @@ -75,21 +86,37 @@ printf("\n"); else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "block") == 0) seccomp_secondary_block(argv[3]); else if (argc == 3 && strcmp(argv[1], "default") == 0) - seccomp_default(argv[2], 0); + seccomp_default(argv[2], 0, true); else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) - seccomp_default(argv[2], 1); + seccomp_default(argv[2], 1, true); + else if (argc == 3 && strcmp(argv[1], "default32") == 0) + seccomp_default(argv[2], 0, false); + else if (argc == 4 && strcmp(argv[1], "default32") == 0 && strcmp(argv[3], "allow-debuggers") == 0) + seccomp_default(argv[2], 1, false); else if (argc == 5 && strcmp(argv[1], "drop") == 0) - seccomp_drop(argv[2], argv[3], argv[4], 0); + seccomp_drop(argv[2], argv[3], argv[4], 0, true); else if (argc == 6 && strcmp(argv[1], "drop") == 0 && strcmp(argv[5], "allow-debuggers") == 0) - seccomp_drop(argv[2], argv[3], argv[4], 1); + seccomp_drop(argv[2], argv[3], argv[4], 1, true); + else if (argc == 5 && strcmp(argv[1], "drop32") == 0) + seccomp_drop(argv[2], argv[3], argv[4], 0, false); + else if (argc == 6 && strcmp(argv[1], "drop32") == 0 && strcmp(argv[5], "allow-debuggers") == 0) + seccomp_drop(argv[2], argv[3], argv[4], 1, false); else if (argc == 6 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0) - seccomp_default_drop(argv[3], argv[4], argv[5], 0); + seccomp_default_drop(argv[3], argv[4], argv[5], 0, true); else if (argc == 7 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0 && strcmp(argv[6], "allow-debuggers") == 0) - seccomp_default_drop(argv[3], argv[4], argv[5], 1); + seccomp_default_drop(argv[3], argv[4], argv[5], 1, true); + else if (argc == 6 && strcmp(argv[1], "default32") == 0 && strcmp(argv[2], "drop") == 0) + seccomp_default_drop(argv[3], argv[4], argv[5], 0, false); + else if (argc == 7 && strcmp(argv[1], "default32") == 0 && strcmp(argv[2], "drop") == 0 && strcmp(argv[6], "allow-debuggers") == 0) + seccomp_default_drop(argv[3], argv[4], argv[5], 1, false); else if (argc == 5 && strcmp(argv[1], "keep") == 0) - seccomp_keep(argv[2], argv[3], argv[4]); + seccomp_keep(argv[2], argv[3], argv[4], true); + else if (argc == 5 && strcmp(argv[1], "keep32") == 0) + seccomp_keep(argv[2], argv[3], argv[4], false); else if (argc == 3 && strcmp(argv[1], "memory-deny-write-execute") == 0) memory_deny_write_execute(argv[2]); + else if (argc == 3 && strcmp(argv[1], "memory-deny-write-execute.32") == 0) + memory_deny_write_execute_32(argv[2]); else { fprintf(stderr, "Error fseccomp: invalid arguments\n"); return 1; diff --git a/src/fseccomp/protocol.c b/src/fseccomp/protocol.c index 7a21eb2c2..b8b30f488 100644 --- a/src/fseccomp/protocol.c +++ b/src/fseccomp/protocol.c @@ -122,10 +122,23 @@ void protocol_build_filter(const char *prlist, const char *fname) { // header struct sock_filter filter_start[] = { - VALIDATE_ARCHITECTURE, - EXAMINE_SYSCALL, - ONLY(SYS_socket), - EXAMINE_ARGUMENT(0) +#if defined __x86_64__ + /* check for native arch */ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1 + 2 + 1, 0), + /* i386 filter */ + EXAMINE_SYSCALL, // 1 + // checking SYS_socket only: filtering SYS_socketcall not possible with seccomp + ONLY(359), // 1 + 2 + BPF_JUMP(BPF_JMP+BPF_JA+BPF_K, (3 + 1 + 2), 0, 0), // 1 + 2 + 1 +#else +#warning 32 bit protocol filter not implemented yet for your architecture +#endif + VALIDATE_ARCHITECTURE, // 3 + EXAMINE_SYSCALL, // 3 + 1 + ONLY(SYS_socket), // 3 + 1 + 2 + + EXAMINE_ARGUMENT(0) // 3 + 1 + 2 + 1 }; memcpy(ptr, &filter_start[0], sizeof(filter_start)); ptr += sizeof(filter_start); diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c index 29aa2f2f5..0db7b5954 100644 --- a/src/fseccomp/seccomp.c +++ b/src/fseccomp/seccomp.c @@ -24,12 +24,12 @@ #include #include -static void add_default_list(int fd, int allow_debuggers) { +static void add_default_list(int fd, int allow_debuggers, bool native) { int r; if (!allow_debuggers) - r = syscall_check_list("@default-nodebuggers", filter_add_blacklist, fd, 0, NULL); + r = syscall_check_list("@default-nodebuggers", filter_add_blacklist, fd, 0, NULL, native); else - r = syscall_check_list("@default", filter_add_blacklist, fd, 0, NULL); + r = syscall_check_list("@default", filter_add_blacklist, fd, 0, NULL, native); assert(r == 0); //#ifdef SYS_mknod - emoved in 0.9.29 - it breaks Zotero extension @@ -46,7 +46,7 @@ static void add_default_list(int fd, int allow_debuggers) { } // default list -void seccomp_default(const char *fname, int allow_debuggers) { +void seccomp_default(const char *fname, int allow_debuggers, bool native) { assert(fname); // open file @@ -57,8 +57,8 @@ void seccomp_default(const char *fname, int allow_debuggers) { } // build filter (no post-exec filter needed because default list is fine for us) - filter_init(fd); - add_default_list(fd, allow_debuggers); + filter_init(fd, native); + add_default_list(fd, allow_debuggers, native); filter_end_blacklist(fd); // close file @@ -66,7 +66,7 @@ void seccomp_default(const char *fname, int allow_debuggers) { } // drop list -void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers) { +void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers, bool native) { assert(fname1); assert(fname2); (void) allow_debuggers; // todo: to implemnet it @@ -79,15 +79,15 @@ 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); + filter_init(fd, native); // allow exceptions in form of !syscall - syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); + syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL, native); char *prelist, *postlist; - syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); + syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist, native); if (prelist) - if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL)) { + if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL, native)) { fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); exit(1); } @@ -106,8 +106,8 @@ void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_ } // build post-exec filter: blacklist remaining syscalls - filter_init(fd); - if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL)) { + filter_init(fd, native); + if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL, native)) { fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); exit(1); } @@ -118,7 +118,7 @@ void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_ } // default+drop -void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers) { +void seccomp_default_drop(const char *fname1, const char *fname2, char *list, int allow_debuggers, bool native) { assert(fname1); assert(fname2); @@ -131,16 +131,16 @@ 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); + filter_init(fd, native); // allow exceptions in form of !syscall - syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); + syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL, native); - add_default_list(fd, allow_debuggers); + add_default_list(fd, allow_debuggers, native); char *prelist, *postlist; - syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); + syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist, native); if (prelist) - if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL)) { + if (syscall_check_list(prelist, filter_add_blacklist, fd, 0, NULL, native)) { fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); exit(1); } @@ -160,8 +160,8 @@ void seccomp_default_drop(const char *fname1, const char *fname2, char *list, in } // build post-exec filter: blacklist remaining syscalls - filter_init(fd); - if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL)) { + filter_init(fd, native); + if (syscall_check_list(postlist, filter_add_blacklist, fd, 0, NULL, native)) { fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); exit(1); } @@ -171,7 +171,7 @@ void seccomp_default_drop(const char *fname1, const char *fname2, char *list, in close(fd); } -void seccomp_keep(const char *fname1, const char *fname2, char *list) { +void seccomp_keep(const char *fname1, const char *fname2, char *list, bool native) { (void) fname2; // open file for pre-exec filter @@ -182,17 +182,17 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) { } // build pre-exec filter: whitelist also @default-keep - filter_init(fd); + filter_init(fd, native); // allow exceptions in form of !syscall - syscall_check_list(list, filter_add_blacklist_for_excluded, fd, 0, NULL); + syscall_check_list(list, filter_add_blacklist_for_excluded, fd, 0, NULL, native); // 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); + r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0, NULL, native); assert(r == 0); - if (syscall_check_list(list, filter_add_whitelist, fd, 0, NULL)) { + if (syscall_check_list(list, filter_add_whitelist, fd, 0, NULL, native)) { fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); exit(1); } @@ -206,6 +206,15 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) { #if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) # define filter_syscall SYS_mmap # undef block_syscall +#if defined(__x86_64__) +// i386 syscalls +# define filter_syscall_32 192 +# define block_syscall_32 90 +# define mprotect_32 125 +# define pkey_mprotect_32 380 +# define shmat_32 397 +# define memfd_create_32 356 +#endif #elif defined(__i386__) # define filter_syscall SYS_mmap2 # define block_syscall SYS_mmap @@ -216,6 +225,12 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) { # warning "Platform does not support seccomp memory-deny-write-execute filter yet" # undef filter_syscall # undef block_syscall +# undef filter_syscall_32 +# undef block_syscall_32 +# undef mprotect_32 +# undef pkey_mprotect_32 +# undef shmat_32 +# undef memfd_create_32 #endif void memory_deny_write_execute(const char *fname) { @@ -226,10 +241,10 @@ void memory_deny_write_execute(const char *fname) { exit(1); } - filter_init(fd); + filter_init(fd, true); // build filter - static const struct sock_filter filter[] = { + struct sock_filter filter[] = { #ifdef block_syscall // block old multiplexing mmap syscall for i386 BLACKLIST(block_syscall), @@ -288,3 +303,75 @@ void memory_deny_write_execute(const char *fname) { // close file close(fd); } + +void memory_deny_write_execute_32(const char *fname) { + // open file + int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + filter_init(fd, false); + + // build filter + struct sock_filter filter[] = { +#if defined(__x86_64__) +#ifdef block_syscall_32 + // block old multiplexing mmap syscall for i386 + BLACKLIST(block_syscall_32), +#endif +#ifdef filter_syscall_32 + // block mmap(,,x|PROT_WRITE|PROT_EXEC) so W&X memory can't be created + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, filter_syscall_32, 0, 5), + EXAMINE_ARGUMENT(2), + BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1), + KILL_PROCESS, + RETURN_ALLOW, +#endif +#ifdef mprotect_32 + // block mprotect(,,PROT_EXEC) so writable memory can't be turned into executable + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, mprotect_32, 0, 5), + EXAMINE_ARGUMENT(2), + BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), + KILL_PROCESS, + RETURN_ALLOW, +#endif +#ifdef pkey_mprotect_32 + // same for pkey_mprotect(,,PROT_EXEC), where available + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, pkey_mprotect_32, 0, 5), + EXAMINE_ARGUMENT(2), + BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1), + KILL_PROCESS, + RETURN_ALLOW, +#endif + +#ifdef shmat_32 + // block shmat(,,x|SHM_EXEC) so W&X shared memory can't be created + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, shmat_32, 0, 5), + EXAMINE_ARGUMENT(2), + BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1), + KILL_PROCESS, + RETURN_ALLOW, +#endif +#ifdef memfd_create_32 + // block memfd_create as it can be used to create + // arbitrary memory contents which can be later mapped + // as executable + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, memfd_create_32, 0, 1), + KILL_PROCESS, +#endif +#endif + RETURN_ALLOW + }; + write_to_file(fd, filter, sizeof(filter)); + + filter_end_blacklist(fd); + + // close file + close(fd); +} diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c index e47e8db25..872b41261 100644 --- a/src/fseccomp/seccomp_file.c +++ b/src/fseccomp/seccomp_file.c @@ -21,11 +21,11 @@ #include "../include/seccomp.h" #include -void write_to_file(int fd, const void *data, int size) { +void write_to_file(int fd, const void *data, size_t size) { assert(data); assert(size); - int written = 0; + size_t written = 0; while (written < size) { int rv = write(fd, (unsigned char *) data + written, size - written); if (rv == -1) { @@ -36,8 +36,8 @@ void write_to_file(int fd, const void *data, int size) { } } -void filter_init(int fd) { - struct sock_filter filter[] = { +void filter_init(int fd, bool native) { + struct sock_filter filter_native[] = { VALIDATE_ARCHITECTURE, #if defined(__x86_64__) EXAMINE_SYSCALL, @@ -46,6 +46,10 @@ void filter_init(int fd) { EXAMINE_SYSCALL #endif }; + struct sock_filter filter_32[] = { + VALIDATE_ARCHITECTURE_32, + EXAMINE_SYSCALL + }; #if 0 { @@ -57,7 +61,10 @@ void filter_init(int fd) { } #endif - write_to_file(fd, filter, sizeof(filter)); + if (native) + write_to_file(fd, filter_native, sizeof(filter_native)); + else + write_to_file(fd, filter_32, sizeof(filter_32)); } static void write_whitelist(int fd, int syscall) { @@ -74,9 +81,10 @@ static void write_blacklist(int fd, int syscall) { write_to_file(fd, filter, sizeof(filter)); } -void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg) { +void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg, bool native) { (void) arg; (void) ptrarg; + (void) native; if (syscall >= 0) { write_whitelist(fd, syscall); @@ -84,18 +92,20 @@ void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg) { } // handle seccomp list exceptions (seccomp x,y,!z) -void filter_add_whitelist_for_excluded(int fd, int syscall, int arg, void *ptrarg) { +void filter_add_whitelist_for_excluded(int fd, int syscall, int arg, void *ptrarg, bool native) { (void) arg; (void) ptrarg; + (void) native; if (syscall < 0) { write_whitelist(fd, -syscall); } } -void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg) { +void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg, bool native) { (void) arg; (void) ptrarg; + (void) native; if (syscall >= 0) { write_blacklist(fd, syscall); @@ -103,17 +113,20 @@ void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg) { } // handle seccomp list exceptions (seccomp x,y,!z) -void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg) { +void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg, bool native) { (void) arg; (void) ptrarg; + (void) native; if (syscall < 0) { write_blacklist(fd, -syscall); } } -void filter_add_errno(int fd, int syscall, int arg, void *ptrarg) { +void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native) { (void) ptrarg; + (void) native; + struct sock_filter filter[] = { BLACKLIST_ERRNO(syscall, arg) }; diff --git a/src/fseccomp/syscall.c b/src/fseccomp/syscall.c deleted file mode 100644 index 2b112245c..000000000 --- a/src/fseccomp/syscall.c +++ /dev/null @@ -1,1632 +0,0 @@ -/* - * Copyright (C) 2014-2020 Firejail Authors - * - * This file is part of firejail project - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#define _GNU_SOURCE -#include "fseccomp.h" -#include -#include - -typedef struct { - const char * const name; - int nr; -} SyscallEntry; - -typedef struct { - const char * const name; - const char * const list; -} SyscallGroupList; - -typedef struct { - const char *slist; - char *prelist, *postlist; - bool found; - int syscall; -} SyscallCheckList; - -static const SyscallEntry syslist[] = { -// -// code generated using tools/extract-syscall -// -#include "../include/syscall.h" -// -// end of generated code -// -}; // end of syslist - -static const SyscallGroupList sysgroups[] = { - { .name = "@aio", .list = -#ifdef SYS_io_cancel - "io_cancel," -#endif -#ifdef SYS_io_destroy - "io_destroy," -#endif -#ifdef SYS_io_getevents - "io_getevents," -#endif -#ifdef SYS_io_pgetevents - "io_pgetevents," -#endif -#ifdef SYS_io_setup - "io_setup," -#endif -#ifdef SYS_io_submit - "io_submit" -#endif - }, - { .name = "@basic-io", .list = -#ifdef SYS__llseek - "_llseek," -#endif -#ifdef SYS_close - "close," -#endif -#ifdef SYS_dup - "dup," -#endif -#ifdef SYS_dup2 - "dup2," -#endif -#ifdef SYS_dup3 - "dup3," -#endif -#ifdef SYS_lseek - "lseek," -#endif -#ifdef SYS_pread64 - "pread64," -#endif -#ifdef SYS_preadv - "preadv," -#endif -#ifdef SYS_preadv2 - "preadv2," -#endif -#ifdef SYS_pwrite64 - "pwrite64," -#endif -#ifdef SYS_pwritev - "pwritev," -#endif -#ifdef SYS_pwritev2 - "pwritev2," -#endif -#ifdef SYS_read - "read," -#endif -#ifdef SYS_readv - "readv," -#endif -#ifdef SYS_write - "write," -#endif -#ifdef SYS_writev - "writev" -#endif - }, - { .name = "@chown", .list = -#ifdef SYS_chown - "chown," -#endif -#ifdef SYS_chown32 - "chown32," -#endif -#ifdef SYS_fchown - "fchown," -#endif -#ifdef SYS_fchown32 - "fchown32," -#endif -#ifdef SYS_fchownat - "fchownat," -#endif -#ifdef SYS_lchown - "lchown," -#endif -#ifdef SYS_lchown32 - "lchown32" -#endif - }, - { .name = "@clock", .list = -#ifdef SYS_adjtimex - "adjtimex," -#endif -#ifdef SYS_clock_adjtime - "clock_adjtime," -#endif -#ifdef SYS_clock_settime - "clock_settime," -#endif -#ifdef SYS_settimeofday - "settimeofday," -#endif -#ifdef SYS_stime - "stime" -#endif - }, - { .name = "@cpu-emulation", .list = -#ifdef SYS_modify_ldt - "modify_ldt," -#endif -#ifdef SYS_subpage_prot - "subpage_prot," -#endif -#ifdef SYS_switch_endian - "switch_endian," -#endif -#ifdef SYS_vm86 - "vm86," -#endif -#ifdef SYS_vm86old - "vm86old" -#endif -#if !defined(SYS_modify_ldt) && !defined(SYS_subpage_prot) && !defined(SYS_switch_endian) && !defined(SYS_vm86) && !defined(SYS_vm86old) - "__dummy_syscall__" // workaround for arm64, s390x and sparc64 which don't have any of above defined and empty syscall lists are not allowed -#endif - }, - { .name = "@debug", .list = -#ifdef SYS_lookup_dcookie - "lookup_dcookie," -#endif -#ifdef SYS_perf_event_open - "perf_event_open," -#endif -#ifdef SYS_process_vm_writev - "process_vm_writev," -#endif -#ifdef SYS_rtas - "rtas," -#endif -#ifdef SYS_s390_runtime_instr - "s390_runtime_instr," -#endif -#ifdef SYS_sys_debug_setcontext - "sys_debug_setcontext," -#endif - }, - { .name = "@default", .list = - "@clock," - "@cpu-emulation," - "@debug," - "@module," - "@obsolete," - "@raw-io," - "@reboot," - "@swap," -#ifdef SYS_open_by_handle_at - "open_by_handle_at," -#endif -#ifdef SYS_name_to_handle_at - "name_to_handle_at," -#endif -#ifdef SYS_ioprio_set - "ioprio_set," -#endif -#ifdef SYS_ni_syscall - "ni_syscall," -#endif -#ifdef SYS_syslog - "syslog," -#endif -#ifdef SYS_fanotify_init - "fanotify_init," -#endif -#ifdef SYS_kcmp - "kcmp," -#endif -#ifdef SYS_add_key - "add_key," -#endif -#ifdef SYS_request_key - "request_key," -#endif -#ifdef SYS_mbind - "mbind," -#endif -#ifdef SYS_migrate_pages - "migrate_pages," -#endif -#ifdef SYS_move_pages - "move_pages," -#endif -#ifdef SYS_keyctl - "keyctl," -#endif -#ifdef SYS_io_setup - "io_setup," -#endif -#ifdef SYS_io_destroy - "io_destroy," -#endif -#ifdef SYS_io_getevents - "io_getevents," -#endif -#ifdef SYS_io_submit - "io_submit," -#endif -#ifdef SYS_io_cancel - "io_cancel," -#endif -#ifdef SYS_remap_file_pages - "remap_file_pages," -#endif -#ifdef SYS_set_mempolicy - "set_mempolicy" -#endif -#ifdef SYS_vmsplice - "vmsplice," -#endif -#ifdef SYS_umount - "umount," -#endif -#ifdef SYS_userfaultfd - "userfaultfd," -#endif -#ifdef SYS_acct - "acct," -#endif -#ifdef SYS_bpf - "bpf," -#endif -#ifdef SYS_chroot - "chroot," -#endif -#ifdef SYS_mount - "mount," -#endif -#ifdef SYS_nfsservctl - "nfsservctl," -#endif -#ifdef SYS_pivot_root - "pivot_root," -#endif -#ifdef SYS_setdomainname - "setdomainname," -#endif -#ifdef SYS_sethostname - "sethostname," -#endif -#ifdef SYS_umount2 - "umount2," -#endif -#ifdef SYS_vhangup - "vhangup" -#endif -//#ifdef SYS_mincore // 0.9.57 - problem fixed in Linux kernel 5.0; on 4.x it will break kodi, mpv, totem -// "mincore" -//#endif - }, - { .name = "@default-nodebuggers", .list = - "@default," -#ifdef SYS_ptrace - "ptrace," -#endif -#ifdef SYS_personality - "personality," -#endif -#ifdef SYS_process_vm_readv - "process_vm_readv" -#endif - }, - { .name = "@default-keep", .list = - "execve," - "prctl" - }, - { .name = "@file-system", .list = -#ifdef SYS_access - "access," -#endif -#ifdef SYS_chdir - "chdir," -#endif -#ifdef SYS_chmod - "chmod," -#endif -#ifdef SYS_close - "close," -#endif -#ifdef SYS_creat - "creat," -#endif -#ifdef SYS_faccessat - "faccessat," -#endif -#ifdef SYS_fallocate - "fallocate," -#endif -#ifdef SYS_fchdir - "fchdir," -#endif -#ifdef SYS_fchmod - "fchmod," -#endif -#ifdef SYS_fchmodat - "fchmodat," -#endif -#ifdef SYS_fcntl - "fcntl," -#endif -#ifdef SYS_fcntl64 - "fcntl64," -#endif -#ifdef SYS_fgetxattr - "fgetxattr," -#endif -#ifdef SYS_flistxattr - "flistxattr," -#endif -#ifdef SYS_fremovexattr - "fremovexattr," -#endif -#ifdef SYS_fsetxattr - "fsetxattr," -#endif -#ifdef SYS_fstat - "fstat," -#endif -#ifdef SYS_fstat64 - "fstat64," -#endif -#ifdef SYS_fstatat64 - "fstatat64," -#endif -#ifdef SYS_fstatfs - "fstatfs," -#endif -#ifdef SYS_fstatfs64 - "fstatfs64," -#endif -#ifdef SYS_ftruncate - "ftruncate," -#endif -#ifdef SYS_ftruncate64 - "ftruncate64," -#endif -#ifdef SYS_futimesat - "futimesat," -#endif -#ifdef SYS_getcwd - "getcwd," -#endif -#ifdef SYS_getdents - "getdents," -#endif -#ifdef SYS_getdents64 - "getdents64," -#endif -#ifdef SYS_getxattr - "getxattr," -#endif -#ifdef SYS_inotify_add_watch - "inotify_add_watch," -#endif -#ifdef SYS_inotify_init - "inotify_init," -#endif -#ifdef SYS_inotify_init1 - "inotify_init1," -#endif -#ifdef SYS_inotify_rm_watch - "inotify_rm_watch," -#endif -#ifdef SYS_lgetxattr - "lgetxattr," -#endif -#ifdef SYS_link - "link," -#endif -#ifdef SYS_linkat - "linkat," -#endif -#ifdef SYS_listxattr - "listxattr," -#endif -#ifdef SYS_llistxattr - "llistxattr," -#endif -#ifdef SYS_lremovexattr - "lremovexattr," -#endif -#ifdef SYS_lsetxattr - "lsetxattr," -#endif -#ifdef SYS_lstat - "lstat," -#endif -#ifdef SYS_lstat64 - "lstat64," -#endif -#ifdef SYS_mkdir - "mkdir," -#endif -#ifdef SYS_mkdirat - "mkdirat," -#endif -#ifdef SYS_mknod - "mknod," -#endif -#ifdef SYS_mknodat - "mknodat," -#endif -#ifdef SYS_mmap - "mmap," -#endif -#ifdef SYS_mmap2 - "mmap2," -#endif -#ifdef SYS_munmap - "munmap," -#endif -#ifdef SYS_newfstatat - "newfstatat," -#endif -#ifdef SYS_oldfstat - "oldfstat," -#endif -#ifdef SYS_oldlstat - "oldlstat," -#endif -#ifdef SYS_oldstat - "oldstat," -#endif -#ifdef SYS_open - "open," -#endif -#ifdef SYS_openat - "openat," -#endif -#ifdef SYS_readlink - "readlink," -#endif -#ifdef SYS_readlinkat - "readlinkat," -#endif -#ifdef SYS_removexattr - "removexattr," -#endif -#ifdef SYS_rename - "rename," -#endif -#ifdef SYS_renameat - "renameat," -#endif -#ifdef SYS_renameat2 - "renameat2," -#endif -#ifdef SYS_rmdir - "rmdir," -#endif -#ifdef SYS_setxattr - "setxattr," -#endif -#ifdef SYS_stat - "stat," -#endif -#ifdef SYS_stat64 - "stat64," -#endif -#ifdef SYS_statfs - "statfs," -#endif -#ifdef SYS_statfs64 - "statfs64," -#endif -#ifdef SYS_statx - "statx," -#endif -#ifdef SYS_symlink - "symlink," -#endif -#ifdef SYS_symlinkat - "symlinkat," -#endif -#ifdef SYS_truncate - "truncate," -#endif -#ifdef SYS_truncate64 - "truncate64," -#endif -#ifdef SYS_unlink - "unlink," -#endif -#ifdef SYS_unlinkat - "unlinkat," -#endif -#ifdef SYS_utime - "utime," -#endif -#ifdef SYS_utimensat - "utimensat," -#endif -#ifdef SYS_utimes - "utimes" -#endif - }, - { .name = "@io-event", .list = -#ifdef SYS__newselect - "_newselect," -#endif -#ifdef SYS_epoll_create - "epoll_create," -#endif -#ifdef SYS_epoll_create1 - "epoll_create1," -#endif -#ifdef SYS_epoll_ctl - "epoll_ctl," -#endif -#ifdef SYS_epoll_ctl_old - "epoll_ctl_old," -#endif -#ifdef SYS_epoll_pwait - "epoll_pwait," -#endif -#ifdef SYS_epoll_wait - "epoll_wait," -#endif -#ifdef SYS_epoll_wait_old - "epoll_wait_old," -#endif -#ifdef SYS_eventfd - "eventfd," -#endif -#ifdef SYS_eventfd2 - "eventfd2," -#endif -#ifdef SYS_poll - "poll," -#endif -#ifdef SYS_ppoll - "ppoll," -#endif -#ifdef SYS_pselect6 - "pselect6," -#endif -#ifdef SYS_select - "select" -#endif - }, - { .name = "@ipc", .list = -#ifdef SYS_ipc - "ipc," -#endif -#ifdef SYS_memfd_create - "memfd_create," -#endif -#ifdef SYS_mq_getsetattr - "mq_getsetattr," -#endif -#ifdef SYS_mq_notify - "mq_notify," -#endif -#ifdef SYS_mq_open - "mq_open," -#endif -#ifdef SYS_mq_timedreceive - "mq_timedreceive," -#endif -#ifdef SYS_mq_timedsend - "mq_timedsend," -#endif -#ifdef SYS_mq_unlink - "mq_unlink," -#endif -#ifdef SYS_msgctl - "msgctl," -#endif -#ifdef SYS_msgget - "msgget," -#endif -#ifdef SYS_msgrcv - "msgrcv," -#endif -#ifdef SYS_msgsnd - "msgsnd," -#endif -#ifdef SYS_pipe - "pipe," -#endif -#ifdef SYS_pipe2 - "pipe2," -#endif -#ifdef SYS_process_vm_readv - "process_vm_readv," -#endif -#ifdef SYS_process_vm_writev - "process_vm_writev," -#endif -#ifdef SYS_semctl - "semctl," -#endif -#ifdef SYS_semget - "semget," -#endif -#ifdef SYS_semop - "semop," -#endif -#ifdef SYS_semtimedop - "semtimedop," -#endif -#ifdef SYS_shmat - "shmat," -#endif -#ifdef SYS_shmctl - "shmctl," -#endif -#ifdef SYS_shmdt - "shmdt," -#endif -#ifdef SYS_shmget - "shmget" -#endif - }, - { .name = "@keyring", .list = -#ifdef SYS_add_key - "add_key," -#endif -#ifdef SYS_keyctl - "keyctl," -#endif -#ifdef SYS_request_key - "request_key" -#endif - }, - { .name = "@memlock", .list = -#ifdef SYS_mlock - "mlock," -#endif -#ifdef SYS_mlock2 - "mlock2," -#endif -#ifdef SYS_mlockall - "mlockall," -#endif -#ifdef SYS_munlock - "munlock," -#endif -#ifdef SYS_munlockall - "munlockall" -#endif - }, - { .name = "@module", .list = -#ifdef SYS_delete_module - "delete_module," -#endif -#ifdef SYS_finit_module - "finit_module," -#endif -#ifdef SYS_init_module - "init_module" -#endif - }, - { .name = "@mount", .list = -#ifdef SYS_chroot - "chroot," -#endif -#ifdef SYS_mount - "mount," -#endif -#ifdef SYS_pivot_root - "pivot_root," -#endif -#ifdef SYS_umount - "umount," -#endif -#ifdef SYS_umount2 - "umount2" -#endif - }, - { .name = "@network-io", .list = -#ifdef SYS_accept - "accept," -#endif -#ifdef SYS_accept4 - "accept4," -#endif -#ifdef SYS_bind - "bind," -#endif -#ifdef SYS_connect - "connect," -#endif -#ifdef SYS_getpeername - "getpeername," -#endif -#ifdef SYS_getsockname - "getsockname," -#endif -#ifdef SYS_getsockopt - "getsockopt," -#endif -#ifdef SYS_listen - "listen," -#endif -#ifdef SYS_recv - "recv," -#endif -#ifdef SYS_recvfrom - "recvfrom," -#endif -#ifdef SYS_recvmmsg - "recvmmsg," -#endif -#ifdef SYS_recvmsg - "recvmsg," -#endif -#ifdef SYS_send - "send," -#endif -#ifdef SYS_sendmmsg - "sendmmsg," -#endif -#ifdef SYS_sendmsg - "sendmsg," -#endif -#ifdef SYS_sendto - "sendto," -#endif -#ifdef SYS_setsockopt - "setsockopt," -#endif -#ifdef SYS_shutdown - "shutdown," -#endif -#ifdef SYS_socket - "socket," -#endif -#ifdef SYS_socketcall - "socketcall," -#endif -#ifdef SYS_socketpair - "socketpair" -#endif - }, - { .name = "@obsolete", .list = -#ifdef SYS__sysctl - "_sysctl," -#endif -#ifdef SYS_afs_syscall - "afs_syscall," -#endif -#ifdef SYS_bdflush - "bdflush," -#endif -#ifdef SYS_break - "break," -#endif -#ifdef SYS_create_module - "create_module," -#endif -#ifdef SYS_ftime - "ftime," -#endif -#ifdef SYS_get_kernel_syms - "get_kernel_syms," -#endif -#ifdef SYS_getpmsg - "getpmsg," -#endif -#ifdef SYS_gtty - "gtty," -#endif -#ifdef SYS_idle - "idle," -#endif -#ifdef SYS_lock - "lock," -#endif -#ifdef SYS_mpx - "mpx," -#endif -#ifdef SYS_prof - "prof," -#endif -#ifdef SYS_profil - "profil," -#endif -#ifdef SYS_putpmsg - "putpmsg," -#endif -#ifdef SYS_query_module - "query_module," -#endif -#ifdef SYS_security - "security," -#endif -#ifdef SYS_sgetmask - "sgetmask," -#endif -#ifdef SYS_ssetmask - "ssetmask," -#endif -#ifdef SYS_stty - "stty," -#endif -#ifdef SYS_sysfs - "sysfs," -#endif -#ifdef SYS_tuxcall - "tuxcall," -#endif -#ifdef SYS_ulimit - "ulimit," -#endif -#ifdef SYS_uselib - "uselib," -#endif -#ifdef SYS_ustat - "ustat," -#endif -#ifdef SYS_vserver - "vserver" -#endif -#if !defined(SYS__sysctl) && !defined(SYS_afs_syscall) && !defined(SYS_bdflush) && !defined(SYS_break) && !defined(SYS_create_module) && !defined(SYS_ftime) && !defined(SYS_get_kernel_syms) && !defined(SYS_getpmsg) && !defined(SYS_gtty) && !defined(SYS_lock) && !defined(SYS_mpx) && !defined(SYS_prof) && !defined(SYS_profil) && !defined(SYS_putpmsg) && !defined(SYS_query_module) && !defined(SYS_security) && !defined(SYS_sgetmask) && !defined(SYS_ssetmask) && !defined(SYS_stty) && !defined(SYS_sysfs) && !defined(SYS_tuxcall) && !defined(SYS_ulimit) && !defined(SYS_uselib) && !defined(SYS_ustat) && !defined(SYS_vserver) - "__dummy_syscall__" // workaround for arm64 which doesn't have any of above defined and empty syscall lists are not allowed -#endif - }, - { .name = "@privileged", .list = - "@chown," - "@clock," - "@module," - "@raw-io," - "@reboot," - "@swap," -#ifdef SYS__sysctl - "_sysctl," -#endif -#ifdef SYS_acct - "acct," -#endif -#ifdef SYS_bpf - "bpf," -#endif -#ifdef SYS_capset - "capset," -#endif -#ifdef SYS_chroot - "chroot," -#endif -#ifdef SYS_fanotify_init - "fanotify_init," -#endif -#ifdef SYS_mount - "mount," -#endif -#ifdef SYS_nfsservctl - "nfsservctl," -#endif -#ifdef SYS_open_by_handle_at - "open_by_handle_at," -#endif -#ifdef SYS_pivot_root - "pivot_root," -#endif -#ifdef SYS_quotactl - "quotactl," -#endif -#ifdef SYS_setdomainname - "setdomainname," -#endif -#ifdef SYS_setfsuid - "setfsuid," -#endif -#ifdef SYS_setfsuid32 - "setfsuid32," -#endif -#ifdef SYS_setgroups - "setgroups," -#endif -#ifdef SYS_setgroups32 - "setgroups32," -#endif -#ifdef SYS_sethostname - "sethostname," -#endif -#ifdef SYS_setresuid - "setresuid," -#endif -#ifdef SYS_setresuid32 - "setresuid32," -#endif -#ifdef SYS_setreuid - "setreuid," -#endif -#ifdef SYS_setreuid32 - "setreuid32," -#endif -#ifdef SYS_setuid - "setuid," -#endif -#ifdef SYS_setuid32 - "setuid32," -#endif -#ifdef SYS_umount2 - "umount2," -#endif -#ifdef SYS_vhangup - "vhangup" -#endif - }, - { .name = "@process", .list = -#ifdef SYS_arch_prctl - "arch_prctl," -#endif -#ifdef SYS_capget - "capget," -#endif -#ifdef SYS_clone - "clone," -#endif -#ifdef SYS_execveat - "execveat," -#endif -#ifdef SYS_fork - "fork," -#endif -#ifdef SYS_getrusage - "getrusage," -#endif -#ifdef SYS_kill - "kill," -#endif -#ifdef SYS_pidfd_send_signal - "pidfd_send_signal," -#endif -#ifdef SYS_prctl - "prctl," -#endif -#ifdef SYS_rt_sigqueueinfo - "rt_sigqueueinfo," -#endif -#ifdef SYS_rt_tgsigqueueinfo - "rt_tgsigqueueinfo," -#endif -#ifdef SYS_setns - "setns," -#endif -#ifdef SYS_swapcontext - "swapcontext," -#endif -#ifdef SYS_tgkill - "tgkill," -#endif -#ifdef SYS_times - "times," -#endif -#ifdef SYS_tkill - "tkill," -#endif -#ifdef SYS_unshare - "unshare," -#endif -#ifdef SYS_vfork - "vfork," -#endif -#ifdef SYS_wait4 - "wait4," -#endif -#ifdef SYS_waitid - "waitid," -#endif -#ifdef SYS_waitpid - "waitpid" -#endif - }, - { .name = "@raw-io", .list = -#ifdef SYS_ioperm - "ioperm," -#endif -#ifdef SYS_iopl - "iopl," -#endif -#ifdef SYS_pciconfig_iobase - "pciconfig_iobase," -#endif -#ifdef SYS_pciconfig_read - "pciconfig_read," -#endif -#ifdef SYS_pciconfig_write - "pciconfig_write," -#endif -#ifdef SYS_s390_mmio_read - "s390_mmio_read," -#endif -#ifdef SYS_s390_mmio_write - "s390_mmio_write" -#endif -#if !defined(SYS_ioperm) && !defined(SYS_iopl) && !defined(SYS_pciconfig_iobase) && !defined(SYS_pciconfig_read) && !defined(SYS_pciconfig_write) && !defined(SYS_s390_mmio_read) && !defined(SYS_s390_mmio_write) - "__dummy_syscall__" // workaround for s390x which doesn't have any of above defined and empty syscall lists are not allowed -#endif - }, - { .name = "@reboot", .list = -#ifdef SYS_kexec_load - "kexec_load," -#endif -#ifdef SYS_kexec_file_load - "kexec_file_load," -#endif -#ifdef SYS_reboot - "reboot," -#endif - }, - { .name = "@resources", .list = -#ifdef SYS_ioprio_set - "ioprio_set," -#endif -#ifdef SYS_mbind - "mbind," -#endif -#ifdef SYS_migrate_pages - "migrate_pages," -#endif -#ifdef SYS_move_pages - "move_pages," -#endif -#ifdef SYS_nice - "nice," -#endif -#ifdef SYS_sched_setaffinity - "sched_setaffinity," -#endif -#ifdef SYS_sched_setattr - "sched_setattr," -#endif -#ifdef SYS_sched_setparam - "sched_setparam," -#endif -#ifdef SYS_sched_setscheduler - "sched_setscheduler," -#endif -#ifdef SYS_set_mempolicy - "set_mempolicy" -#endif - }, - { .name = "@setuid", .list = -#ifdef SYS_setgid - "setgid," -#endif -#ifdef SYS_setgid32 - "setgid32," -#endif -#ifdef SYS_setgroups - "setgroups," -#endif -#ifdef SYS_setgroups32 - "setgroups32," -#endif -#ifdef SYS_setregid - "setregid," -#endif -#ifdef SYS_setregid32 - "setregid32," -#endif -#ifdef SYS_setresgid - "setresgid," -#endif -#ifdef SYS_setresgid32 - "setresgid32," -#endif -#ifdef SYS_setresuid - "setresuid," -#endif -#ifdef SYS_setresuid32 - "setresuid32," -#endif -#ifdef SYS_setreuid - "setreuid," -#endif -#ifdef SYS_setreuid32 - "setreuid32," -#endif -#ifdef SYS_setuid - "setuid," -#endif -#ifdef SYS_setuid32 - "setuid32" -#endif - }, - { .name = "@signal", .list = -#ifdef SYS_rt_sigaction - "rt_sigaction," -#endif -#ifdef SYS_rt_sigpending - "rt_sigpending," -#endif -#ifdef SYS_rt_sigprocmask - "rt_sigprocmask," -#endif -#ifdef SYS_rt_sigsuspend - "rt_sigsuspend," -#endif -#ifdef SYS_rt_sigtimedwait - "rt_sigtimedwait," -#endif -#ifdef SYS_sigaction - "sigaction," -#endif -#ifdef SYS_sigaltstack - "sigaltstack," -#endif -#ifdef SYS_signal - "signal," -#endif -#ifdef SYS_signalfd - "signalfd," -#endif -#ifdef SYS_signalfd4 - "signalfd4," -#endif -#ifdef SYS_sigpending - "sigpending," -#endif -#ifdef SYS_sigprocmask - "sigprocmask," -#endif -#ifdef SYS_sigsuspend - "sigsuspend" -#endif - }, - { .name = "@swap", .list = -#ifdef SYS_swapon - "swapon," -#endif -#ifdef SYS_swapoff - "swapoff" -#endif - }, - { .name = "@sync", .list = -#ifdef SYS_fdatasync - "fdatasync," -#endif -#ifdef SYS_fsync - "fsync," -#endif -#ifdef SYS_msync - "msync," -#endif -#ifdef SYS_sync - "sync," -#endif -#ifdef SYS_sync_file_range - "sync_file_range," -#endif -#ifdef SYS_sync_file_range2 - "sync_file_range2," -#endif -#ifdef SYS_syncfs - "syncfs" -#endif - }, - { .name = "@system-service", .list = - "@aio," - "@basic-io," - "@chown," - "@default," - "@file-system," - "@io-event," - "@ipc," - "@keyring," - "@memlock," - "@network-io," - "@process," - "@resources," - "@setuid," - "@signal," - "@sync," - "@timer," -#ifdef SYS_brk - "brk," -#endif -#ifdef SYS_capget - "capget," -#endif -#ifdef SYS_capset - "capset," -#endif -#ifdef SYS_copy_file_range - "copy_file_range," -#endif -#ifdef SYS_fadvise64 - "fadvise64," -#endif -#ifdef SYS_fadvise64_64 - "fadvise64_64," -#endif -#ifdef SYS_flock - "flock," -#endif -#ifdef SYS_get_mempolicy - "get_mempolicy," -#endif -#ifdef SYS_getcpu - "getcpu," -#endif -#ifdef SYS_getpriority - "getpriority," -#endif -#ifdef SYS_getrandom - "getrandom," -#endif -#ifdef SYS_ioctl - "ioctl," -#endif -#ifdef SYS_ioprio_get - "ioprio_get," -#endif -#ifdef SYS_kcmp - "kcmp," -#endif -#ifdef SYS_madvise - "madvise," -#endif -#ifdef SYS_mprotect - "mprotect," -#endif -#ifdef SYS_mremap - "mremap," -#endif -#ifdef SYS_name_to_handle_at - "name_to_handle_at," -#endif -#ifdef SYS_oldolduname - "oldolduname," -#endif -#ifdef SYS_olduname - "olduname," -#endif -#ifdef SYS_personality - "personality," -#endif -#ifdef SYS_readahead - "readahead," -#endif -#ifdef SYS_readdir - "readdir," -#endif -#ifdef SYS_remap_file_pages - "remap_file_pages," -#endif -#ifdef SYS_sched_get_priority_max - "sched_get_priority_max," -#endif -#ifdef SYS_sched_get_priority_min - "sched_get_priority_min," -#endif -#ifdef SYS_sched_getaffinity - "sched_getaffinity," -#endif -#ifdef SYS_sched_getattr - "sched_getattr," -#endif -#ifdef SYS_sched_getparam - "sched_getparam," -#endif -#ifdef SYS_sched_getscheduler - "sched_getscheduler," -#endif -#ifdef SYS_sched_rr_get_interval - "sched_rr_get_interval," -#endif -#ifdef SYS_sched_yield - "sched_yield," -#endif -#ifdef SYS_sendfile - "sendfile," -#endif -#ifdef SYS_sendfile64 - "sendfile64," -#endif -#ifdef SYS_setfsgid - "setfsgid," -#endif -#ifdef SYS_setfsgid32 - "setfsgid32," -#endif -#ifdef SYS_setfsuid - "setfsuid," -#endif -#ifdef SYS_setfsuid32 - "setfsuid32," -#endif -#ifdef SYS_setpgid - "setpgid," -#endif -#ifdef SYS_setsid - "setsid," -#endif -#ifdef SYS_splice - "splice," -#endif -#ifdef SYS_sysinfo - "sysinfo," -#endif -#ifdef SYS_tee - "tee," -#endif -#ifdef SYS_umask - "umask," -#endif -#ifdef SYS_uname - "uname," -#endif -#ifdef SYS_userfaultfd - "userfaultfd," -#endif -#ifdef SYS_vmsplice - "vmsplice" -#endif - }, - { .name = "@timer", .list = -#ifdef SYS_alarm - "alarm," -#endif -#ifdef SYS_getitimer - "getitimer," -#endif -#ifdef SYS_setitimer - "setitimer," -#endif -#ifdef SYS_timer_create - "timer_create," -#endif -#ifdef SYS_timer_delete - "timer_delete," -#endif -#ifdef SYS_timer_getoverrun - "timer_getoverrun," -#endif -#ifdef SYS_timer_gettime - "timer_gettime," -#endif -#ifdef SYS_timer_settime - "timer_settime," -#endif -#ifdef SYS_timerfd_create - "timerfd_create," -#endif -#ifdef SYS_timerfd_gettime - "timerfd_gettime," -#endif -#ifdef SYS_timerfd_settime - "timerfd_settime," -#endif -#ifdef SYS_times - "times" -#endif - } -}; - -// return -1 if error, or syscall number -static int syscall_find_name(const char *name) { - int i; - int elems = sizeof(syslist) / sizeof(syslist[0]); - for (i = 0; i < elems; i++) { - if (strcmp(name, syslist[i].name) == 0) - return syslist[i].nr; - } - - return -1; -} - -const char *syscall_find_nr(int nr) { - int i; - int elems = sizeof(syslist) / sizeof(syslist[0]); - for (i = 0; i < elems; i++) { - if (nr == syslist[i].nr) - return syslist[i].name; - } - - return "unknown"; -} - -void syscall_print(void) { - int i; - int elems = sizeof(syslist) / sizeof(syslist[0]); - for (i = 0; i < elems; i++) { - printf("%d\t- %s\n", syslist[i].nr, syslist[i].name); - } - printf("\n"); -} - -static const char *syscall_find_group(const char *name) { - int i; - int elems = sizeof(sysgroups) / sizeof(sysgroups[0]); - for (i = 0; i < elems; i++) { - if (strcmp(name, sysgroups[i].name) == 0) - return sysgroups[i].list; - } - - return NULL; -} - -// allowed input: -// - syscall -// - syscall(error) -static void syscall_process_name(const char *name, int *syscall_nr, int *error_nr) { - assert(name); - if (strlen(name) == 0) - goto error; - *error_nr = -1; - - // syntax check - char *str = strdup(name); - if (!str) - errExit("strdup"); - - char *syscall_name = str; - char *error_name = strchr(str, ':'); - if (error_name) { - *error_name = '\0'; - error_name++; - } - if (strlen(syscall_name) == 0) { - free(str); - goto error; - } - - if (*syscall_name == '$') - *syscall_nr = strtol(syscall_name + 1, NULL, 0); - else - *syscall_nr = syscall_find_name(syscall_name); - if (error_name) { - *error_nr = errno_find_name(error_name); - if (*error_nr == -1) - *syscall_nr = -1; - } - - free(str); - return; - -error: - fprintf(stderr, "Error fseccomp: invalid syscall list entry %s\n", name); - exit(1); -} - -// return 1 if error, 0 if OK -int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg, void *ptrarg), int fd, int arg, void *ptrarg) { - // don't allow empty lists - if (slist == NULL || *slist == '\0') { - fprintf(stderr, "Error fseccomp: empty syscall lists are not allowed\n"); - exit(1); - } - - // work on a copy of the string - char *str = strdup(slist); - if (!str) - errExit("strdup"); - - char *saveptr; - char *ptr = strtok_r(str, ",", &saveptr); - if (ptr == NULL) { - fprintf(stderr, "Error fseccomp: empty syscall lists are not allowed\n"); - exit(1); - } - - while (ptr) { - int syscall_nr; - int error_nr; - if (*ptr == '@') { - const char *new_list = syscall_find_group(ptr); - if (!new_list) { - fprintf(stderr, "Error fseccomp: unknown syscall group %s\n", ptr); - exit(1); - } - 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); - } - else if (error_nr != -1 && fd == 0) { - callback(fd, syscall_nr, error_nr, ptrarg); - } - else { - callback(fd, syscall_nr, arg, ptrarg); - } - } - } - ptr = strtok_r(NULL, ",", &saveptr); - } - - free(str); - return 0; -} - -static void find_syscall(int fd, int syscall, int arg, void *ptrarg) { - (void)fd; - (void) arg; - SyscallCheckList *ptr = ptrarg; - if (abs(syscall) == ptr->syscall) - ptr->found = true; -} - -// go through list2 and find matches for problem syscall -static void syscall_in_list(int fd, int syscall, int arg, void *ptrarg) { - (void) fd; - (void)arg; - SyscallCheckList *ptr = ptrarg; - SyscallCheckList sl; - sl.found = false; - sl.syscall = syscall; - syscall_check_list(ptr->slist, find_syscall, fd, 0, &sl); - // if found in the problem list, add to post-exec list - if (sl.found) { - if (ptr->postlist) { - if (asprintf(&ptr->postlist, "%s,%s", ptr->postlist, syscall_find_nr(syscall)) == -1) - errExit("asprintf"); - } - else - ptr->postlist = strdup(syscall_find_nr(syscall)); - } - else { // no problem, add to pre-exec list - // build syscall:error_no - char *newcall = NULL; - if (arg != 0) { - if (asprintf(&newcall, "%s:%s", syscall_find_nr(syscall), errno_find_nr(arg)) == -1) - errExit("asprintf"); - } - else { - newcall = strdup(syscall_find_nr(syscall)); - if (!newcall) - errExit("strdup"); - } - - if (ptr->prelist) { - if (asprintf(&ptr->prelist, "%s,%s", ptr->prelist, newcall) == -1) - errExit("asprintf"); - free(newcall); - } - else - ptr->prelist = newcall; - } -} - -// go through list and find matches for syscalls in list @default-keep -void syscalls_in_list(const char *list, const char *slist, int fd, char **prelist, char **postlist) { - (void) fd; - SyscallCheckList sl; - // these syscalls are used by firejail after the seccomp filter is initialized - sl.slist = slist; - sl.prelist = NULL; - sl.postlist = NULL; - syscall_check_list(list, syscall_in_list, 0, 0, &sl); - if (!arg_quiet) { - printf("Seccomp list in: %s,", list); - if (sl.slist) - printf(" check list: %s,", sl.slist); - if (sl.prelist) - printf(" prelist: %s,", sl.prelist); - if (sl.postlist) - printf(" postlist: %s", sl.postlist); - printf("\n"); - } - *prelist = sl.prelist; - *postlist = sl.postlist; -} -- cgit v1.2.3-54-g00ecf