From f9c60d5a3aaecc11b1dbb933bca45c461b03ca83 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Thu, 28 Dec 2017 12:28:08 -0500 Subject: replacing seccomp printing with a seccomp disassembler --- src/firejail/firejail.h | 1 + src/firejail/seccomp.c | 20 +-- src/fsec-print/Makefile.in | 45 ++++++ src/fsec-print/fsec_print.h | 32 ++++ src/fsec-print/main.c | 81 ++++++++++ src/fsec-print/print.c | 334 ++++++++++++++++++++++++++++++++++++++++++ src/fsec-print/syscall_list.c | 47 ++++++ src/fseccomp/main.c | 3 - src/fseccomp/seccomp_print.c | 183 ----------------------- src/include/seccomp.h | 14 ++ 10 files changed, 564 insertions(+), 196 deletions(-) create mode 100644 src/fsec-print/Makefile.in create mode 100644 src/fsec-print/fsec_print.h create mode 100644 src/fsec-print/main.c create mode 100644 src/fsec-print/print.c create mode 100644 src/fsec-print/syscall_list.c delete mode 100644 src/fseccomp/seccomp_print.c (limited to 'src') diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 3df6af7b6..a009c4e65 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -771,6 +771,7 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, #define PATH_FIREMON (PREFIX "/bin/firemon") #define PATH_FIREJAIL (PREFIX "/bin/firejail") #define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") +#define PATH_FSEC_PRINT (LIBDIR "/firejail/fsec-print") #define PATH_FCOPY (LIBDIR "/firejail/fcopy") #define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" #define PATH_FLDD (LIBDIR "/firejail/fldd") diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index e75863c3a..9c32f2169 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c @@ -126,9 +126,9 @@ int seccomp_load(const char *fname) { errExit("strdup"); filter_list_head = fl; - if (arg_debug && access(PATH_FSECCOMP, X_OK) == 0) { - sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, - PATH_FSECCOMP, "print", fname); + if (arg_debug && access(PATH_FSEC_PRINT, X_OK) == 0) { + sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, + PATH_FSEC_PRINT, fname); } return 0; @@ -240,12 +240,12 @@ int seccomp_filter_drop(void) { printf("seccomp filter configured\n"); } - if (arg_debug && access(PATH_FSECCOMP, X_OK) == 0) { + if (arg_debug && access(PATH_FSEC_PRINT, X_OK) == 0) { struct stat st; if (stat(RUN_SECCOMP_POSTEXEC, &st) != -1 && st.st_size != 0) { printf("configuring postexec seccomp filter in %s\n", RUN_SECCOMP_POSTEXEC); - sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, - PATH_FSECCOMP, "print", RUN_SECCOMP_POSTEXEC); + sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, + PATH_FSEC_PRINT, RUN_SECCOMP_POSTEXEC); } } @@ -280,12 +280,12 @@ int seccomp_filter_keep(void) { printf("seccomp filter configured\n"); } - if (arg_debug && access(PATH_FSECCOMP, X_OK) == 0) { + if (arg_debug && access(PATH_FSEC_PRINT, X_OK) == 0) { struct stat st; if (stat(RUN_SECCOMP_POSTEXEC, &st) != -1 && st.st_size != 0) { printf("configuring postexec seccomp filter in %s\n", RUN_SECCOMP_POSTEXEC); - sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, - PATH_FSECCOMP, "print", RUN_SECCOMP_POSTEXEC); + sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, + PATH_FSEC_PRINT, RUN_SECCOMP_POSTEXEC); } } @@ -332,7 +332,7 @@ void seccomp_print_filter(pid_t pid) { } // read and print the filter - run this as root, the user doesn't have access - sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FSECCOMP, "print", fname); + sbox_run(SBOX_ROOT | SBOX_SECCOMP, 2, PATH_FSEC_PRINT, fname); free(fname); exit(0); diff --git a/src/fsec-print/Makefile.in b/src/fsec-print/Makefile.in new file mode 100644 index 000000000..5d23382f7 --- /dev/null +++ b/src/fsec-print/Makefile.in @@ -0,0 +1,45 @@ +all: fsec-print + +CC=@CC@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sysconfdir=@sysconfdir@ + +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ +HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ +HAVE_SECCOMP=@HAVE_SECCOMP@ +HAVE_CHROOT=@HAVE_CHROOT@ +HAVE_BIND=@HAVE_BIND@ +HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ +HAVE_NETWORK=@HAVE_NETWORK@ +HAVE_USERNS=@HAVE_USERNS@ +HAVE_X11=@HAVE_X11@ +HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ +HAVE_WHITELIST=@HAVE_WHITELIST@ +HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ +HAVE_APPARMOR=@HAVE_APPARMOR@ +HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ +HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ +EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ +HAVE_GCOV=@HAVE_GCOV@ +EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ + +H_FILE_LIST = $(sort $(wildcard *.[h])) +C_FILE_LIST = $(sort $(wildcard *.c)) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread + +%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/seccomp.h ../include/syscall.h + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +fsec-print: $(OBJS) ../lib/libnetlink.o + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) + +clean:; rm -f *.o fsec-print *.gcov *.gcda *.gcno + +distclean: clean + rm -fr Makefile diff --git a/src/fsec-print/fsec_print.h b/src/fsec-print/fsec_print.h new file mode 100644 index 000000000..d3f4a4df9 --- /dev/null +++ b/src/fsec-print/fsec_print.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014-2017 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. +*/ +#ifndef FSEC_PRINT_H +#define FSEC_PRINT_H +#include "../include/common.h" +#include "../include/seccomp.h" +#include + +// print.c +void print(struct sock_filter *filter, int entries); + +// syscall_list.c +const char *syscall_find_nr(int nr); + +#endif \ No newline at end of file diff --git a/src/fsec-print/main.c b/src/fsec-print/main.c new file mode 100644 index 000000000..e8639b822 --- /dev/null +++ b/src/fsec-print/main.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014-2017 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 "fsec_print.h" + +static void usage(void) { + printf("Usage:\n"); + printf("\tfsec-print file - disassemble seccomp filter\n"); +} + +int main(int argc, char **argv) { +#if 0 +{ +//system("cat /proc/self/status"); +int i; +for (i = 0; i < argc; i++) + printf("*%s* ", argv[i]); +printf("\n"); +} +#endif + if (argc != 2) { + usage(); + return 1; + } + + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { + usage(); + return 0; + } + + char *fname = argv[1]; + + // open input file + int fd = open(fname, O_RDONLY); + if (fd == -1) + goto errexit; + + // calculate the number of entries + int size = lseek(fd, 0, SEEK_END); + if (size == -1) // todo: check maximum size of seccomp filter (4KB?) + goto errexit; + unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); + + // read filter + struct sock_filter *filter = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (filter == MAP_FAILED) + goto errexit; + + + // print filter + print(filter, entries); + + // free mapped memory + if (munmap(filter, size) == -1) + perror("Error un-mmapping the file"); + + // close file + close(fd); + return 0; +errexit: + close(fd); + fprintf(stderr, "Error: cannot read %s\n", fname); + exit(1); + +} diff --git a/src/fsec-print/print.c b/src/fsec-print/print.c new file mode 100644 index 000000000..964a3a8a9 --- /dev/null +++ b/src/fsec-print/print.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2014-2017 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. + * + * + * + * Parts of this code was lifted from libseccomp project, license LGPV 2.1. + * This is the original copyright notice in libseccomp code: + * + * + * + * BPF Disassembler + * + * Copyright (c) 2012 Red Hat + * Author: Paul Moore + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include "fsec_print.h" + +// From /usr/include/linux/filter.h +//struct sock_filter { /* Filter block */ +// __u16 code; /* Actual filter code */ +// __u8 jt; /* Jump true */ +// __u8 jf; /* Jump false */ +// __u32 k; /* Generic multiuse field */ +//}; + + +static const char *bpf_decode_op(const struct sock_filter *bpf) { + switch (bpf->code) { + case BPF_LD+BPF_W+BPF_IMM: + case BPF_LD+BPF_W+BPF_ABS: + case BPF_LD+BPF_W+BPF_IND: + case BPF_LD+BPF_W+BPF_MEM: + case BPF_LD+BPF_W+BPF_LEN: + case BPF_LD+BPF_W+BPF_MSH: + return "ld"; + case BPF_LD+BPF_H+BPF_IMM: + case BPF_LD+BPF_H+BPF_ABS: + case BPF_LD+BPF_H+BPF_IND: + case BPF_LD+BPF_H+BPF_MEM: + case BPF_LD+BPF_H+BPF_LEN: + case BPF_LD+BPF_H+BPF_MSH: + return "ldh"; + case BPF_LD+BPF_B+BPF_IMM: + case BPF_LD+BPF_B+BPF_ABS: + case BPF_LD+BPF_B+BPF_IND: + case BPF_LD+BPF_B+BPF_MEM: + case BPF_LD+BPF_B+BPF_LEN: + case BPF_LD+BPF_B+BPF_MSH: + return "ldb"; + case BPF_LDX+BPF_W+BPF_IMM: + case BPF_LDX+BPF_W+BPF_ABS: + case BPF_LDX+BPF_W+BPF_IND: + case BPF_LDX+BPF_W+BPF_MEM: + case BPF_LDX+BPF_W+BPF_LEN: + case BPF_LDX+BPF_W+BPF_MSH: + case BPF_LDX+BPF_H+BPF_IMM: + case BPF_LDX+BPF_H+BPF_ABS: + case BPF_LDX+BPF_H+BPF_IND: + case BPF_LDX+BPF_H+BPF_MEM: + case BPF_LDX+BPF_H+BPF_LEN: + case BPF_LDX+BPF_H+BPF_MSH: + case BPF_LDX+BPF_B+BPF_IMM: + case BPF_LDX+BPF_B+BPF_ABS: + case BPF_LDX+BPF_B+BPF_IND: + case BPF_LDX+BPF_B+BPF_MEM: + case BPF_LDX+BPF_B+BPF_LEN: + case BPF_LDX+BPF_B+BPF_MSH: + return "ldx"; + case BPF_ST: + return "st"; + case BPF_STX: + return "stx"; + case BPF_ALU+BPF_ADD+BPF_K: + case BPF_ALU+BPF_ADD+BPF_X: + return "add"; + case BPF_ALU+BPF_SUB+BPF_K: + case BPF_ALU+BPF_SUB+BPF_X: + return "sub"; + case BPF_ALU+BPF_MUL+BPF_K: + case BPF_ALU+BPF_MUL+BPF_X: + return "mul"; + case BPF_ALU+BPF_DIV+BPF_K: + case BPF_ALU+BPF_DIV+BPF_X: + return "div"; + case BPF_ALU+BPF_OR+BPF_K: + case BPF_ALU+BPF_OR+BPF_X: + return "or"; + case BPF_ALU+BPF_AND+BPF_K: + case BPF_ALU+BPF_AND+BPF_X: + return "and"; + case BPF_ALU+BPF_LSH+BPF_K: + case BPF_ALU+BPF_LSH+BPF_X: + return "lsh"; + case BPF_ALU+BPF_RSH+BPF_K: + case BPF_ALU+BPF_RSH+BPF_X: + return "rsh"; + case BPF_ALU+BPF_NEG+BPF_K: + case BPF_ALU+BPF_NEG+BPF_X: + return "neg"; + case BPF_ALU+BPF_MOD+BPF_K: + case BPF_ALU+BPF_MOD+BPF_X: + return "mod"; + case BPF_ALU+BPF_XOR+BPF_K: + case BPF_ALU+BPF_XOR+BPF_X: + return "xor"; + case BPF_JMP+BPF_JA+BPF_K: + case BPF_JMP+BPF_JA+BPF_X: + return "jmp"; + case BPF_JMP+BPF_JEQ+BPF_K: + case BPF_JMP+BPF_JEQ+BPF_X: + return "jeq"; + case BPF_JMP+BPF_JGT+BPF_K: + case BPF_JMP+BPF_JGT+BPF_X: + return "jgt"; + case BPF_JMP+BPF_JGE+BPF_K: + case BPF_JMP+BPF_JGE+BPF_X: + return "jge"; + case BPF_JMP+BPF_JSET+BPF_K: + case BPF_JMP+BPF_JSET+BPF_X: + return "jset"; + case BPF_RET+BPF_K: + case BPF_RET+BPF_X: + case BPF_RET+BPF_A: + return "ret"; + case BPF_MISC+BPF_TAX: + return "tax"; + case BPF_MISC+BPF_TXA: + return "txa"; + } + return "???"; +} + +static void bpf_decode_action(uint32_t k) { + uint32_t act = k & SECCOMP_RET_ACTION; + uint32_t data = k & SECCOMP_RET_DATA; + + switch (act) { + case SECCOMP_RET_KILL: + printf("KILL"); + break; + case SECCOMP_RET_TRAP: + printf("TRAP"); + break; + case SECCOMP_RET_ERRNO: + printf("ERRNO(%u)", data); + break; + case SECCOMP_RET_TRACE: + printf("TRACE(%u)", data); + break; + case SECCOMP_RET_LOG: + printf("LOG"); + break; + case SECCOMP_RET_ALLOW: + printf("ALLOW"); + break; + default: + printf("0x%.8x", k); + } +} + + +// implementing a simple state machine around accumulator +// in order to translate the syscall number +int syscall_loaded = 0; +int native_arch = 0; + +static void bpf_decode_args(const struct sock_filter *bpf, unsigned int line) { + switch (BPF_CLASS(bpf->code)) { + case BPF_LD: + case BPF_LDX: + switch (BPF_MODE(bpf->code)) { + case BPF_ABS: + syscall_loaded = 0; + if (bpf->k == offsetof(struct seccomp_data, arch)) + printf("data.architecture"); + else if (bpf->k == offsetof(struct seccomp_data, nr)) { + printf("data.syscall-number"); + syscall_loaded = 1; + } + else if (bpf->k == offsetof(struct seccomp_data, nr)) + printf("data.instruction_pointer"); + else { + int index = bpf->k - offsetof(struct seccomp_data, args); + printf("data.args[%x]", index); + } + break; + case BPF_MEM: + printf("$temp[%u]", bpf->k); + break; + case BPF_IMM: + printf("%x", bpf->k); + break; + case BPF_IND: + printf("$data[X + %x]", bpf->k); + break; + case BPF_LEN: + printf("len($data)"); + break; + case BPF_MSH: + printf("4 * $data[%x] & 0x0f", bpf->k); + break; + } + break; + case BPF_ST: + case BPF_STX: + printf("$temp[%u]", bpf->k); + break; + case BPF_ALU: + if (BPF_SRC(bpf->code) == BPF_K) { + switch (BPF_OP(bpf->code)) { + case BPF_OR: + case BPF_AND: + printf("%.8x", bpf->k); + break; + default: + printf("%x", bpf->k); + } + } + else + printf("%u", bpf->k); + break; + case BPF_JMP: + if (BPF_OP(bpf->code) == BPF_JA) { + printf("%.4u", (line + 1) + bpf->k); + } + else { + const char *name = NULL; + if (syscall_loaded && native_arch) + name = syscall_find_nr(bpf->k); + if (bpf->k == ARCH_32) { + printf("ARCH_32 %.4x (false %.4x)", + (line + 1) + bpf->jt, + (line + 1) + bpf->jf); + native_arch = (ARCH_NR == ARCH_32)? 1: 0; + } + else if (bpf->k == ARCH_64) { + printf("ARCH_64 %.4x (false %.4x)", + (line + 1) + bpf->jt, + (line + 1) + bpf->jf); + native_arch = (ARCH_NR == ARCH_64)? 1: 0; + } + else if (bpf->k == X32_SYSCALL_BIT) + printf("X32_ABI true:%.4x (false %.4x)", + (line + 1) + bpf->jt, + (line + 1) + bpf->jf); + else if (name) + printf("%s %.4x (false %.4x)", + name, + (line + 1) + bpf->jt, + (line + 1) + bpf->jf); + else + printf("%x %.4x (false %.4x)", + bpf->k, + (line + 1) + bpf->jt, + (line + 1) + bpf->jf); + } + break; + case BPF_RET: + if (BPF_RVAL(bpf->code) == BPF_A) { + /* XXX - accumulator? */ + printf("$acc"); + } + else if (BPF_SRC(bpf->code) == BPF_K) { + bpf_decode_action(bpf->k); + } + else if (BPF_SRC(bpf->code) == BPF_X) { + /* XXX - any idea? */ + printf("???"); + } + break; + case BPF_MISC: + break; + default: + printf("???"); + } +} + +void print(struct sock_filter *filter, int entries) { + unsigned int line = 0; + int i; + + /* header */ + printf(" line OP JT JF K\n"); + printf("=================================\n"); + struct sock_filter *bpf = filter; + for (i = 0; i < entries; i++, bpf++) { + + /* convert the bpf statement */ +// bpf.code = ttoh16(arch, bpf.code); +// bpf.k = ttoh32(arch, bpf.k); + + /* display a hex dump */ + printf(" %.4x: %.2x %.2x %.2x %.8x", + i, bpf->code, bpf->jt, bpf->jf, bpf->k); + + /* display the assembler statements */ + printf(" "); + printf("%-3s", bpf_decode_op(bpf)); + printf(" "); + bpf_decode_args(bpf, i); + + printf("\n"); + } +} + diff --git a/src/fsec-print/syscall_list.c b/src/fsec-print/syscall_list.c new file mode 100644 index 000000000..410956de5 --- /dev/null +++ b/src/fsec-print/syscall_list.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014-2017 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 "fsec_print.h" +#include + +typedef struct { + const char * const name; + int nr; +} SyscallEntry; + +static const SyscallEntry syslist[] = { +// +// code generated using tools/extract-syscall +// +#include "../include/syscall.h" +// +// end of generated code +// +}; // end of syslist + +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 NULL; +} diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index ae0ae64ef..030eaf90b 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c @@ -37,7 +37,6 @@ static void usage(void) { printf("\tfseccomp default drop file1 file2 list allow-debuggers\n"); printf("\tfseccomp keep file1 file2 list\n"); printf("\tfseccomp memory-deny-write-execute file\n"); - printf("\tfseccomp print file\n"); } int main(int argc, char **argv) { @@ -93,8 +92,6 @@ printf("\n"); seccomp_keep(argv[2], argv[3], argv[4]); 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], "print") == 0) - filter_print(argv[2]); else { fprintf(stderr, "Error fseccomp: invalid arguments\n"); return 1; diff --git a/src/fseccomp/seccomp_print.c b/src/fseccomp/seccomp_print.c deleted file mode 100644 index ffc65e7c3..000000000 --- a/src/fseccomp/seccomp_print.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2014-2017 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/seccomp.h" -#include - -static struct sock_filter *filter = NULL; -static int filter_cnt = 0; - -static void load_seccomp(const char *fname) { - assert(fname); - - // open filter file - int fd = open(fname, O_RDONLY); - if (fd == -1) - goto errexit; - - // calculate the number of entries - int size = lseek(fd, 0, SEEK_END); - if (size == -1) - goto errexit; - if (lseek(fd, 0 , SEEK_SET) == -1) - goto errexit; - unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); - filter_cnt = entries; - - // read filter - filter = malloc(size); - if (filter == NULL) - goto errexit; - memset(filter, 0, size); - int rd = 0; - while (rd < size) { - int rv = read(fd, (unsigned char *) filter + rd, size - rd); - if (rv == -1) - goto errexit; - rd += rv; - } - - // close file - close(fd); - return; - -errexit: - fprintf(stderr, "Error fseccomp: cannot read %s\n", fname); - exit(1); -} - -static int detect_filter_type(void) { - // the filter ishould already be load in filter variable - assert(filter); - - printf("SECCOMP Filter\n"); - - // testing for main seccomp filter, protocol, mdwe - platform architecture - const struct sock_filter start_main[] = { - VALIDATE_ARCHITECTURE, -#if defined(__x86_64__) - EXAMINE_SYSCALL, - HANDLE_X32 -#else - EXAMINE_SYSCALL -#endif - }; - - if (memcmp(&start_main[0], filter, sizeof(start_main)) == 0) { - printf(" VALIDATE_ARCHITECTURE\n"); - printf(" EXAMINE_SYSCALL\n"); -#if defined(__x86_64__) - printf(" HANDLE_X32\n"); -#endif - return sizeof(start_main) / sizeof(struct sock_filter); - } - - - // testing for secondary 64 bit filter - const struct sock_filter start_secondary_64[] = { - VALIDATE_ARCHITECTURE_64, - EXAMINE_SYSCALL, - }; - - if (memcmp(&start_secondary_64[0], filter, sizeof(start_secondary_64)) == 0) { - printf(" VALIDATE_ARCHITECTURE_64\n"); - printf(" EXAMINE_SYSCALL\n"); - return sizeof(start_secondary_64) / sizeof(struct sock_filter); - } - - // testing for secondary 32 bit filter - const struct sock_filter start_secondary_32[] = { - VALIDATE_ARCHITECTURE_32, - EXAMINE_SYSCALL, - }; - - if (memcmp(&start_secondary_32[0], filter, sizeof(start_secondary_32)) == 0) { - printf(" VALIDATE_ARCHITECTURE_32\n"); - 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 -} - -// debug filter -void filter_print(const char *fname) { - assert(fname); - load_seccomp(fname); - - int i = detect_filter_type(); - if (i == 0) { - printf("Invalid seccomp filter %s\n", fname); - return; - } - - // loop trough the rest of commands - while (i < filter_cnt) { - // minimal parsing! - struct sock_filter *s = (struct sock_filter *) &filter[i]; - if (s->code == BPF_JMP+BPF_JEQ+BPF_K && (s + 1)->code == BPF_RET+BPF_K && (s + 1)->k == SECCOMP_RET_ALLOW ) { - printf(" WHITELIST %d %s\n", s->k, syscall_find_nr(s->k)); - i += 2; - } - else if (s->code == BPF_JMP+BPF_JEQ+BPF_K && (s + 1)->code == BPF_RET+BPF_K && (s + 1)->k == SECCOMP_RET_KILL ) { - printf(" BLACKLIST %d %s\n", s->k, syscall_find_nr(s->k)); - i += 2; - } - else if (s->code == BPF_JMP+BPF_JEQ+BPF_K && (s + 1)->code == BPF_RET+BPF_K && ((s + 1)->k & ~SECCOMP_RET_DATA) == SECCOMP_RET_ERRNO) { - printf(" BLACKLIST_ERRNO %d %s %d %s\n", s->k, syscall_find_nr(s->k), (s + 1)->k & SECCOMP_RET_DATA, errno_find_nr((s + 1)->k & SECCOMP_RET_DATA)); - i += 2; - } - else if (s->code == BPF_RET+BPF_K && (s->k & ~SECCOMP_RET_DATA) == SECCOMP_RET_ERRNO) { - printf(" RETURN_ERRNO %d %s\n", s->k & SECCOMP_RET_DATA, errno_find_nr(s->k & SECCOMP_RET_DATA)); - i++; - } - else if (s->code == BPF_RET+BPF_K && s->k == SECCOMP_RET_KILL) { - printf(" KILL_PROCESS\n"); - i++; - } - else if (s->code == BPF_RET+BPF_K && s->k == SECCOMP_RET_ALLOW) { - printf(" RETURN_ALLOW\n"); - i++; - } - else { - printf(" UNKNOWN ENTRY %x!\n", s->code); - i++; - } - } -} diff --git a/src/include/seccomp.h b/src/include/seccomp.h index b8bfce96b..6d8983b39 100644 --- a/src/include/seccomp.h +++ b/src/include/seccomp.h @@ -67,6 +67,14 @@ #include #include +// From /usr/include/linux/filter.h +//struct sock_filter { /* Filter block */ +// __u16 code; /* Actual filter code */ +// __u8 jt; /* Jump true */ +// __u8 jf; /* Jump false */ +// __u32 k; /* Generic multiuse field */ +//}; + #include #ifndef PR_SET_NO_NEW_PRIVS # define PR_SET_NO_NEW_PRIVS 38 @@ -81,6 +89,7 @@ #define SECCOMP_RET_ALLOW 0x7fff0000U #define SECCOMP_RET_ERRNO 0x00050000U #define SECCOMP_RET_DATA 0x0000ffffU + struct seccomp_data { int nr; __u32 arch; @@ -89,6 +98,11 @@ struct seccomp_data { }; #endif +#ifndef SECCOMP_RET_LOG +#define SECCOMP_RET_LOG 0x7ffc0000U +#endif + + #if defined(__i386__) # define ARCH_NR AUDIT_ARCH_I386 # define ARCH_32 AUDIT_ARCH_I386 -- cgit v1.2.3-70-g09d2