From d01216de45884300c87e7d3ccb70e53ebb461449 Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Sat, 19 Aug 2017 23:22:38 +0300 Subject: Feature: switch/config option to block secondary architectures Add a feature for a new (opt-in) command line switch and config file option to block secondary architectures entirely. Also block changing Linux execution domain with personality() system call for the primary architecture. Closes #1479 --- src/fseccomp/fseccomp.h | 1 + src/fseccomp/main.c | 3 ++ src/fseccomp/seccomp_print.c | 19 ++++++++ src/fseccomp/seccomp_secondary.c | 97 ++++++++++++++++++++++++++-------------- 4 files changed, 87 insertions(+), 33 deletions(-) (limited to 'src/fseccomp') diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index 144b612ae..2deb282f5 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h @@ -46,6 +46,7 @@ void protocol_build_filter(const char *prlist, const char *fname); // seccomp_secondary.c void seccomp_secondary_64(const char *fname); 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); diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 3bf7de0fa..ae0ae64ef 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c @@ -28,6 +28,7 @@ static void usage(void) { printf("\tfseccomp protocol build list file\n"); printf("\tfseccomp secondary 64 file\n"); printf("\tfseccomp secondary 32 file\n"); + printf("\tfseccomp secondary block file\n"); printf("\tfseccomp default file\n"); printf("\tfseccomp default file allow-debuggers\n"); printf("\tfseccomp drop file1 file2 list\n"); @@ -74,6 +75,8 @@ printf("\n"); seccomp_secondary_64(argv[3]); else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "32") == 0) seccomp_secondary_32(argv[3]); + 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); else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) diff --git a/src/fseccomp/seccomp_print.c b/src/fseccomp/seccomp_print.c index 19fe7a545..7af95d51c 100644 --- a/src/fseccomp/seccomp_print.c +++ b/src/fseccomp/seccomp_print.c @@ -113,6 +113,25 @@ static int detect_filter_type(void) { printf(" EXAMINE_SYSCALL\n"); return sizeof(start_secondary_32) / sizeof(struct sock_filter); } + + const struct sock_filter start_secondary_block[] = { + VALIDATE_ARCHITECTURE_KILL, +#if defined(__x86_64__) + EXAMINE_SYSCALL, + HANDLE_X32_KILL, +#else + EXAMINE_SYSCALL +#endif + }; + + if (memcmp(&start_secondary_block[0], filter, sizeof(start_secondary_block)) == 0) { + printf(" VALIDATE_ARCHITECTURE_KILL\n"); + printf(" EXAMINE_SYSCALL\n"); +#if defined(__x86_64__) + printf(" HANDLE_X32_KILL\n"); +#endif + return sizeof(start_secondary_block) / sizeof(struct sock_filter); + } return 0; // filter unrecognized } diff --git a/src/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c index fceb2c3ec..dd69b58cc 100644 --- a/src/fseccomp/seccomp_secondary.c +++ b/src/fseccomp/seccomp_secondary.c @@ -19,8 +19,29 @@ */ #include "fseccomp.h" #include "../include/seccomp.h" +#include #include +static void write_filter(const char *fname, size_t size, const void *filter) { + // save filter to file + int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (dst < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + size_t written = 0; + while (written < size) { + ssize_t rv = write(dst, (unsigned char *) filter + written, size - written); + if (rv == -1) { + fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); + exit(1); + } + written += rv; + } + close(dst); +} + void seccomp_secondary_64(const char *fname) { // hardcoded syscall values struct sock_filter filter[] = { @@ -84,23 +105,7 @@ void seccomp_secondary_64(const char *fname) { }; // save filter to file - int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (dst < 0) { - fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); - exit(1); - } - - int size = (int) sizeof(filter); - int written = 0; - while (written < size) { - int rv = write(dst, (unsigned char *) filter + written, size - written); - if (rv == -1) { - fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); - exit(1); - } - written += rv; - } - close(dst); + write_filter(fname, sizeof(filter), filter); } // i386 filter installed on amd64 architectures @@ -166,21 +171,47 @@ void seccomp_secondary_32(const char *fname) { }; // save filter to file - int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (dst < 0) { - fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); - exit(1); - } + write_filter(fname, sizeof(filter), filter); +} - int size = (int) sizeof(filter); - int written = 0; - while (written < size) { - int rv = write(dst, (unsigned char *) filter + written, size - written); - if (rv == -1) { - fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); - exit(1); - } - written += rv; - } - close(dst); +#define jmp_from_to(from_addr, to_addr) ((to_addr) - (from_addr) - 1) + +#if __BYTE_ORDER == __BIG_ENDIAN +#define MSW 0 +#define LSW (sizeof(int)) +#else +#define MSW (sizeof(int)) +#define LSW 0 +#endif + +void seccomp_secondary_block(const char *fname) { + struct sock_filter filter[] = { + // block other architectures + VALIDATE_ARCHITECTURE_KILL, + EXAMINE_SYSCALL, +#if defined(__x86_64__) + // block x32 + HANDLE_X32_KILL, +#endif + // block personality(2) where domain != PER_LINUX or 0xffffffff (query current personality) + // 0: if personality(2), continue to 1, else goto 7 (allow) + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYS_personality, 0, jmp_from_to(0, 7)), + // 1: get LSW of system call argument 0 + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, args[0])) + LSW), + // 2: if LSW(arg0) == PER_LINUX, goto step 4, else continue to 3 + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, PER_LINUX, jmp_from_to(2, 4), 0), + // 3: if LSW(arg0) == 0xffffffff, continue to 4, else goto 6 (kill) + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 0, jmp_from_to(3, 6)), + // 4: get MSW of system call argument 0 + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, args[0])) + MSW), + // 5: if MSW(arg0) == 0, goto 7 (allow) else continue to 6 (kill) + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, jmp_from_to(5, 7), 0), + // 6: + KILL_PROCESS, + // 7: + RETURN_ALLOW + }; + + // save filter to file + write_filter(fname, sizeof(filter), filter); } -- cgit v1.2.3-54-g00ecf