diff options
author | netblue30 <netblue30@yahoo.com> | 2016-11-02 07:49:01 -0400 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2016-11-02 07:49:01 -0400 |
commit | 72b93c5761b5e42c5742e192f46bac1696c36f4c (patch) | |
tree | 3951e01a771ea3e8f11b8364991bb47f752f011f | |
parent | fixed /run/firejail/mnt problem introduced recently (diff) | |
download | firejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.tar.gz firejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.tar.zst firejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.zip |
major cleanup
-rw-r--r-- | src/firejail/errno.c | 2 | ||||
-rw-r--r-- | src/firejail/firejail.h | 24 | ||||
-rw-r--r-- | src/firejail/join.c | 6 | ||||
-rw-r--r-- | src/firejail/preproc.c | 31 | ||||
-rw-r--r-- | src/firejail/protocol.c | 46 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 33 | ||||
-rw-r--r-- | src/firejail/seccomp.c | 873 | ||||
-rw-r--r-- | src/firejail/syscall.c | 105 | ||||
-rw-r--r-- | src/firejail/util.c | 4 | ||||
-rw-r--r-- | src/fnet/Makefile.in | 4 | ||||
-rw-r--r-- | src/fseccomp/Makefile.in | 4 | ||||
-rw-r--r-- | src/fseccomp/errno.c | 43 | ||||
-rw-r--r-- | src/fseccomp/fseccomp.h | 50 | ||||
-rw-r--r-- | src/fseccomp/main.c | 49 | ||||
-rw-r--r-- | src/fseccomp/seccomp.c | 292 | ||||
-rw-r--r-- | src/fseccomp/seccomp_file.c | 108 | ||||
-rw-r--r-- | src/fseccomp/seccomp_print.c | 116 | ||||
-rw-r--r-- | src/fseccomp/seccomp_secondary.c | 183 | ||||
-rw-r--r-- | src/fseccomp/syscall.c | 84 | ||||
-rwxr-xr-x | test/filters/filters.sh | 15 | ||||
-rwxr-xr-x | test/filters/fseccomp.exp | 138 |
21 files changed, 1281 insertions, 929 deletions
diff --git a/src/firejail/errno.c b/src/firejail/errno.c index 03f10bb14..8215c99a1 100644 --- a/src/firejail/errno.c +++ b/src/firejail/errno.c | |||
@@ -17,7 +17,6 @@ | |||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | |||
21 | #ifdef HAVE_SECCOMP | 20 | #ifdef HAVE_SECCOMP |
22 | #include "firejail.h" | 21 | #include "firejail.h" |
23 | #include <errno.h> | 22 | #include <errno.h> |
@@ -205,5 +204,4 @@ char *errno_find_nr(int nr) { | |||
205 | 204 | ||
206 | return "unknown"; | 205 | return "unknown"; |
207 | } | 206 | } |
208 | |||
209 | #endif // HAVE_SECCOMP | 207 | #endif // HAVE_SECCOMP |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index dcec160fb..cf540ff91 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -25,7 +25,6 @@ | |||
25 | // debug restricted shell | 25 | // debug restricted shell |
26 | //#define DEBUG_RESTRICTED_SHELL | 26 | //#define DEBUG_RESTRICTED_SHELL |
27 | 27 | ||
28 | |||
29 | // filesystem | 28 | // filesystem |
30 | #define RUN_FIREJAIL_BASEDIR "/run" | 29 | #define RUN_FIREJAIL_BASEDIR "/run" |
31 | #define RUN_FIREJAIL_DIR "/run/firejail" | 30 | #define RUN_FIREJAIL_DIR "/run/firejail" |
@@ -38,8 +37,6 @@ | |||
38 | #define RUN_RO_DIR "/run/firejail/firejail.ro.dir" | 37 | #define RUN_RO_DIR "/run/firejail/firejail.ro.dir" |
39 | #define RUN_RO_FILE "/run/firejail/firejail.ro.file" | 38 | #define RUN_RO_FILE "/run/firejail/firejail.ro.file" |
40 | #define RUN_MNT_DIR "/run/firejail/mnt" // a tmpfs is mounted on this directory before any of the files below are created | 39 | #define RUN_MNT_DIR "/run/firejail/mnt" // a tmpfs is mounted on this directory before any of the files below are created |
41 | #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" | ||
42 | #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" | ||
43 | #define RUN_CGROUP_CFG "/run/firejail/mnt/cgroup" | 40 | #define RUN_CGROUP_CFG "/run/firejail/mnt/cgroup" |
44 | #define RUN_CPU_CFG "/run/firejail/mnt/cpu" | 41 | #define RUN_CPU_CFG "/run/firejail/mnt/cpu" |
45 | #define RUN_GROUPS_CFG "/run/firejail/mnt/groups" | 42 | #define RUN_GROUPS_CFG "/run/firejail/mnt/groups" |
@@ -50,6 +47,12 @@ | |||
50 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" | 47 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" |
51 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" | 48 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" |
52 | 49 | ||
50 | #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter | ||
51 | #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter | ||
52 | #define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures | ||
53 | #define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures | ||
54 | |||
55 | |||
53 | #define RUN_DEV_DIR "/run/firejail/mnt/dev" | 56 | #define RUN_DEV_DIR "/run/firejail/mnt/dev" |
54 | #define RUN_DEVLOG_FILE "/run/firejail/mnt/devlog" | 57 | #define RUN_DEVLOG_FILE "/run/firejail/mnt/devlog" |
55 | 58 | ||
@@ -76,6 +79,8 @@ | |||
76 | #define RUN_GROUP_FILE "/run/firejail/mnt/group" | 79 | #define RUN_GROUP_FILE "/run/firejail/mnt/group" |
77 | #define RUN_FSLOGGER_FILE "/run/firejail/mnt/fslogger" | 80 | #define RUN_FSLOGGER_FILE "/run/firejail/mnt/fslogger" |
78 | 81 | ||
82 | |||
83 | |||
79 | // profiles | 84 | // profiles |
80 | #define DEFAULT_USER_PROFILE "default" | 85 | #define DEFAULT_USER_PROFILE "default" |
81 | #define DEFAULT_ROOT_PROFILE "server" | 86 | #define DEFAULT_ROOT_PROFILE "server" |
@@ -491,12 +496,14 @@ void fs_private_home_list(void); | |||
491 | 496 | ||
492 | 497 | ||
493 | // seccomp.c | 498 | // seccomp.c |
499 | int seccomp_load(const char *fname); | ||
500 | void seccomp_filter_32(void); | ||
501 | void seccomp_filter_64(void); | ||
494 | int seccomp_filter_drop(int enforce_seccomp); | 502 | int seccomp_filter_drop(int enforce_seccomp); |
495 | int seccomp_filter_keep(void); | 503 | int seccomp_filter_keep(void); |
496 | void seccomp_set(void); | 504 | int seccomp_filter_errno(void); |
497 | void seccomp_print_filter_name(const char *name); | 505 | void seccomp_print_filter_name(const char *name); |
498 | void seccomp_print_filter(pid_t pid); | 506 | void seccomp_print_filter(pid_t pid); |
499 | int seccomp_filter_errno(void); | ||
500 | 507 | ||
501 | // caps.c | 508 | // caps.c |
502 | int caps_default_filter(void); | 509 | int caps_default_filter(void); |
@@ -591,13 +598,10 @@ void fs_check_bin_list(void); | |||
591 | void fs_private_bin_list(void); | 598 | void fs_private_bin_list(void); |
592 | 599 | ||
593 | // protocol.c | 600 | // protocol.c |
594 | void protocol_list(); | ||
595 | void protocol_print_filter_name(const char *name); | ||
596 | void protocol_print_filter(pid_t pid); | ||
597 | void protocol_store(const char *prlist); | ||
598 | void protocol_filter(const char *fname); | ||
599 | void protocol_filter_save(void); | 601 | void protocol_filter_save(void); |
600 | void protocol_filter_load(const char *fname); | 602 | void protocol_filter_load(const char *fname); |
603 | void protocol_print_filter_name(const char *name); | ||
604 | void protocol_print_filter(pid_t pid); | ||
601 | 605 | ||
602 | // restrict_users.c | 606 | // restrict_users.c |
603 | void restrict_users(void); | 607 | void restrict_users(void); |
diff --git a/src/firejail/join.c b/src/firejail/join.c index 9b5fba24d..6f1e9455c 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -292,16 +292,16 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
292 | if (apply_caps == 1) // not available for uid 0 | 292 | if (apply_caps == 1) // not available for uid 0 |
293 | caps_set(caps); | 293 | caps_set(caps); |
294 | #ifdef HAVE_SECCOMP | 294 | #ifdef HAVE_SECCOMP |
295 | // set protocol filter | 295 | // read cfg.protocol from file |
296 | if (getuid() != 0) | 296 | if (getuid() != 0) |
297 | protocol_filter_load(RUN_PROTOCOL_CFG); | 297 | protocol_filter_load(RUN_PROTOCOL_CFG); |
298 | if (cfg.protocol) { // not available for uid 0 | 298 | if (cfg.protocol) { // not available for uid 0 |
299 | protocol_filter(RUN_SECCOMP_PROTOCOL); | 299 | seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter |
300 | } | 300 | } |
301 | 301 | ||
302 | // set seccomp filter | 302 | // set seccomp filter |
303 | if (apply_seccomp == 1) // not available for uid 0 | 303 | if (apply_seccomp == 1) // not available for uid 0 |
304 | seccomp_set(); | 304 | seccomp_load(RUN_SECCOMP_CFG); |
305 | #endif | 305 | #endif |
306 | 306 | ||
307 | // fix qt 4.8 | 307 | // fix qt 4.8 |
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c index 27e06b556..2873571a9 100644 --- a/src/firejail/preproc.c +++ b/src/firejail/preproc.c | |||
@@ -66,8 +66,6 @@ void preproc_build_firejail_dir(void) { | |||
66 | 66 | ||
67 | // build /run/firejail/mnt directory | 67 | // build /run/firejail/mnt directory |
68 | void preproc_mount_mnt_dir(void) { | 68 | void preproc_mount_mnt_dir(void) { |
69 | struct stat s; | ||
70 | |||
71 | // mount tmpfs on top of /run/firejail/mnt | 69 | // mount tmpfs on top of /run/firejail/mnt |
72 | if (!tmpfs_mounted) { | 70 | if (!tmpfs_mounted) { |
73 | if (arg_debug) | 71 | if (arg_debug) |
@@ -76,6 +74,35 @@ void preproc_mount_mnt_dir(void) { | |||
76 | errExit("mounting /run/firejail/mnt"); | 74 | errExit("mounting /run/firejail/mnt"); |
77 | tmpfs_mounted = 1; | 75 | tmpfs_mounted = 1; |
78 | fs_logger2("tmpfs", RUN_MNT_DIR); | 76 | fs_logger2("tmpfs", RUN_MNT_DIR); |
77 | |||
78 | // create all seccomp files | ||
79 | // as root, create RUN_SECCOMP_I386 file | ||
80 | create_empty_file_as_root(RUN_SECCOMP_I386, 0644); | ||
81 | if (chown(RUN_SECCOMP_I386, getuid(), getgid()) == -1) | ||
82 | errExit("chown"); | ||
83 | if (chmod(RUN_SECCOMP_I386, 0644) == -1) | ||
84 | errExit("chmod"); | ||
85 | |||
86 | // as root, create RUN_SECCOMP_AMD64 file | ||
87 | create_empty_file_as_root(RUN_SECCOMP_AMD64, 0644); | ||
88 | if (chown(RUN_SECCOMP_AMD64, getuid(), getgid()) == -1) | ||
89 | errExit("chown"); | ||
90 | if (chmod(RUN_SECCOMP_AMD64, 0644) == -1) | ||
91 | errExit("chmod"); | ||
92 | |||
93 | // as root, create RUN_SECCOMP file | ||
94 | create_empty_file_as_root(RUN_SECCOMP_CFG, 0644); | ||
95 | if (chown(RUN_SECCOMP_CFG, getuid(), getgid()) == -1) | ||
96 | errExit("chown"); | ||
97 | if (chmod(RUN_SECCOMP_CFG, 0644) == -1) | ||
98 | errExit("chmod"); | ||
99 | |||
100 | // as root, create RUN_SECCOMP_PROTOCOL file | ||
101 | create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644); | ||
102 | if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1) | ||
103 | errExit("chown"); | ||
104 | if (chmod(RUN_SECCOMP_PROTOCOL, 0644) == -1) | ||
105 | errExit("chmod"); | ||
79 | } | 106 | } |
80 | } | 107 | } |
81 | 108 | ||
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c index db6c6cad9..e8e88aee9 100644 --- a/src/firejail/protocol.c +++ b/src/firejail/protocol.c | |||
@@ -22,52 +22,6 @@ | |||
22 | #include "firejail.h" | 22 | #include "firejail.h" |
23 | #include "../include/seccomp.h" | 23 | #include "../include/seccomp.h" |
24 | 24 | ||
25 | // install protocol filter | ||
26 | void protocol_filter(const char *fname) { | ||
27 | #ifndef SYS_socket | ||
28 | if (arg_debug) | ||
29 | printf("No support for --protocol on this platform\n"); | ||
30 | return; | ||
31 | #else | ||
32 | assert(fname); | ||
33 | |||
34 | // check file | ||
35 | struct stat s; | ||
36 | if (stat(fname, &s) == -1) { | ||
37 | fprintf(stderr, "Error: cannot read protocol filter file\n"); | ||
38 | exit(1); | ||
39 | } | ||
40 | int size = s.st_size; | ||
41 | |||
42 | // read filter | ||
43 | struct sock_filter filter[32]; // big enough | ||
44 | memset(&filter[0], 0, sizeof(filter)); | ||
45 | int src = open(fname, O_RDONLY); | ||
46 | int rd = 0; | ||
47 | while (rd < size) { | ||
48 | int rv = read(src, (unsigned char *) filter + rd, size - rd); | ||
49 | if (rv == -1) { | ||
50 | fprintf(stderr, "Error: cannot read %s file\n", fname); | ||
51 | exit(1); | ||
52 | } | ||
53 | rd += rv; | ||
54 | } | ||
55 | close(src); | ||
56 | |||
57 | // install filter | ||
58 | unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); | ||
59 | struct sock_fprog prog = { | ||
60 | .len = entries, | ||
61 | .filter = filter, | ||
62 | }; | ||
63 | |||
64 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
65 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
66 | return; | ||
67 | } | ||
68 | #endif | ||
69 | } | ||
70 | |||
71 | void protocol_filter_save(void) { | 25 | void protocol_filter_save(void) { |
72 | // save protocol filter configuration in PROTOCOL_CFG | 26 | // save protocol filter configuration in PROTOCOL_CFG |
73 | FILE *fp = fopen(RUN_PROTOCOL_CFG, "w"); | 27 | FILE *fp = fopen(RUN_PROTOCOL_CFG, "w"); |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index a15003d03..3942e4da6 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -559,13 +559,6 @@ assert(0); | |||
559 | if (cfg.protocol) { | 559 | if (cfg.protocol) { |
560 | if (arg_debug) | 560 | if (arg_debug) |
561 | printf("Build protocol filter: %s\n", cfg.protocol); | 561 | printf("Build protocol filter: %s\n", cfg.protocol); |
562 | // as root, create RUN_SECCOMP_PROTOCOL file | ||
563 | // this is where fseccomp program will store the protocol filter | ||
564 | create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644); | ||
565 | if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1) | ||
566 | errExit("chown"); | ||
567 | if (chmod(RUN_SECCOMP_PROTOCOL, 0644) == -1) | ||
568 | errExit("chmod"); | ||
569 | 562 | ||
570 | // build the seccomp filter as a regular user | 563 | // build the seccomp filter as a regular user |
571 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, | 564 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, |
@@ -826,13 +819,23 @@ assert(0); | |||
826 | // set rlimits | 819 | // set rlimits |
827 | set_rlimits(); | 820 | set_rlimits(); |
828 | 821 | ||
829 | // set seccomp | 822 | // set cpu affinity |
823 | if (cfg.cpus) { | ||
824 | save_cpu(); // save cpu affinity mask to CPU_CFG file | ||
825 | set_cpu_affinity(); | ||
826 | } | ||
827 | |||
828 | // save cgroup in CGROUP_CFG file | ||
829 | if (cfg.cgroup) | ||
830 | save_cgroup(); | ||
831 | |||
832 | // set seccomp //todo: push it down after drop_privs and/or configuring noroot | ||
830 | #ifdef HAVE_SECCOMP | 833 | #ifdef HAVE_SECCOMP |
831 | // install protocol filter | 834 | // install protocol filter |
832 | if (cfg.protocol) { | 835 | if (cfg.protocol) { |
833 | if (arg_debug) | 836 | if (arg_debug) |
834 | printf("Install protocol filter: %s\n", cfg.protocol); | 837 | printf("Install protocol filter: %s\n", cfg.protocol); |
835 | protocol_filter(RUN_SECCOMP_PROTOCOL); // install filter | 838 | seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter |
836 | protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG | 839 | protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG |
837 | } | 840 | } |
838 | 841 | ||
@@ -847,16 +850,6 @@ assert(0); | |||
847 | } | 850 | } |
848 | #endif | 851 | #endif |
849 | 852 | ||
850 | // set cpu affinity | ||
851 | if (cfg.cpus) { | ||
852 | save_cpu(); // save cpu affinity mask to CPU_CFG file | ||
853 | set_cpu_affinity(); | ||
854 | } | ||
855 | |||
856 | // save cgroup in CGROUP_CFG file | ||
857 | if (cfg.cgroup) | ||
858 | save_cgroup(); | ||
859 | |||
860 | //**************************************** | 853 | //**************************************** |
861 | // drop privileges or create a new user namespace | 854 | // drop privileges or create a new user namespace |
862 | //**************************************** | 855 | //**************************************** |
@@ -929,8 +922,6 @@ assert(0); | |||
929 | int status = monitor_application(app_pid); // monitor application | 922 | int status = monitor_application(app_pid); // monitor application |
930 | flush_stdin(); | 923 | flush_stdin(); |
931 | 924 | ||
932 | |||
933 | |||
934 | if (WIFEXITED(status)) { | 925 | if (WIFEXITED(status)) { |
935 | // if we had a proper exit, return that exit status | 926 | // if we had a proper exit, return that exit status |
936 | return WEXITSTATUS(status); | 927 | return WEXITSTATUS(status); |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 69be04a03..74d29fc9d 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -22,760 +22,203 @@ | |||
22 | #include "firejail.h" | 22 | #include "firejail.h" |
23 | #include "../include/seccomp.h" | 23 | #include "../include/seccomp.h" |
24 | 24 | ||
25 | #define SECSIZE 128 // initial filter size | 25 | int seccomp_load(const char *fname) { |
26 | static struct sock_filter *sfilter = NULL; | 26 | assert(fname); |
27 | static int sfilter_alloc_size = 0; | ||
28 | static int sfilter_index = 0; | ||
29 | |||
30 | // debug filter | ||
31 | void filter_debug(void) { | ||
32 | // start filter | ||
33 | struct sock_filter filter[] = { | ||
34 | VALIDATE_ARCHITECTURE, | ||
35 | EXAMINE_SYSCALL | ||
36 | }; | ||
37 | 27 | ||
38 | // print sizes | 28 | // check file |
39 | printf("SECCOMP Filter:\n"); | 29 | struct stat s; |
40 | if (sfilter == NULL) { | 30 | if (stat(fname, &s) == -1) { |
41 | printf("SECCOMP filter not allocated\n"); | 31 | fprintf(stderr, "Error: cannot read protocol filter file\n"); |
42 | return; | 32 | exit(1); |
43 | } | ||
44 | if (sfilter_index < 4) | ||
45 | return; | ||
46 | |||
47 | // test the start of the filter | ||
48 | if (memcmp(sfilter, filter, sizeof(filter)) == 0) { | ||
49 | printf(" VALIDATE_ARCHITECTURE\n"); | ||
50 | printf(" EXAMINE_SYSCAL\n"); | ||
51 | } | 33 | } |
52 | 34 | int size = s.st_size; | |
53 | // loop trough blacklists | 35 | unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); |
54 | int i = 4; | 36 | //printf("size %d, entries %d\n", s.st_size, entries); |
55 | while (i < sfilter_index) { | 37 | |
56 | // minimal parsing! | 38 | // read filter |
57 | unsigned char *ptr = (unsigned char *) &sfilter[i]; | 39 | struct sock_filter filter[entries]; |
58 | int *nr = (int *) (ptr + 4); | 40 | memset(&filter[0], 0, sizeof(filter)); |
59 | if (*ptr == 0x15 && *(ptr +14) == 0xff && *(ptr + 15) == 0x7f ) { | 41 | int src = open(fname, O_RDONLY); |
60 | printf(" WHITELIST %d %s\n", *nr, syscall_find_nr(*nr)); | 42 | int rd = 0; |
61 | i += 2; | 43 | while (rd < size) { |
62 | } | 44 | int rv = read(src, (unsigned char *) filter + rd, size - rd); |
63 | else if (*ptr == 0x15 && *(ptr +14) == 0 && *(ptr + 15) == 0) { | 45 | if (rv == -1) { |
64 | printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); | 46 | fprintf(stderr, "Error: cannot read %s file\n", fname); |
65 | i += 2; | 47 | exit(1); |
66 | } | ||
67 | else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) { | ||
68 | int err = *(ptr + 13) << 8 | *(ptr + 12); | ||
69 | printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err)); | ||
70 | i += 2; | ||
71 | } | ||
72 | else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { | ||
73 | printf(" KILL_PROCESS\n"); | ||
74 | i++; | ||
75 | } | ||
76 | else if (*ptr == 0x06 && *(ptr +6) == 0xff && *(ptr + 7) == 0x7f ) { | ||
77 | printf(" RETURN_ALLOW\n"); | ||
78 | i++; | ||
79 | } | ||
80 | else { | ||
81 | printf(" UNKNOWN ENTRY!!!\n"); | ||
82 | i++; | ||
83 | } | 48 | } |
49 | rd += rv; | ||
84 | } | 50 | } |
85 | } | 51 | close(src); |
86 | |||
87 | // initialize filter | ||
88 | static void filter_init(void) { | ||
89 | if (sfilter) { | ||
90 | assert(0); | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | // if (arg_debug) | ||
95 | // printf("Initialize seccomp filter\n"); | ||
96 | // allocate a filter of SECSIZE | ||
97 | sfilter = malloc(sizeof(struct sock_filter) * SECSIZE); | ||
98 | if (!sfilter) | ||
99 | errExit("malloc"); | ||
100 | memset(sfilter, 0, sizeof(struct sock_filter) * SECSIZE); | ||
101 | sfilter_alloc_size = SECSIZE; | ||
102 | |||
103 | // copy the start entries | ||
104 | #if defined(__x86_64__) | ||
105 | #define X32_SYSCALL_BIT 0x40000000 | ||
106 | struct sock_filter filter[] = { | ||
107 | VALIDATE_ARCHITECTURE, | ||
108 | EXAMINE_SYSCALL, | ||
109 | // handle X32 ABI | ||
110 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), | ||
111 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), | ||
112 | RETURN_ERRNO(EPERM) | ||
113 | }; | ||
114 | #else | ||
115 | struct sock_filter filter[] = { | ||
116 | VALIDATE_ARCHITECTURE, | ||
117 | EXAMINE_SYSCALL | ||
118 | }; | ||
119 | #endif | ||
120 | sfilter_index = sizeof(filter) / sizeof(struct sock_filter); | ||
121 | memcpy(sfilter, filter, sizeof(filter)); | ||
122 | } | ||
123 | |||
124 | static void filter_realloc(void) { | ||
125 | assert(sfilter); | ||
126 | assert(sfilter_alloc_size); | ||
127 | assert(sfilter_index); | ||
128 | if (arg_debug) | ||
129 | printf("Allocating more seccomp filter entries\n"); | ||
130 | |||
131 | // allocate the new memory | ||
132 | struct sock_filter *old = sfilter; | ||
133 | sfilter = malloc(sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); | ||
134 | if (!sfilter) | ||
135 | errExit("malloc"); | ||
136 | memset(sfilter, 0, sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); | ||
137 | |||
138 | // copy old filter | ||
139 | memcpy(sfilter, old, sizeof(struct sock_filter) * sfilter_alloc_size); | ||
140 | sfilter_alloc_size += SECSIZE; | ||
141 | } | ||
142 | |||
143 | static void filter_add_whitelist(int syscall, int arg) { | ||
144 | (void) arg; | ||
145 | assert(sfilter); | ||
146 | assert(sfilter_alloc_size); | ||
147 | assert(sfilter_index); | ||
148 | // if (arg_debug) | ||
149 | // printf("Whitelisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); | ||
150 | |||
151 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
152 | filter_realloc(); | ||
153 | |||
154 | struct sock_filter filter[] = { | ||
155 | WHITELIST(syscall) | ||
156 | }; | ||
157 | #if 0 | ||
158 | { | ||
159 | int i; | ||
160 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
161 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
162 | printf("%x, ", (*ptr) & 0xff); | ||
163 | printf("\n"); | ||
164 | } | ||
165 | #endif | ||
166 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
167 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
168 | } | ||
169 | 52 | ||
170 | static void filter_add_blacklist(int syscall, int arg) { | 53 | // install filter |
171 | (void) arg; | 54 | struct sock_fprog prog = { |
172 | assert(sfilter); | 55 | .len = entries, |
173 | assert(sfilter_alloc_size); | 56 | .filter = filter, |
174 | assert(sfilter_index); | ||
175 | // if (arg_debug) | ||
176 | // printf("Blacklisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); | ||
177 | |||
178 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
179 | filter_realloc(); | ||
180 | |||
181 | struct sock_filter filter[] = { | ||
182 | BLACKLIST(syscall) | ||
183 | }; | ||
184 | #if 0 | ||
185 | { | ||
186 | int i; | ||
187 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
188 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
189 | printf("%x, ", (*ptr) & 0xff); | ||
190 | printf("\n"); | ||
191 | } | ||
192 | #endif | ||
193 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
194 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
195 | } | ||
196 | |||
197 | static void filter_add_errno(int syscall, int arg) { | ||
198 | assert(sfilter); | ||
199 | assert(sfilter_alloc_size); | ||
200 | assert(sfilter_index); | ||
201 | // if (arg_debug) | ||
202 | // printf("Errno syscall %d %d %s\n", syscall, arg, syscall_find_nr(syscall)); | ||
203 | |||
204 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
205 | filter_realloc(); | ||
206 | |||
207 | struct sock_filter filter[] = { | ||
208 | BLACKLIST_ERRNO(syscall, arg) | ||
209 | }; | ||
210 | #if 0 | ||
211 | { | ||
212 | int i; | ||
213 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
214 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
215 | printf("%x, ", (*ptr) & 0xff); | ||
216 | printf("\n"); | ||
217 | } | ||
218 | #endif | ||
219 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
220 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
221 | } | ||
222 | |||
223 | static void filter_end_blacklist(void) { | ||
224 | assert(sfilter); | ||
225 | assert(sfilter_alloc_size); | ||
226 | assert(sfilter_index); | ||
227 | // if (arg_debug) | ||
228 | // printf("Ending syscall filter\n"); | ||
229 | |||
230 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
231 | filter_realloc(); | ||
232 | |||
233 | struct sock_filter filter[] = { | ||
234 | RETURN_ALLOW | ||
235 | }; | ||
236 | #if 0 | ||
237 | { | ||
238 | int i; | ||
239 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
240 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
241 | printf("%x, ", (*ptr) & 0xff); | ||
242 | printf("\n"); | ||
243 | } | ||
244 | #endif | ||
245 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
246 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
247 | } | ||
248 | |||
249 | static void filter_end_whitelist(void) { | ||
250 | assert(sfilter); | ||
251 | assert(sfilter_alloc_size); | ||
252 | assert(sfilter_index); | ||
253 | if (arg_debug) | ||
254 | printf("Ending syscall filter\n"); | ||
255 | |||
256 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
257 | filter_realloc(); | ||
258 | |||
259 | struct sock_filter filter[] = { | ||
260 | KILL_PROCESS | ||
261 | }; | 57 | }; |
262 | #if 0 | ||
263 | { | ||
264 | int i; | ||
265 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
266 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
267 | printf("%x, ", (*ptr) & 0xff); | ||
268 | printf("\n"); | ||
269 | } | ||
270 | #endif | ||
271 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
272 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
273 | } | ||
274 | |||
275 | |||
276 | // save seccomp filter in /run/firejail/mnt/seccomp | ||
277 | static void write_seccomp_file(void) { | ||
278 | assert(sfilter); | ||
279 | |||
280 | int fd = open(RUN_SECCOMP_CFG, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); | ||
281 | if (fd == -1) | ||
282 | errExit("open"); | ||
283 | 58 | ||
284 | if (arg_debug) | 59 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
285 | printf("Save seccomp filter, size %u bytes\n", (unsigned) (sfilter_index * sizeof(struct sock_filter))); | 60 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); |
286 | errno = 0; | 61 | return 1; |
287 | ssize_t sz = write(fd, sfilter, sfilter_index * sizeof(struct sock_filter)); | ||
288 | if (sz != (ssize_t)(sfilter_index * sizeof(struct sock_filter))) { | ||
289 | fprintf(stderr, "Error: cannot save seccomp filter\n"); | ||
290 | exit(1); | ||
291 | } | 62 | } |
292 | SET_PERMS_FD(fd, 0, 0, S_IRUSR | S_IWUSR); | 63 | |
293 | close(fd); | 64 | return 0; |
294 | } | 65 | } |
295 | 66 | ||
296 | // read seccomp filter from /run/firejail/mnt/seccomp | ||
297 | static void read_seccomp_file(const char *fname) { | ||
298 | assert(sfilter == NULL && sfilter_index == 0); | ||
299 | 67 | ||
300 | // check file | ||
301 | struct stat s; | ||
302 | if (stat(fname, &s) == -1) { | ||
303 | fprintf(stderr, "Warning: seccomp file not found\n"); | ||
304 | return; | ||
305 | } | ||
306 | ssize_t sz = s.st_size; | ||
307 | if (sz == 0 || (sz % sizeof(struct sock_filter)) != 0) { | ||
308 | fprintf(stderr, "Error: invalid seccomp file\n"); | ||
309 | exit(1); | ||
310 | } | ||
311 | sfilter = malloc(sz); | ||
312 | if (!sfilter) | ||
313 | errExit("malloc"); | ||
314 | |||
315 | // read file | ||
316 | /* coverity[toctou] */ | ||
317 | int fd = open(fname,O_RDONLY); | ||
318 | if (fd == -1) | ||
319 | errExit("open"); | ||
320 | errno = 0; | ||
321 | ssize_t size = read(fd, sfilter, sz); | ||
322 | if (size != sz) { | ||
323 | fprintf(stderr, "Error: invalid seccomp file\n"); | ||
324 | exit(1); | ||
325 | } | ||
326 | sfilter_index = sz / sizeof(struct sock_filter); | ||
327 | 68 | ||
328 | if (arg_debug) | ||
329 | printf("Read seccomp filter, size %u bytes\n", (unsigned) (sfilter_index * sizeof(struct sock_filter))); | ||
330 | |||
331 | close(fd); | ||
332 | |||
333 | if (arg_debug) | ||
334 | filter_debug(); | ||
335 | } | ||
336 | 69 | ||
337 | // i386 filter installed on amd64 architectures | 70 | // i386 filter installed on amd64 architectures |
338 | void seccomp_filter_32(void) { | 71 | void seccomp_filter_32(void) { |
339 | // hardcoded syscall values | 72 | if (arg_debug) |
340 | struct sock_filter filter[] = { | 73 | printf("Build secondary 32-bit filter\n"); |
341 | VALIDATE_ARCHITECTURE_32, | ||
342 | EXAMINE_SYSCALL, | ||
343 | BLACKLIST(21), // mount | ||
344 | BLACKLIST(52), // umount2 | ||
345 | // todo: implement --allow-debuggers | ||
346 | BLACKLIST(26), // ptrace | ||
347 | BLACKLIST(283), // kexec_load | ||
348 | BLACKLIST(341), // name_to_handle_at | ||
349 | BLACKLIST(342), // open_by_handle_at | ||
350 | BLACKLIST(127), // create_module | ||
351 | BLACKLIST(128), // init_module | ||
352 | BLACKLIST(350), // finit_module | ||
353 | BLACKLIST(129), // delete_module | ||
354 | BLACKLIST(110), // iopl | ||
355 | BLACKLIST(101), // ioperm | ||
356 | BLACKLIST(289), // ioprio_set | ||
357 | BLACKLIST(87), // swapon | ||
358 | BLACKLIST(115), // swapoff | ||
359 | BLACKLIST(103), // syslog | ||
360 | BLACKLIST(347), // process_vm_readv | ||
361 | BLACKLIST(348), // process_vm_writev | ||
362 | BLACKLIST(135), // sysfs | ||
363 | BLACKLIST(149), // _sysctl | ||
364 | BLACKLIST(124), // adjtimex | ||
365 | BLACKLIST(343), // clock_adjtime | ||
366 | BLACKLIST(253), // lookup_dcookie | ||
367 | BLACKLIST(336), // perf_event_open | ||
368 | BLACKLIST(338), // fanotify_init | ||
369 | BLACKLIST(349), // kcmp | ||
370 | BLACKLIST(286), // add_key | ||
371 | BLACKLIST(287), // request_key | ||
372 | BLACKLIST(288), // keyctl | ||
373 | BLACKLIST(86), // uselib | ||
374 | BLACKLIST(51), // acct | ||
375 | BLACKLIST(123), // modify_ldt | ||
376 | BLACKLIST(217), // pivot_root | ||
377 | BLACKLIST(245), // io_setup | ||
378 | BLACKLIST(246), // io_destroy | ||
379 | BLACKLIST(247), // io_getevents | ||
380 | BLACKLIST(248), // io_submit | ||
381 | BLACKLIST(249), // io_cancel | ||
382 | BLACKLIST(257), // remap_file_pages | ||
383 | BLACKLIST(274), // mbind | ||
384 | BLACKLIST(275), // get_mempolicy | ||
385 | BLACKLIST(276), // set_mempolicy | ||
386 | BLACKLIST(294), // migrate_pages | ||
387 | BLACKLIST(317), // move_pages | ||
388 | BLACKLIST(316), // vmsplice | ||
389 | BLACKLIST(61), // chroot | ||
390 | BLACKLIST(88), // reboot | ||
391 | BLACKLIST(169), // nfsservctl | ||
392 | BLACKLIST(130), // get_kernel_syms | ||
393 | |||
394 | RETURN_ALLOW | ||
395 | }; | ||
396 | 74 | ||
397 | struct sock_fprog prog = { | 75 | // build the seccomp filter as a regular user |
398 | .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), | 76 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, |
399 | .filter = filter, | 77 | PATH_FSECCOMP, "secondary", "32", RUN_SECCOMP_I386); |
400 | }; | 78 | if (rv) |
79 | exit(rv); | ||
401 | 80 | ||
402 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | 81 | if (seccomp_load(RUN_SECCOMP_I386) == 0) { |
403 | ; | 82 | if (arg_debug) |
404 | } | 83 | printf("Dual i386/amd64 seccomp filter configured\n"); |
405 | else if (arg_debug) { | ||
406 | printf("Dual i386/amd64 seccomp filter configured\n"); | ||
407 | } | 84 | } |
408 | } | 85 | } |
409 | 86 | ||
410 | // amd64 filter installed on i386 architectures | 87 | // amd64 filter installed on i386 architectures |
411 | void seccomp_filter_64(void) { | 88 | void seccomp_filter_64(void) { |
412 | // hardcoded syscall values | 89 | if (arg_debug) |
413 | struct sock_filter filter[] = { | 90 | printf("Build secondary 64-bit filter\n"); |
414 | VALIDATE_ARCHITECTURE_64, | ||
415 | EXAMINE_SYSCALL, | ||
416 | BLACKLIST(165), // mount | ||
417 | BLACKLIST(166), // umount2 | ||
418 | // todo: implement --allow-debuggers | ||
419 | BLACKLIST(101), // ptrace | ||
420 | BLACKLIST(246), // kexec_load | ||
421 | BLACKLIST(304), // open_by_handle_at | ||
422 | BLACKLIST(303), // name_to_handle_at | ||
423 | BLACKLIST(174), // create_module | ||
424 | BLACKLIST(175), // init_module | ||
425 | BLACKLIST(313), // finit_module | ||
426 | BLACKLIST(176), // delete_module | ||
427 | BLACKLIST(172), // iopl | ||
428 | BLACKLIST(173), // ioperm | ||
429 | BLACKLIST(251), // ioprio_set | ||
430 | BLACKLIST(167), // swapon | ||
431 | BLACKLIST(168), // swapoff | ||
432 | BLACKLIST(103), // syslog | ||
433 | BLACKLIST(310), // process_vm_readv | ||
434 | BLACKLIST(311), // process_vm_writev | ||
435 | BLACKLIST(139), // sysfs | ||
436 | BLACKLIST(156), // _sysctl | ||
437 | BLACKLIST(159), // adjtimex | ||
438 | BLACKLIST(305), // clock_adjtime | ||
439 | BLACKLIST(212), // lookup_dcookie | ||
440 | BLACKLIST(298), // perf_event_open | ||
441 | BLACKLIST(300), // fanotify_init | ||
442 | BLACKLIST(312), // kcmp | ||
443 | BLACKLIST(248), // add_key | ||
444 | BLACKLIST(249), // request_key | ||
445 | BLACKLIST(250), // keyctl | ||
446 | BLACKLIST(134), // uselib | ||
447 | BLACKLIST(163), // acct | ||
448 | BLACKLIST(154), // modify_ldt | ||
449 | BLACKLIST(155), // pivot_root | ||
450 | BLACKLIST(206), // io_setup | ||
451 | BLACKLIST(207), // io_destroy | ||
452 | BLACKLIST(208), // io_getevents | ||
453 | BLACKLIST(209), // io_submit | ||
454 | BLACKLIST(210), // io_cancel | ||
455 | BLACKLIST(216), // remap_file_pages | ||
456 | BLACKLIST(237), // mbind | ||
457 | BLACKLIST(239), // get_mempolicy | ||
458 | BLACKLIST(238), // set_mempolicy | ||
459 | BLACKLIST(256), // migrate_pages | ||
460 | BLACKLIST(279), // move_pages | ||
461 | BLACKLIST(278), // vmsplice | ||
462 | BLACKLIST(161), // chroot | ||
463 | BLACKLIST(184), // tuxcall | ||
464 | BLACKLIST(169), // reboot | ||
465 | BLACKLIST(180), // nfsservctl | ||
466 | BLACKLIST(177), // get_kernel_syms | ||
467 | |||
468 | RETURN_ALLOW | ||
469 | }; | ||
470 | 91 | ||
471 | struct sock_fprog prog = { | 92 | // build the seccomp filter as a regular user |
472 | .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), | 93 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, |
473 | .filter = filter, | 94 | PATH_FSECCOMP, "secondary", "64", RUN_SECCOMP_AMD64); |
474 | }; | 95 | if (rv) |
96 | exit(rv); | ||
475 | 97 | ||
476 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | 98 | if (seccomp_load(RUN_SECCOMP_AMD64) == 0) { |
477 | ; | 99 | if (arg_debug) |
478 | } | 100 | printf("Dual i386/amd64 seccomp filter configured\n"); |
479 | else if (arg_debug) { | ||
480 | printf("Dual i386/amd64 seccomp filter configured\n"); | ||
481 | } | 101 | } |
482 | } | 102 | } |
483 | 103 | ||
484 | 104 | ||
485 | // drop filter for seccomp option | 105 | // drop filter for seccomp option |
486 | int seccomp_filter_drop(int enforce_seccomp) { | 106 | int seccomp_filter_drop(int enforce_seccomp) { |
487 | filter_init(); | ||
488 | |||
489 | // default seccomp | 107 | // default seccomp |
490 | if (cfg.seccomp_list_drop == NULL) { | 108 | if (cfg.seccomp_list_drop == NULL && cfg.seccomp_list == NULL) { |
491 | #if defined(__x86_64__) | 109 | #if defined(__x86_64__) |
492 | seccomp_filter_32(); | 110 | seccomp_filter_32(); |
493 | #endif | 111 | #endif |
494 | #if defined(__i386__) | 112 | #if defined(__i386__) |
495 | seccomp_filter_64(); | 113 | seccomp_filter_64(); |
496 | #endif | 114 | #endif |
497 | 115 | if (arg_debug) | |
498 | #ifdef SYS_mount | 116 | printf("Build default seccomp filter\n"); |
499 | filter_add_blacklist(SYS_mount, 0); | 117 | // build the seccomp filter as a regular user |
500 | #endif | 118 | int rv; |
501 | #ifdef SYS_umount2 | 119 | if (arg_allow_debuggers) |
502 | filter_add_blacklist(SYS_umount2, 0); | 120 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, |
503 | #endif | 121 | PATH_FSECCOMP, "default", RUN_SECCOMP_CFG, "allow-debuggers"); |
504 | 122 | else | |
505 | if (!arg_allow_debuggers) { | 123 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, |
506 | #ifdef SYS_ptrace | 124 | PATH_FSECCOMP, "default", RUN_SECCOMP_CFG); |
507 | filter_add_blacklist(SYS_ptrace, 0); | 125 | if (rv) |
508 | #endif | 126 | exit(rv); |
509 | } | ||
510 | |||
511 | #ifdef SYS_kexec_load | ||
512 | filter_add_blacklist(SYS_kexec_load, 0); | ||
513 | #endif | ||
514 | #ifdef SYS_kexec_file_load | ||
515 | filter_add_blacklist(SYS_kexec_file_load, 0); | ||
516 | #endif | ||
517 | #ifdef SYS_open_by_handle_at | ||
518 | filter_add_blacklist(SYS_open_by_handle_at, 0); | ||
519 | #endif | ||
520 | #ifdef SYS_name_to_handle_at | ||
521 | filter_add_blacklist(SYS_name_to_handle_at, 0); | ||
522 | #endif | ||
523 | #ifdef SYS_init_module | ||
524 | filter_add_blacklist(SYS_init_module, 0); | ||
525 | #endif | ||
526 | #ifdef SYS_finit_module // introduced in 2013 | ||
527 | filter_add_blacklist(SYS_finit_module, 0); | ||
528 | #endif | ||
529 | #ifdef SYS_create_module | ||
530 | filter_add_blacklist(SYS_create_module, 0); | ||
531 | #endif | ||
532 | #ifdef SYS_delete_module | ||
533 | filter_add_blacklist(SYS_delete_module, 0); | ||
534 | #endif | ||
535 | #ifdef SYS_iopl | ||
536 | filter_add_blacklist(SYS_iopl, 0); | ||
537 | #endif | ||
538 | #ifdef SYS_ioperm | ||
539 | filter_add_blacklist(SYS_ioperm, 0); | ||
540 | #endif | ||
541 | #ifdef SYS_ioprio_set | ||
542 | filter_add_blacklist(SYS_ioprio_set, 0); | ||
543 | #endif | ||
544 | #ifdef SYS_ni_syscall // new io permissions call on arm devices | ||
545 | filter_add_blacklist(SYS_ni_syscall, 0); | ||
546 | #endif | ||
547 | #ifdef SYS_swapon | ||
548 | filter_add_blacklist(SYS_swapon, 0); | ||
549 | #endif | ||
550 | #ifdef SYS_swapoff | ||
551 | filter_add_blacklist(SYS_swapoff, 0); | ||
552 | #endif | ||
553 | #ifdef SYS_syslog | ||
554 | filter_add_blacklist(SYS_syslog, 0); | ||
555 | #endif | ||
556 | if (!arg_allow_debuggers) { | ||
557 | #ifdef SYS_process_vm_readv | ||
558 | filter_add_blacklist(SYS_process_vm_readv, 0); | ||
559 | #endif | ||
560 | } | ||
561 | |||
562 | #ifdef SYS_process_vm_writev | ||
563 | filter_add_blacklist(SYS_process_vm_writev, 0); | ||
564 | #endif | ||
565 | |||
566 | // mknod removed in 0.9.29 - it brakes Zotero extension | ||
567 | //#ifdef SYS_mknod | ||
568 | // filter_add_blacklist(SYS_mknod, 0); | ||
569 | //#endif | ||
570 | |||
571 | // new syscalls in 0.9,23 | ||
572 | #ifdef SYS_sysfs | ||
573 | filter_add_blacklist(SYS_sysfs, 0); | ||
574 | #endif | ||
575 | #ifdef SYS__sysctl | ||
576 | filter_add_blacklist(SYS__sysctl, 0); | ||
577 | #endif | ||
578 | #ifdef SYS_adjtimex | ||
579 | filter_add_blacklist(SYS_adjtimex, 0); | ||
580 | #endif | ||
581 | #ifdef SYS_clock_adjtime | ||
582 | filter_add_blacklist(SYS_clock_adjtime, 0); | ||
583 | #endif | ||
584 | #ifdef SYS_lookup_dcookie | ||
585 | filter_add_blacklist(SYS_lookup_dcookie, 0); | ||
586 | #endif | ||
587 | #ifdef SYS_perf_event_open | ||
588 | filter_add_blacklist(SYS_perf_event_open, 0); | ||
589 | #endif | ||
590 | #ifdef SYS_fanotify_init | ||
591 | filter_add_blacklist(SYS_fanotify_init, 0); | ||
592 | #endif | ||
593 | #ifdef SYS_kcmp | ||
594 | filter_add_blacklist(SYS_kcmp, 0); | ||
595 | #endif | ||
596 | |||
597 | // 0.9.32 | ||
598 | #ifdef SYS_add_key | ||
599 | filter_add_blacklist(SYS_add_key, 0); | ||
600 | #endif | ||
601 | #ifdef SYS_request_key | ||
602 | filter_add_blacklist(SYS_request_key, 0); | ||
603 | #endif | ||
604 | #ifdef SYS_keyctl | ||
605 | filter_add_blacklist(SYS_keyctl, 0); | ||
606 | #endif | ||
607 | #ifdef SYS_uselib | ||
608 | filter_add_blacklist(SYS_uselib, 0); | ||
609 | #endif | ||
610 | #ifdef SYS_acct | ||
611 | filter_add_blacklist(SYS_acct, 0); | ||
612 | #endif | ||
613 | #ifdef SYS_modify_ldt | ||
614 | filter_add_blacklist(SYS_modify_ldt, 0); | ||
615 | #endif | ||
616 | //#ifdef SYS_unshare | ||
617 | // filter_add_blacklist(SYS_unshare, 0); | ||
618 | //#endif | ||
619 | #ifdef SYS_pivot_root | ||
620 | filter_add_blacklist(SYS_pivot_root, 0); | ||
621 | #endif | ||
622 | //#ifdef SYS_quotactl | ||
623 | // filter_add_blacklist(SYS_quotactl, 0); | ||
624 | //#endif | ||
625 | #ifdef SYS_io_setup | ||
626 | filter_add_blacklist(SYS_io_setup, 0); | ||
627 | #endif | ||
628 | #ifdef SYS_io_destroy | ||
629 | filter_add_blacklist(SYS_io_destroy, 0); | ||
630 | #endif | ||
631 | #ifdef SYS_io_getevents | ||
632 | filter_add_blacklist(SYS_io_getevents, 0); | ||
633 | #endif | ||
634 | #ifdef SYS_io_submit | ||
635 | filter_add_blacklist(SYS_io_submit, 0); | ||
636 | #endif | ||
637 | #ifdef SYS_io_cancel | ||
638 | filter_add_blacklist(SYS_io_cancel, 0); | ||
639 | #endif | ||
640 | #ifdef SYS_remap_file_pages | ||
641 | filter_add_blacklist(SYS_remap_file_pages, 0); | ||
642 | #endif | ||
643 | #ifdef SYS_mbind | ||
644 | filter_add_blacklist(SYS_mbind, 0); | ||
645 | #endif | ||
646 | #ifdef SYS_get_mempolicy | ||
647 | filter_add_blacklist(SYS_get_mempolicy, 0); | ||
648 | #endif | ||
649 | #ifdef SYS_set_mempolicy | ||
650 | filter_add_blacklist(SYS_set_mempolicy, 0); | ||
651 | #endif | ||
652 | #ifdef SYS_migrate_pages | ||
653 | filter_add_blacklist(SYS_migrate_pages, 0); | ||
654 | #endif | ||
655 | #ifdef SYS_move_pages | ||
656 | filter_add_blacklist(SYS_move_pages, 0); | ||
657 | #endif | ||
658 | #ifdef SYS_vmsplice | ||
659 | filter_add_blacklist(SYS_vmsplice, 0); | ||
660 | #endif | ||
661 | #ifdef SYS_chroot | ||
662 | filter_add_blacklist(SYS_chroot, 0); | ||
663 | #endif | ||
664 | //#ifdef SYS_set_robust_list | ||
665 | // filter_add_blacklist(SYS_set_robust_list, 0); | ||
666 | //#endif | ||
667 | //#ifdef SYS_get_robust_list | ||
668 | // filter_add_blacklist(SYS_get_robust_list, 0); | ||
669 | //#endif | ||
670 | |||
671 | // CHECK_SECCOMP(seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone), 1, | ||
672 | // SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER))); | ||
673 | |||
674 | // 0.9.39 | ||
675 | #ifdef SYS_tuxcall | ||
676 | filter_add_blacklist(SYS_tuxcall, 0); | ||
677 | #endif | ||
678 | #ifdef SYS_reboot | ||
679 | filter_add_blacklist(SYS_reboot, 0); | ||
680 | #endif | ||
681 | #ifdef SYS_nfsservctl | ||
682 | filter_add_blacklist(SYS_nfsservctl, 0); | ||
683 | #endif | ||
684 | #ifdef SYS_get_kernel_syms | ||
685 | filter_add_blacklist(SYS_get_kernel_syms, 0); | ||
686 | #endif | ||
687 | |||
688 | } | 127 | } |
689 | 128 | ||
690 | // default seccomp filter with additional drop list | 129 | // default seccomp filter with additional drop list |
691 | if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) { | 130 | else if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) { |
692 | if (syscall_check_list(cfg.seccomp_list, filter_add_blacklist, 0)) { | 131 | #if defined(__x86_64__) |
693 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | 132 | seccomp_filter_32(); |
133 | #endif | ||
134 | #if defined(__i386__) | ||
135 | seccomp_filter_64(); | ||
136 | #endif | ||
137 | if (arg_debug) | ||
138 | printf("Build default+drop seccomp filter\n"); | ||
139 | if (strlen(cfg.seccomp_list) == 0) { | ||
140 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | ||
694 | exit(1); | 141 | exit(1); |
695 | } | 142 | } |
143 | |||
144 | // build the seccomp filter as a regular user | ||
145 | int rv; | ||
146 | if (arg_allow_debuggers) | ||
147 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6, | ||
148 | PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list, "allow-debuggers"); | ||
149 | else | ||
150 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, | ||
151 | PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list); | ||
152 | if (rv) | ||
153 | exit(rv); | ||
696 | } | 154 | } |
697 | // drop list | 155 | |
156 | // drop list without defaults - secondary filters are not installed | ||
698 | else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { | 157 | else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { |
699 | if (syscall_check_list(cfg.seccomp_list_drop, filter_add_blacklist, 0)) { | 158 | if (arg_debug) |
700 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | 159 | printf("Build drop seccomp filter\n"); |
160 | if (strlen(cfg.seccomp_list_drop) == 0) { | ||
161 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | ||
701 | exit(1); | 162 | exit(1); |
702 | } | 163 | } |
703 | } | ||
704 | |||
705 | |||
706 | filter_end_blacklist(); | ||
707 | if (arg_debug) | ||
708 | filter_debug(); | ||
709 | |||
710 | // save seccomp filter in /run/firejail/mnt/seccomp | ||
711 | // in order to use it in --join operations | ||
712 | write_seccomp_file(); | ||
713 | |||
714 | |||
715 | struct sock_fprog prog = { | ||
716 | .len = sfilter_index, | ||
717 | .filter = sfilter, | ||
718 | }; | ||
719 | 164 | ||
720 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | 165 | // build the seccomp filter as a regular user |
721 | if (enforce_seccomp) { | 166 | int rv; |
722 | fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n"); | 167 | if (arg_allow_debuggers) |
723 | exit(1); | 168 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, |
724 | } | 169 | PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop, "allow-debuggers"); |
725 | else | 170 | else |
726 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | 171 | rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, |
172 | PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop); | ||
727 | 173 | ||
728 | return 1; | 174 | if (rv) |
175 | exit(rv); | ||
176 | } | ||
177 | else { | ||
178 | assert(0); | ||
729 | } | 179 | } |
730 | 180 | ||
731 | return 0; | 181 | // load the filter |
182 | if (seccomp_load(RUN_SECCOMP_CFG) == 0) { | ||
183 | if (arg_debug) | ||
184 | printf("seccomp filter configured\n"); | ||
185 | } | ||
186 | else if (enforce_seccomp) { | ||
187 | fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n"); | ||
188 | exit(1); | ||
189 | } | ||
190 | |||
191 | if (arg_debug) | ||
192 | sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, | ||
193 | PATH_FSECCOMP, "print", RUN_SECCOMP_CFG); | ||
194 | |||
195 | return seccomp_load(RUN_SECCOMP_CFG); | ||
732 | } | 196 | } |
733 | 197 | ||
734 | // keep filter for seccomp option | 198 | // keep filter for seccomp option |
735 | int seccomp_filter_keep(void) { | 199 | int seccomp_filter_keep(void) { |
736 | filter_init(); | 200 | if (arg_debug) |
737 | 201 | printf("Build drop seccomp filter\n"); | |
738 | // these 4 syscalls are used by firejail after the seccomp filter is initialized | 202 | if (strlen(cfg.seccomp_list_keep) == 0) { |
739 | filter_add_whitelist(SYS_setuid, 0); | 203 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); |
740 | filter_add_whitelist(SYS_setgid, 0); | 204 | exit(1); |
741 | filter_add_whitelist(SYS_setgroups, 0); | ||
742 | filter_add_whitelist(SYS_dup, 0); | ||
743 | |||
744 | // apply keep list | ||
745 | if (cfg.seccomp_list_keep) { | ||
746 | if (syscall_check_list(cfg.seccomp_list_keep, filter_add_whitelist, 0)) { | ||
747 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | ||
748 | exit(1); | ||
749 | } | ||
750 | } | 205 | } |
751 | 206 | ||
752 | filter_end_whitelist(); | 207 | // build the seccomp filter as a regular user |
208 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, | ||
209 | PATH_FSECCOMP, "keep", RUN_SECCOMP_CFG, cfg.seccomp_list_keep); | ||
210 | if (rv) | ||
211 | exit(rv); | ||
753 | if (arg_debug) | 212 | if (arg_debug) |
754 | filter_debug(); | 213 | printf("seccomp filter configured\n"); |
755 | |||
756 | // save seccomp filter in /run/firejail/mnt/seccomp | ||
757 | // in order to use it in --join operations | ||
758 | write_seccomp_file(); | ||
759 | |||
760 | 214 | ||
761 | struct sock_fprog prog = { | 215 | |
762 | .len = sfilter_index, | 216 | return seccomp_load(RUN_SECCOMP_CFG); |
763 | .filter = sfilter, | ||
764 | }; | ||
765 | |||
766 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
767 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
768 | return 1; | ||
769 | } | ||
770 | else if (arg_debug) { | ||
771 | printf("seccomp enabled\n"); | ||
772 | } | ||
773 | |||
774 | return 0; | ||
775 | } | 217 | } |
776 | 218 | ||
777 | // errno filter for seccomp option | 219 | // errno filter for seccomp option |
778 | int seccomp_filter_errno(void) { | 220 | int seccomp_filter_errno(void) { |
221 | #if 0 //todo: disabled temporarely, bring it back | ||
779 | int i; | 222 | int i; |
780 | int higest_errno = errno_highest_nr(); | 223 | int higest_errno = errno_highest_nr(); |
781 | filter_init(); | 224 | filter_init(); |
@@ -798,42 +241,11 @@ int seccomp_filter_errno(void) { | |||
798 | // save seccomp filter in /run/firejail/mnt/seccomp | 241 | // save seccomp filter in /run/firejail/mnt/seccomp |
799 | // in order to use it in --join operations | 242 | // in order to use it in --join operations |
800 | write_seccomp_file(); | 243 | write_seccomp_file(); |
801 | 244 | return seccomp_load(RUN_SECCOMP_CFG); | |
802 | struct sock_fprog prog = { | 245 | #else |
803 | .len = sfilter_index, | 246 | printf("*** --seccomp.<errno> is temporarily disabled, it will be brought back soon ***\n"); |
804 | .filter = sfilter, | ||
805 | }; | ||
806 | |||
807 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
808 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
809 | return 1; | ||
810 | } | ||
811 | else if (arg_debug) { | ||
812 | printf("seccomp enabled\n"); | ||
813 | } | ||
814 | |||
815 | return 0; | 247 | return 0; |
816 | } | 248 | #endif |
817 | |||
818 | |||
819 | |||
820 | void seccomp_set(void) { | ||
821 | // read seccomp filter from /runp/firejail/mnt/seccomp | ||
822 | read_seccomp_file(RUN_SECCOMP_CFG); | ||
823 | |||
824 | // apply filter | ||
825 | struct sock_fprog prog = { | ||
826 | .len = sfilter_index, | ||
827 | .filter = sfilter, | ||
828 | }; | ||
829 | |||
830 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
831 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
832 | return; | ||
833 | } | ||
834 | else if (arg_debug) { | ||
835 | printf("seccomp enabled\n"); | ||
836 | } | ||
837 | } | 249 | } |
838 | 250 | ||
839 | void seccomp_print_filter_name(const char *name) { | 251 | void seccomp_print_filter_name(const char *name) { |
@@ -890,10 +302,11 @@ void seccomp_print_filter(pid_t pid) { | |||
890 | exit(1); | 302 | exit(1); |
891 | } | 303 | } |
892 | 304 | ||
893 | // read and print the filter | 305 | // read and print the filter - run this as root, the user doesn't have access |
894 | read_seccomp_file(fname); | 306 | int rv = sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, |
895 | drop_privs(1); | 307 | PATH_FSECCOMP, "print", fname); |
896 | filter_debug(); | 308 | if (rv) |
309 | exit(rv); | ||
897 | free(fname); | 310 | free(fname); |
898 | 311 | ||
899 | exit(0); | 312 | exit(0); |
diff --git a/src/firejail/syscall.c b/src/firejail/syscall.c deleted file mode 100644 index f405f23c8..000000000 --- a/src/firejail/syscall.c +++ /dev/null | |||
@@ -1,105 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifdef HAVE_SECCOMP | ||
22 | #include "firejail.h" | ||
23 | #include <sys/syscall.h> | ||
24 | |||
25 | typedef struct { | ||
26 | char *name; | ||
27 | int nr; | ||
28 | } SyscallEntry; | ||
29 | |||
30 | static SyscallEntry syslist[] = { | ||
31 | // | ||
32 | // code generated using tools/extract-syscall | ||
33 | // | ||
34 | #include "../include/syscall.h" | ||
35 | // | ||
36 | // end of generated code | ||
37 | // | ||
38 | }; // end of syslist | ||
39 | |||
40 | const char *syscall_find_nr(int nr) { | ||
41 | int i; | ||
42 | int elems = sizeof(syslist) / sizeof(syslist[0]); | ||
43 | for (i = 0; i < elems; i++) { | ||
44 | if (nr == syslist[i].nr) | ||
45 | return syslist[i].name; | ||
46 | } | ||
47 | |||
48 | return "unknown"; | ||
49 | } | ||
50 | |||
51 | // return -1 if error, or syscall number | ||
52 | static int syscall_find_name(const char *name) { | ||
53 | int i; | ||
54 | int elems = sizeof(syslist) / sizeof(syslist[0]); | ||
55 | for (i = 0; i < elems; i++) { | ||
56 | if (strcmp(name, syslist[i].name) == 0) | ||
57 | return syslist[i].nr; | ||
58 | } | ||
59 | |||
60 | return -1; | ||
61 | } | ||
62 | |||
63 | // return 1 if error, 0 if OK | ||
64 | int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg) { | ||
65 | // don't allow empty lists | ||
66 | if (slist == NULL || *slist == '\0') { | ||
67 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | ||
68 | return -1; | ||
69 | } | ||
70 | |||
71 | // work on a copy of the string | ||
72 | char *str = strdup(slist); | ||
73 | if (!str) | ||
74 | errExit("strdup"); | ||
75 | |||
76 | char *ptr = str; | ||
77 | char *start = str; | ||
78 | while (*ptr != '\0') { | ||
79 | if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') | ||
80 | ; | ||
81 | else if (*ptr == ',') { | ||
82 | *ptr = '\0'; | ||
83 | int nr = syscall_find_name(start); | ||
84 | if (nr == -1) | ||
85 | fprintf(stderr, "Warning: syscall %s not found\n", start); | ||
86 | else if (callback != NULL) | ||
87 | callback(nr, arg); | ||
88 | |||
89 | start = ptr + 1; | ||
90 | } | ||
91 | ptr++; | ||
92 | } | ||
93 | if (*start != '\0') { | ||
94 | int nr = syscall_find_name(start); | ||
95 | if (nr == -1) | ||
96 | fprintf(stderr, "Warning: syscall %s not found\n", start); | ||
97 | else if (callback != NULL) | ||
98 | callback(nr, arg); | ||
99 | } | ||
100 | |||
101 | free(str); | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | #endif // HAVE_SECCOMP | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c index 8d3b9d3cd..9752504e5 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -721,13 +721,13 @@ void create_empty_file_as_root(const char *fname, mode_t mode) { | |||
721 | if (arg_debug) | 721 | if (arg_debug) |
722 | printf("Creating empty %s file\n", fname); | 722 | printf("Creating empty %s file\n", fname); |
723 | 723 | ||
724 | /* coverity[toctou] */ | ||
725 | FILE *fp = fopen(fname, "w"); | 724 | FILE *fp = fopen(fname, "w"); |
726 | if (!fp) | 725 | if (!fp) |
727 | errExit("fopen"); | 726 | errExit("fopen"); |
728 | |||
729 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR); | 727 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR); |
730 | fclose(fp); | 728 | fclose(fp); |
729 | if (chmod(fname, mode) == -1) | ||
730 | errExit("chmod"); | ||
731 | } | 731 | } |
732 | } | 732 | } |
733 | 733 | ||
diff --git a/src/fnet/Makefile.in b/src/fnet/Makefile.in index 1bfb4c68d..b515d2333 100644 --- a/src/fnet/Makefile.in +++ b/src/fnet/Makefile.in | |||
@@ -30,11 +30,11 @@ BINOBJS = $(foreach file, $(OBJS), $file) | |||
30 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -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 | 30 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -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 |
31 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread | 31 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread |
32 | 32 | ||
33 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h | 33 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/libnetlink.h |
34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | 34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ |
35 | 35 | ||
36 | fnet: $(OBJS) ../lib/libnetlink.o ../lib/common.o | 36 | fnet: $(OBJS) ../lib/libnetlink.o ../lib/common.o |
37 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) | 37 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o $(LIBS) $(EXTRA_LDFLAGS) |
38 | 38 | ||
39 | clean:; rm -f *.o fnet | 39 | clean:; rm -f *.o fnet |
40 | 40 | ||
diff --git a/src/fseccomp/Makefile.in b/src/fseccomp/Makefile.in index e7edd1b8f..110d2c95f 100644 --- a/src/fseccomp/Makefile.in +++ b/src/fseccomp/Makefile.in | |||
@@ -30,11 +30,11 @@ BINOBJS = $(foreach file, $(OBJS), $file) | |||
30 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -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 | 30 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -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 |
31 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread | 31 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread |
32 | 32 | ||
33 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h ../include/syscall.h | 33 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h |
34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | 34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ |
35 | 35 | ||
36 | fseccomp: $(OBJS) ../lib/libnetlink.o ../lib/common.o | 36 | fseccomp: $(OBJS) ../lib/libnetlink.o ../lib/common.o |
37 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) | 37 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) |
38 | 38 | ||
39 | clean:; rm -f *.o fseccomp | 39 | clean:; rm -f *.o fseccomp |
40 | 40 | ||
diff --git a/src/fseccomp/errno.c b/src/fseccomp/errno.c index 625f484bd..dbee916d4 100644 --- a/src/fseccomp/errno.c +++ b/src/fseccomp/errno.c | |||
@@ -1,3 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
1 | #include "fseccomp.h" | 20 | #include "fseccomp.h" |
2 | 21 | ||
3 | #include <errno.h> | 22 | #include <errno.h> |
@@ -151,6 +170,30 @@ static ErrnoEntry errnolist[] = { | |||
151 | #endif | 170 | #endif |
152 | }; | 171 | }; |
153 | 172 | ||
173 | int errno_find_name(const char *name) { | ||
174 | int i; | ||
175 | int elems = sizeof(errnolist) / sizeof(errnolist[0]); | ||
176 | for (i = 0; i < elems; i++) { | ||
177 | if (strcasecmp(name, errnolist[i].name) == 0) | ||
178 | return errnolist[i].nr; | ||
179 | } | ||
180 | |||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | char *errno_find_nr(int nr) { | ||
185 | int i; | ||
186 | int elems = sizeof(errnolist) / sizeof(errnolist[0]); | ||
187 | for (i = 0; i < elems; i++) { | ||
188 | if (nr == errnolist[i].nr) | ||
189 | return errnolist[i].name; | ||
190 | } | ||
191 | |||
192 | return "unknown"; | ||
193 | } | ||
194 | |||
195 | |||
196 | |||
154 | void errno_print(void) { | 197 | void errno_print(void) { |
155 | int i; | 198 | int i; |
156 | int elems = sizeof(errnolist) / sizeof(errnolist[0]); | 199 | int elems = sizeof(errnolist) / sizeof(errnolist[0]); |
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index 57757ea6c..504f1c23f 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h | |||
@@ -1,3 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
1 | #ifndef FSECCOMP_H | 20 | #ifndef FSECCOMP_H |
2 | #define FSECCOMP_H | 21 | #define FSECCOMP_H |
3 | #include <stdio.h> | 22 | #include <stdio.h> |
@@ -8,11 +27,42 @@ | |||
8 | 27 | ||
9 | // syscall.c | 28 | // syscall.c |
10 | void syscall_print(void); | 29 | void syscall_print(void); |
30 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg); | ||
31 | int syscall_find_name(const char *name); | ||
32 | char *syscall_find_nr(int nr); | ||
11 | 33 | ||
12 | // errno.c | 34 | // errno.c |
13 | void errno_print(void); | 35 | void errno_print(void); |
36 | int errno_find_name(const char *name); | ||
37 | char *errno_find_nr(int nr); | ||
14 | 38 | ||
15 | // protocol.c | 39 | // protocol.c |
16 | void protocol_print(void); | 40 | void protocol_print(void); |
17 | void protocol_build_filter(const char *prlist, const char *fname); | 41 | void protocol_build_filter(const char *prlist, const char *fname); |
42 | |||
43 | // seccomp_secondary.c | ||
44 | void seccomp_secondary_64(const char *fname); | ||
45 | void seccomp_secondary_32(const char *fname); | ||
46 | |||
47 | // seccomp_file.c | ||
48 | void filter_init(int fd); | ||
49 | void filter_add_whitelist(int fd, int syscall, int arg); | ||
50 | void filter_add_blacklist(int fd, int syscall, int arg); | ||
51 | void filter_add_errno(int fd, int syscall, int arg); | ||
52 | void filter_end_blacklist(int fd); | ||
53 | void filter_end_whitelist(int fd); | ||
54 | |||
55 | // seccomp.c | ||
56 | // default list | ||
57 | void seccomp_default(const char *fname, int allow_debuggers); | ||
58 | // drop list | ||
59 | void seccomp_drop(const char *fname, char *list, int allow_debuggers); | ||
60 | // default+drop list | ||
61 | void seccomp_default_drop(const char *fname, char *list, int allow_debuggers); | ||
62 | // whitelisted filter | ||
63 | void seccomp_keep(const char *fname, char *list); | ||
64 | |||
65 | // seccomp_print | ||
66 | void filter_print(const char *fname); | ||
67 | |||
18 | #endif | 68 | #endif |
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index f53e2ef8b..22b13bcd9 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -1,3 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
1 | #include "fseccomp.h" | 20 | #include "fseccomp.h" |
2 | 21 | ||
3 | static void usage(void) { | 22 | static void usage(void) { |
@@ -6,6 +25,16 @@ static void usage(void) { | |||
6 | printf("\tfseccomp debug-errnos\n"); | 25 | printf("\tfseccomp debug-errnos\n"); |
7 | printf("\tfseccomp debug-protocols\n"); | 26 | printf("\tfseccomp debug-protocols\n"); |
8 | printf("\tfseccomp protocol build list file\n"); | 27 | printf("\tfseccomp protocol build list file\n"); |
28 | printf("\tfseccomp secondary 64 file\n"); | ||
29 | printf("\tfseccomp secondary 32 file\n"); | ||
30 | printf("\tfseccomp default file\n"); | ||
31 | printf("\tfseccomp default file allow-debuggers\n"); | ||
32 | printf("\tfseccomp drop file list\n"); | ||
33 | printf("\tfseccomp drop file list allow-debuggers\n"); | ||
34 | printf("\tfseccomp default drop file list\n"); | ||
35 | printf("\tfseccomp default drop file list allow-debuggers\n"); | ||
36 | printf("\tfseccomp keep file list\n"); | ||
37 | printf("\tfseccomp print file\n"); | ||
9 | } | 38 | } |
10 | 39 | ||
11 | int main(int argc, char **argv) { | 40 | int main(int argc, char **argv) { |
@@ -33,6 +62,26 @@ printf("\n"); | |||
33 | protocol_print(); | 62 | protocol_print(); |
34 | else if (argc == 5 && strcmp(argv[1], "protocol") == 0 && strcmp(argv[2], "build") == 0) | 63 | else if (argc == 5 && strcmp(argv[1], "protocol") == 0 && strcmp(argv[2], "build") == 0) |
35 | protocol_build_filter(argv[3], argv[4]); | 64 | protocol_build_filter(argv[3], argv[4]); |
65 | else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "64") == 0) | ||
66 | seccomp_secondary_64(argv[3]); | ||
67 | else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "32") == 0) | ||
68 | seccomp_secondary_32(argv[3]); | ||
69 | else if (argc == 3 && strcmp(argv[1], "default") == 0) | ||
70 | seccomp_default(argv[2], 0); | ||
71 | else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) | ||
72 | seccomp_default(argv[2], 1); | ||
73 | else if (argc == 4 && strcmp(argv[1], "drop") == 0) | ||
74 | seccomp_drop(argv[2], argv[3], 0); | ||
75 | else if (argc == 5 && strcmp(argv[1], "drop") == 0 && strcmp(argv[4], "allow-debuggers") == 0) | ||
76 | seccomp_drop(argv[2], argv[3], 1); | ||
77 | else if (argc == 5 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0) | ||
78 | seccomp_default_drop(argv[3], argv[4], 0); | ||
79 | else if (argc == 6 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0 && strcmp(argv[5], "allow-debuggers") == 0) | ||
80 | seccomp_default_drop(argv[3], argv[4], 1); | ||
81 | else if (argc == 4 && strcmp(argv[1], "keep") == 0) | ||
82 | seccomp_keep(argv[2], argv[3]); | ||
83 | else if (argc == 3 && strcmp(argv[1], "print") == 0) | ||
84 | filter_print(argv[2]); | ||
36 | else { | 85 | else { |
37 | fprintf(stderr, "Error fseccomp: invalid arguments\n"); | 86 | fprintf(stderr, "Error fseccomp: invalid arguments\n"); |
38 | return 1; | 87 | return 1; |
diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c new file mode 100644 index 000000000..cc6edc8ca --- /dev/null +++ b/src/fseccomp/seccomp.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include "fseccomp.h" | ||
21 | #include "../include/seccomp.h" | ||
22 | #include <sys/syscall.h> | ||
23 | |||
24 | static void add_default_list(int fd, int allow_debuggers) { | ||
25 | #ifdef SYS_mount | ||
26 | filter_add_blacklist(fd, SYS_mount, 0); | ||
27 | #endif | ||
28 | #ifdef SYS_umount2 | ||
29 | filter_add_blacklist(fd, SYS_umount2, 0); | ||
30 | #endif | ||
31 | |||
32 | if (!allow_debuggers) { | ||
33 | #ifdef SYS_ptrace | ||
34 | filter_add_blacklist(fd, SYS_ptrace, 0); | ||
35 | #endif | ||
36 | } | ||
37 | |||
38 | #ifdef SYS_kexec_load | ||
39 | filter_add_blacklist(fd, SYS_kexec_load, 0); | ||
40 | #endif | ||
41 | #ifdef SYS_kexec_file_load | ||
42 | filter_add_blacklist(fd, SYS_kexec_file_load, 0); | ||
43 | #endif | ||
44 | #ifdef SYS_open_by_handle_at | ||
45 | filter_add_blacklist(fd, SYS_open_by_handle_at, 0); | ||
46 | #endif | ||
47 | #ifdef SYS_name_to_handle_at | ||
48 | filter_add_blacklist(fd, SYS_name_to_handle_at, 0); | ||
49 | #endif | ||
50 | #ifdef SYS_init_module | ||
51 | filter_add_blacklist(fd, SYS_init_module, 0); | ||
52 | #endif | ||
53 | #ifdef SYS_finit_module | ||
54 | filter_add_blacklist(fd, SYS_finit_module, 0); | ||
55 | #endif | ||
56 | #ifdef SYS_create_module | ||
57 | filter_add_blacklist(fd, SYS_create_module, 0); | ||
58 | #endif | ||
59 | #ifdef SYS_delete_module | ||
60 | filter_add_blacklist(fd, SYS_delete_module, 0); | ||
61 | #endif | ||
62 | #ifdef SYS_iopl | ||
63 | filter_add_blacklist(fd, SYS_iopl, 0); | ||
64 | #endif | ||
65 | #ifdef SYS_ioperm | ||
66 | filter_add_blacklist(fd, SYS_ioperm, 0); | ||
67 | #endif | ||
68 | #ifdef SYS_ioprio_set | ||
69 | filter_add_blacklist(fd, SYS_ioprio_set, 0); | ||
70 | #endif | ||
71 | #ifdef SYS_ni_syscall | ||
72 | filter_add_blacklist(fd, SYS_ni_syscall, 0); | ||
73 | #endif | ||
74 | #ifdef SYS_swapon | ||
75 | filter_add_blacklist(fd, SYS_swapon, 0); | ||
76 | #endif | ||
77 | #ifdef SYS_swapoff | ||
78 | filter_add_blacklist(fd, SYS_swapoff, 0); | ||
79 | #endif | ||
80 | #ifdef SYS_syslog | ||
81 | filter_add_blacklist(fd, SYS_syslog, 0); | ||
82 | #endif | ||
83 | |||
84 | if (!allow_debuggers) { | ||
85 | #ifdef SYS_process_vm_readv | ||
86 | filter_add_blacklist(fd, SYS_process_vm_readv, 0); | ||
87 | #endif | ||
88 | } | ||
89 | |||
90 | #ifdef SYS_process_vm_writev | ||
91 | filter_add_blacklist(fd, SYS_process_vm_writev, 0); | ||
92 | #endif | ||
93 | |||
94 | // mknod removed in 0.9.29 - it brakes Zotero extension | ||
95 | //#ifdef SYS_mknod | ||
96 | // filter_add_blacklist(SYS_mknod, 0); | ||
97 | //#endif | ||
98 | |||
99 | #ifdef SYS_sysfs | ||
100 | filter_add_blacklist(fd, SYS_sysfs, 0); | ||
101 | #endif | ||
102 | #ifdef SYS__sysctl | ||
103 | filter_add_blacklist(fd, SYS__sysctl, 0); | ||
104 | #endif | ||
105 | #ifdef SYS_adjtimex | ||
106 | filter_add_blacklist(fd, SYS_adjtimex, 0); | ||
107 | #endif | ||
108 | #ifdef SYS_clock_adjtime | ||
109 | filter_add_blacklist(fd, SYS_clock_adjtime, 0); | ||
110 | #endif | ||
111 | #ifdef SYS_lookup_dcookie | ||
112 | filter_add_blacklist(fd, SYS_lookup_dcookie, 0); | ||
113 | #endif | ||
114 | #ifdef SYS_perf_event_open | ||
115 | filter_add_blacklist(fd, SYS_perf_event_open, 0); | ||
116 | #endif | ||
117 | #ifdef SYS_fanotify_init | ||
118 | filter_add_blacklist(fd, SYS_fanotify_init, 0); | ||
119 | #endif | ||
120 | #ifdef SYS_kcmp | ||
121 | filter_add_blacklist(fd, SYS_kcmp, 0); | ||
122 | #endif | ||
123 | #ifdef SYS_add_key | ||
124 | filter_add_blacklist(fd, SYS_add_key, 0); | ||
125 | #endif | ||
126 | #ifdef SYS_request_key | ||
127 | filter_add_blacklist(fd, SYS_request_key, 0); | ||
128 | #endif | ||
129 | #ifdef SYS_keyctl | ||
130 | filter_add_blacklist(fd, SYS_keyctl, 0); | ||
131 | #endif | ||
132 | #ifdef SYS_uselib | ||
133 | filter_add_blacklist(fd, SYS_uselib, 0); | ||
134 | #endif | ||
135 | #ifdef SYS_acct | ||
136 | filter_add_blacklist(fd, SYS_acct, 0); | ||
137 | #endif | ||
138 | #ifdef SYS_modify_ldt | ||
139 | filter_add_blacklist(fd, SYS_modify_ldt, 0); | ||
140 | #endif | ||
141 | #ifdef SYS_pivot_root | ||
142 | filter_add_blacklist(fd, SYS_pivot_root, 0); | ||
143 | #endif | ||
144 | #ifdef SYS_io_setup | ||
145 | filter_add_blacklist(fd, SYS_io_setup, 0); | ||
146 | #endif | ||
147 | #ifdef SYS_io_destroy | ||
148 | filter_add_blacklist(fd, SYS_io_destroy, 0); | ||
149 | #endif | ||
150 | #ifdef SYS_io_getevents | ||
151 | filter_add_blacklist(fd, SYS_io_getevents, 0); | ||
152 | #endif | ||
153 | #ifdef SYS_io_submit | ||
154 | filter_add_blacklist(fd, SYS_io_submit, 0); | ||
155 | #endif | ||
156 | #ifdef SYS_io_cancel | ||
157 | filter_add_blacklist(fd, SYS_io_cancel, 0); | ||
158 | #endif | ||
159 | #ifdef SYS_remap_file_pages | ||
160 | filter_add_blacklist(fd, SYS_remap_file_pages, 0); | ||
161 | #endif | ||
162 | #ifdef SYS_mbind | ||
163 | filter_add_blacklist(fd, SYS_mbind, 0); | ||
164 | #endif | ||
165 | #ifdef SYS_get_mempolicy | ||
166 | filter_add_blacklist(fd, SYS_get_mempolicy, 0); | ||
167 | #endif | ||
168 | #ifdef SYS_set_mempolicy | ||
169 | filter_add_blacklist(fd, SYS_set_mempolicy, 0); | ||
170 | #endif | ||
171 | #ifdef SYS_migrate_pages | ||
172 | filter_add_blacklist(fd, SYS_migrate_pages, 0); | ||
173 | #endif | ||
174 | #ifdef SYS_move_pages | ||
175 | filter_add_blacklist(fd, SYS_move_pages, 0); | ||
176 | #endif | ||
177 | #ifdef SYS_vmsplice | ||
178 | filter_add_blacklist(fd, SYS_vmsplice, 0); | ||
179 | #endif | ||
180 | #ifdef SYS_chroot | ||
181 | filter_add_blacklist(fd, SYS_chroot, 0); | ||
182 | #endif | ||
183 | #ifdef SYS_tuxcall | ||
184 | filter_add_blacklist(fd, SYS_tuxcall, 0); | ||
185 | #endif | ||
186 | #ifdef SYS_reboot | ||
187 | filter_add_blacklist(fd, SYS_reboot, 0); | ||
188 | #endif | ||
189 | #ifdef SYS_nfsservctl | ||
190 | filter_add_blacklist(fd, SYS_nfsservctl, 0); | ||
191 | #endif | ||
192 | #ifdef SYS_get_kernel_syms | ||
193 | filter_add_blacklist(fd, SYS_get_kernel_syms, 0); | ||
194 | #endif | ||
195 | } | ||
196 | |||
197 | // default list | ||
198 | void seccomp_default(const char *fname, int allow_debuggers) { | ||
199 | assert(fname); | ||
200 | |||
201 | // open file | ||
202 | int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
203 | if (fd < 0) { | ||
204 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
205 | exit(1); | ||
206 | } | ||
207 | |||
208 | // build filter | ||
209 | filter_init(fd); | ||
210 | add_default_list(fd, allow_debuggers); | ||
211 | filter_end_blacklist(fd); | ||
212 | |||
213 | // close file | ||
214 | close(fd); | ||
215 | } | ||
216 | |||
217 | // drop list | ||
218 | void seccomp_drop(const char *fname, char *list, int allow_debuggers) { | ||
219 | assert(fname); | ||
220 | (void) allow_debuggers; // todo: to implemnet it | ||
221 | |||
222 | // open file | ||
223 | int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
224 | if (fd < 0) { | ||
225 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
226 | exit(1); | ||
227 | } | ||
228 | |||
229 | // build filter | ||
230 | filter_init(fd); | ||
231 | if (syscall_check_list(list, filter_add_blacklist, fd, 0)) { | ||
232 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | ||
233 | exit(1); | ||
234 | } | ||
235 | filter_end_blacklist(fd); | ||
236 | |||
237 | // close file | ||
238 | close(fd); | ||
239 | } | ||
240 | |||
241 | // default+drop | ||
242 | void seccomp_default_drop(const char *fname, char *list, int allow_debuggers) { | ||
243 | assert(fname); | ||
244 | |||
245 | // open file | ||
246 | int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
247 | if (fd < 0) { | ||
248 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
249 | exit(1); | ||
250 | } | ||
251 | |||
252 | // build filter | ||
253 | filter_init(fd); | ||
254 | add_default_list(fd, allow_debuggers); | ||
255 | if (syscall_check_list(list, filter_add_blacklist, fd, 0)) { | ||
256 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | ||
257 | exit(1); | ||
258 | } | ||
259 | filter_end_blacklist(fd); | ||
260 | |||
261 | // close file | ||
262 | close(fd); | ||
263 | } | ||
264 | |||
265 | void seccomp_keep(const char *fname, char *list) { | ||
266 | // open file | ||
267 | int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
268 | if (fd < 0) { | ||
269 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
270 | exit(1); | ||
271 | } | ||
272 | |||
273 | // build filter | ||
274 | filter_init(fd); | ||
275 | // these 4 syscalls are used by firejail after the seccomp filter is initialized | ||
276 | filter_add_whitelist(fd, SYS_setuid, 0); | ||
277 | filter_add_whitelist(fd, SYS_setgid, 0); | ||
278 | filter_add_whitelist(fd, SYS_setgroups, 0); | ||
279 | filter_add_whitelist(fd, SYS_dup, 0); | ||
280 | filter_add_whitelist(fd, SYS_prctl, 0); | ||
281 | |||
282 | if (syscall_check_list(list, filter_add_whitelist, fd, 0)) { | ||
283 | fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); | ||
284 | exit(1); | ||
285 | } | ||
286 | |||
287 | filter_end_whitelist(fd); | ||
288 | |||
289 | // close file | ||
290 | close(fd); | ||
291 | } | ||
292 | |||
diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c new file mode 100644 index 000000000..10ef9dd31 --- /dev/null +++ b/src/fseccomp/seccomp_file.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include "fseccomp.h" | ||
21 | #include "../include/seccomp.h" | ||
22 | #include <sys/syscall.h> | ||
23 | |||
24 | static void write_to_file(int fd, void *data, int size) { | ||
25 | assert(data); | ||
26 | assert(size); | ||
27 | |||
28 | int written = 0; | ||
29 | while (written < size) { | ||
30 | int rv = write(fd, (unsigned char *) data + written, size - written); | ||
31 | if (rv == -1) { | ||
32 | fprintf(stderr, "Error fseccomp: cannot write seccomp file\n"); | ||
33 | exit(1); | ||
34 | } | ||
35 | written += rv; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | void filter_init(int fd) { | ||
40 | #if defined(__x86_64__) | ||
41 | #define X32_SYSCALL_BIT 0x40000000 | ||
42 | struct sock_filter filter[] = { | ||
43 | VALIDATE_ARCHITECTURE, | ||
44 | EXAMINE_SYSCALL, | ||
45 | // handle X32 ABI | ||
46 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), | ||
47 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), | ||
48 | RETURN_ERRNO(EPERM) | ||
49 | }; | ||
50 | #else | ||
51 | struct sock_filter filter[] = { | ||
52 | VALIDATE_ARCHITECTURE, | ||
53 | EXAMINE_SYSCALL | ||
54 | }; | ||
55 | #endif | ||
56 | |||
57 | #if 0 | ||
58 | { | ||
59 | int i; | ||
60 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
61 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
62 | printf("%x, ", (*ptr) & 0xff); | ||
63 | printf("\n"); | ||
64 | } | ||
65 | #endif | ||
66 | |||
67 | write_to_file(fd, filter, sizeof(filter)); | ||
68 | } | ||
69 | |||
70 | void filter_add_whitelist(int fd, int syscall, int arg) { | ||
71 | (void) arg; | ||
72 | |||
73 | struct sock_filter filter[] = { | ||
74 | WHITELIST(syscall) | ||
75 | }; | ||
76 | write_to_file(fd, filter, sizeof(filter)); | ||
77 | } | ||
78 | |||
79 | void filter_add_blacklist(int fd, int syscall, int arg) { | ||
80 | (void) arg; | ||
81 | |||
82 | struct sock_filter filter[] = { | ||
83 | BLACKLIST(syscall) | ||
84 | }; | ||
85 | write_to_file(fd, filter, sizeof(filter)); | ||
86 | } | ||
87 | |||
88 | void filter_add_errno(int fd, int syscall, int arg) { | ||
89 | struct sock_filter filter[] = { | ||
90 | BLACKLIST_ERRNO(syscall, arg) | ||
91 | }; | ||
92 | write_to_file(fd, filter, sizeof(filter)); | ||
93 | } | ||
94 | |||
95 | void filter_end_blacklist(int fd) { | ||
96 | struct sock_filter filter[] = { | ||
97 | RETURN_ALLOW | ||
98 | }; | ||
99 | write_to_file(fd, filter, sizeof(filter)); | ||
100 | } | ||
101 | |||
102 | void filter_end_whitelist(int fd) { | ||
103 | struct sock_filter filter[] = { | ||
104 | KILL_PROCESS | ||
105 | }; | ||
106 | write_to_file(fd, filter, sizeof(filter)); | ||
107 | } | ||
108 | |||
diff --git a/src/fseccomp/seccomp_print.c b/src/fseccomp/seccomp_print.c new file mode 100644 index 000000000..7dc983b12 --- /dev/null +++ b/src/fseccomp/seccomp_print.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include "fseccomp.h" | ||
21 | #include "../include/seccomp.h" | ||
22 | #include <sys/syscall.h> | ||
23 | |||
24 | static struct sock_filter *filter = NULL; | ||
25 | static int filter_cnt = 0; | ||
26 | |||
27 | static void load_seccomp(const char *fname) { | ||
28 | assert(fname); | ||
29 | |||
30 | // check file | ||
31 | struct stat s; | ||
32 | if (stat(fname, &s) == -1) { | ||
33 | fprintf(stderr, "Error fseccomp: cannot read protocol filter file\n"); | ||
34 | exit(1); | ||
35 | } | ||
36 | int size = s.st_size; | ||
37 | unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); | ||
38 | filter_cnt = entries; | ||
39 | //printf("size %d, entries %d\n", s.st_size, entries); | ||
40 | |||
41 | filter = malloc(sizeof(struct sock_filter) * entries); | ||
42 | if (!filter) | ||
43 | errExit("malloc"); | ||
44 | |||
45 | // read filter | ||
46 | memset(filter, 0, sizeof(struct sock_filter) * entries); | ||
47 | int src = open(fname, O_RDONLY); | ||
48 | int rd = 0; | ||
49 | while (rd < size) { | ||
50 | int rv = read(src, (unsigned char *) filter + rd, size - rd); | ||
51 | if (rv == -1) { | ||
52 | fprintf(stderr, "Error fseccomp: cannot read %s file\n", fname); | ||
53 | exit(1); | ||
54 | } | ||
55 | rd += rv; | ||
56 | } | ||
57 | close(src); | ||
58 | } | ||
59 | |||
60 | // debug filter | ||
61 | void filter_print(const char *fname) { | ||
62 | assert(fname); | ||
63 | load_seccomp(fname); | ||
64 | |||
65 | // start filter | ||
66 | struct sock_filter start[] = { | ||
67 | VALIDATE_ARCHITECTURE, | ||
68 | EXAMINE_SYSCALL | ||
69 | }; | ||
70 | |||
71 | // print sizes | ||
72 | printf("SECCOMP Filter:\n"); | ||
73 | |||
74 | // test the start of the filter | ||
75 | if (memcmp(&start[0], filter, sizeof(start)) == 0) { | ||
76 | printf(" VALIDATE_ARCHITECTURE\n"); | ||
77 | printf(" EXAMINE_SYSCAL\n"); | ||
78 | } | ||
79 | else { | ||
80 | printf("Invalid seccomp filter %s\n", fname); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | // loop trough blacklists | ||
85 | int i = 4; | ||
86 | while (i < filter_cnt) { | ||
87 | // minimal parsing! | ||
88 | unsigned char *ptr = (unsigned char *) &filter[i]; | ||
89 | int *nr = (int *) (ptr + 4); | ||
90 | if (*ptr == 0x15 && *(ptr +14) == 0xff && *(ptr + 15) == 0x7f ) { | ||
91 | printf(" WHITELIST %d %s\n", *nr, syscall_find_nr(*nr)); | ||
92 | i += 2; | ||
93 | } | ||
94 | else if (*ptr == 0x15 && *(ptr +14) == 0 && *(ptr + 15) == 0) { | ||
95 | printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); | ||
96 | i += 2; | ||
97 | } | ||
98 | else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) { | ||
99 | int err = *(ptr + 13) << 8 | *(ptr + 12); | ||
100 | printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err)); | ||
101 | i += 2; | ||
102 | } | ||
103 | else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { | ||
104 | printf(" KILL_PROCESS\n"); | ||
105 | i++; | ||
106 | } | ||
107 | else if (*ptr == 0x06 && *(ptr +6) == 0xff && *(ptr + 7) == 0x7f ) { | ||
108 | printf(" RETURN_ALLOW\n"); | ||
109 | i++; | ||
110 | } | ||
111 | else { | ||
112 | printf(" UNKNOWN ENTRY!!!\n"); | ||
113 | i++; | ||
114 | } | ||
115 | } | ||
116 | } | ||
diff --git a/src/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c new file mode 100644 index 000000000..a856e5aef --- /dev/null +++ b/src/fseccomp/seccomp_secondary.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include "fseccomp.h" | ||
21 | #include "../include/seccomp.h" | ||
22 | #include <sys/syscall.h> | ||
23 | |||
24 | void seccomp_secondary_64(const char *fname) { | ||
25 | // hardcoded syscall values | ||
26 | struct sock_filter filter[] = { | ||
27 | VALIDATE_ARCHITECTURE_64, | ||
28 | EXAMINE_SYSCALL, | ||
29 | BLACKLIST(165), // mount | ||
30 | BLACKLIST(166), // umount2 | ||
31 | // todo: implement --allow-debuggers | ||
32 | BLACKLIST(101), // ptrace | ||
33 | BLACKLIST(246), // kexec_load | ||
34 | BLACKLIST(304), // open_by_handle_at | ||
35 | BLACKLIST(303), // name_to_handle_at | ||
36 | BLACKLIST(174), // create_module | ||
37 | BLACKLIST(175), // init_module | ||
38 | BLACKLIST(313), // finit_module | ||
39 | BLACKLIST(176), // delete_module | ||
40 | BLACKLIST(172), // iopl | ||
41 | BLACKLIST(173), // ioperm | ||
42 | BLACKLIST(251), // ioprio_set | ||
43 | BLACKLIST(167), // swapon | ||
44 | BLACKLIST(168), // swapoff | ||
45 | BLACKLIST(103), // syslog | ||
46 | BLACKLIST(310), // process_vm_readv | ||
47 | BLACKLIST(311), // process_vm_writev | ||
48 | BLACKLIST(139), // sysfs | ||
49 | BLACKLIST(156), // _sysctl | ||
50 | BLACKLIST(159), // adjtimex | ||
51 | BLACKLIST(305), // clock_adjtime | ||
52 | BLACKLIST(212), // lookup_dcookie | ||
53 | BLACKLIST(298), // perf_event_open | ||
54 | BLACKLIST(300), // fanotify_init | ||
55 | BLACKLIST(312), // kcmp | ||
56 | BLACKLIST(248), // add_key | ||
57 | BLACKLIST(249), // request_key | ||
58 | BLACKLIST(250), // keyctl | ||
59 | BLACKLIST(134), // uselib | ||
60 | BLACKLIST(163), // acct | ||
61 | BLACKLIST(154), // modify_ldt | ||
62 | BLACKLIST(155), // pivot_root | ||
63 | BLACKLIST(206), // io_setup | ||
64 | BLACKLIST(207), // io_destroy | ||
65 | BLACKLIST(208), // io_getevents | ||
66 | BLACKLIST(209), // io_submit | ||
67 | BLACKLIST(210), // io_cancel | ||
68 | BLACKLIST(216), // remap_file_pages | ||
69 | BLACKLIST(237), // mbind | ||
70 | BLACKLIST(239), // get_mempolicy | ||
71 | BLACKLIST(238), // set_mempolicy | ||
72 | BLACKLIST(256), // migrate_pages | ||
73 | BLACKLIST(279), // move_pages | ||
74 | BLACKLIST(278), // vmsplice | ||
75 | BLACKLIST(161), // chroot | ||
76 | BLACKLIST(184), // tuxcall | ||
77 | BLACKLIST(169), // reboot | ||
78 | BLACKLIST(180), // nfsservctl | ||
79 | BLACKLIST(177), // get_kernel_syms | ||
80 | |||
81 | RETURN_ALLOW | ||
82 | }; | ||
83 | |||
84 | // save filter to file | ||
85 | int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
86 | if (dst < 0) { | ||
87 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
88 | exit(1); | ||
89 | } | ||
90 | |||
91 | int size = (int) sizeof(filter); | ||
92 | int written = 0; | ||
93 | while (written < size) { | ||
94 | int rv = write(dst, (unsigned char *) filter + written, size - written); | ||
95 | if (rv == -1) { | ||
96 | fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); | ||
97 | exit(1); | ||
98 | } | ||
99 | written += rv; | ||
100 | } | ||
101 | close(dst); | ||
102 | } | ||
103 | |||
104 | // i386 filter installed on amd64 architectures | ||
105 | void seccomp_secondary_32(const char *fname) { | ||
106 | // hardcoded syscall values | ||
107 | struct sock_filter filter[] = { | ||
108 | VALIDATE_ARCHITECTURE_32, | ||
109 | EXAMINE_SYSCALL, | ||
110 | BLACKLIST(21), // mount | ||
111 | BLACKLIST(52), // umount2 | ||
112 | // todo: implement --allow-debuggers | ||
113 | BLACKLIST(26), // ptrace | ||
114 | BLACKLIST(283), // kexec_load | ||
115 | BLACKLIST(341), // name_to_handle_at | ||
116 | BLACKLIST(342), // open_by_handle_at | ||
117 | BLACKLIST(127), // create_module | ||
118 | BLACKLIST(128), // init_module | ||
119 | BLACKLIST(350), // finit_module | ||
120 | BLACKLIST(129), // delete_module | ||
121 | BLACKLIST(110), // iopl | ||
122 | BLACKLIST(101), // ioperm | ||
123 | BLACKLIST(289), // ioprio_set | ||
124 | BLACKLIST(87), // swapon | ||
125 | BLACKLIST(115), // swapoff | ||
126 | BLACKLIST(103), // syslog | ||
127 | BLACKLIST(347), // process_vm_readv | ||
128 | BLACKLIST(348), // process_vm_writev | ||
129 | BLACKLIST(135), // sysfs | ||
130 | BLACKLIST(149), // _sysctl | ||
131 | BLACKLIST(124), // adjtimex | ||
132 | BLACKLIST(343), // clock_adjtime | ||
133 | BLACKLIST(253), // lookup_dcookie | ||
134 | BLACKLIST(336), // perf_event_open | ||
135 | BLACKLIST(338), // fanotify_init | ||
136 | BLACKLIST(349), // kcmp | ||
137 | BLACKLIST(286), // add_key | ||
138 | BLACKLIST(287), // request_key | ||
139 | BLACKLIST(288), // keyctl | ||
140 | BLACKLIST(86), // uselib | ||
141 | BLACKLIST(51), // acct | ||
142 | BLACKLIST(123), // modify_ldt | ||
143 | BLACKLIST(217), // pivot_root | ||
144 | BLACKLIST(245), // io_setup | ||
145 | BLACKLIST(246), // io_destroy | ||
146 | BLACKLIST(247), // io_getevents | ||
147 | BLACKLIST(248), // io_submit | ||
148 | BLACKLIST(249), // io_cancel | ||
149 | BLACKLIST(257), // remap_file_pages | ||
150 | BLACKLIST(274), // mbind | ||
151 | BLACKLIST(275), // get_mempolicy | ||
152 | BLACKLIST(276), // set_mempolicy | ||
153 | BLACKLIST(294), // migrate_pages | ||
154 | BLACKLIST(317), // move_pages | ||
155 | BLACKLIST(316), // vmsplice | ||
156 | BLACKLIST(61), // chroot | ||
157 | BLACKLIST(88), // reboot | ||
158 | BLACKLIST(169), // nfsservctl | ||
159 | BLACKLIST(130), // get_kernel_syms | ||
160 | |||
161 | RETURN_ALLOW | ||
162 | }; | ||
163 | |||
164 | // save filter to file | ||
165 | int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
166 | if (dst < 0) { | ||
167 | fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); | ||
168 | exit(1); | ||
169 | } | ||
170 | |||
171 | int size = (int) sizeof(filter); | ||
172 | int written = 0; | ||
173 | while (written < size) { | ||
174 | int rv = write(dst, (unsigned char *) filter + written, size - written); | ||
175 | if (rv == -1) { | ||
176 | fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); | ||
177 | exit(1); | ||
178 | } | ||
179 | written += rv; | ||
180 | } | ||
181 | close(dst); | ||
182 | } | ||
183 | |||
diff --git a/src/fseccomp/syscall.c b/src/fseccomp/syscall.c index c67d45598..e2052efde 100644 --- a/src/fseccomp/syscall.c +++ b/src/fseccomp/syscall.c | |||
@@ -1,3 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
1 | #include "fseccomp.h" | 20 | #include "fseccomp.h" |
2 | #include <sys/syscall.h> | 21 | #include <sys/syscall.h> |
3 | 22 | ||
@@ -16,6 +35,29 @@ static SyscallEntry syslist[] = { | |||
16 | // | 35 | // |
17 | }; // end of syslist | 36 | }; // end of syslist |
18 | 37 | ||
38 | // return -1 if error, or syscall number | ||
39 | int syscall_find_name(const char *name) { | ||
40 | int i; | ||
41 | int elems = sizeof(syslist) / sizeof(syslist[0]); | ||
42 | for (i = 0; i < elems; i++) { | ||
43 | if (strcmp(name, syslist[i].name) == 0) | ||
44 | return syslist[i].nr; | ||
45 | } | ||
46 | |||
47 | return -1; | ||
48 | } | ||
49 | |||
50 | char *syscall_find_nr(int nr) { | ||
51 | int i; | ||
52 | int elems = sizeof(syslist) / sizeof(syslist[0]); | ||
53 | for (i = 0; i < elems; i++) { | ||
54 | if (nr == syslist[i].nr) | ||
55 | return syslist[i].name; | ||
56 | } | ||
57 | |||
58 | return "unknown"; | ||
59 | } | ||
60 | |||
19 | void syscall_print(void) { | 61 | void syscall_print(void) { |
20 | int i; | 62 | int i; |
21 | int elems = sizeof(syslist) / sizeof(syslist[0]); | 63 | int elems = sizeof(syslist) / sizeof(syslist[0]); |
@@ -24,3 +66,45 @@ void syscall_print(void) { | |||
24 | } | 66 | } |
25 | printf("\n"); | 67 | printf("\n"); |
26 | } | 68 | } |
69 | |||
70 | // return 1 if error, 0 if OK | ||
71 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg) { | ||
72 | // don't allow empty lists | ||
73 | if (slist == NULL || *slist == '\0') { | ||
74 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | ||
75 | return -1; | ||
76 | } | ||
77 | |||
78 | // work on a copy of the string | ||
79 | char *str = strdup(slist); | ||
80 | if (!str) | ||
81 | errExit("strdup"); | ||
82 | |||
83 | char *ptr = str; | ||
84 | char *start = str; | ||
85 | while (*ptr != '\0') { | ||
86 | if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') | ||
87 | ; | ||
88 | else if (*ptr == ',') { | ||
89 | *ptr = '\0'; | ||
90 | int nr = syscall_find_name(start); | ||
91 | if (nr == -1) | ||
92 | fprintf(stderr, "Warning: syscall %s not found\n", start); | ||
93 | else if (callback != NULL) | ||
94 | callback(fd, nr, arg); | ||
95 | |||
96 | start = ptr + 1; | ||
97 | } | ||
98 | ptr++; | ||
99 | } | ||
100 | if (*start != '\0') { | ||
101 | int nr = syscall_find_name(start); | ||
102 | if (nr == -1) | ||
103 | fprintf(stderr, "Warning: syscall %s not found\n", start); | ||
104 | else if (callback != NULL) | ||
105 | callback(fd, nr, arg); | ||
106 | } | ||
107 | |||
108 | free(str); | ||
109 | return 0; | ||
110 | } | ||
diff --git a/test/filters/filters.sh b/test/filters/filters.sh index 5093c8614..5c7c98b3e 100755 --- a/test/filters/filters.sh +++ b/test/filters/filters.sh | |||
@@ -12,11 +12,21 @@ echo "TESTING: noroot (test/filters/noroot.exp)" | |||
12 | echo "TESTING: capabilities (test/filters/caps.exp)" | 12 | echo "TESTING: capabilities (test/filters/caps.exp)" |
13 | ./caps.exp | 13 | ./caps.exp |
14 | 14 | ||
15 | rm -f seccomp-test-file | ||
16 | if [ "$(uname -m)" = "x86_64" ]; then | ||
17 | echo "TESTING: fseccomp (test/filters/fseccomp.exp)" | ||
18 | ./fseccomp.exp | ||
19 | else | ||
20 | echo "TESTING SKIP: fseccomp test implemented only for x86_64" | ||
21 | fi | ||
22 | rm -f seccomp-test-file | ||
23 | |||
24 | |||
15 | if [ "$(uname -m)" = "x86_64" ]; then | 25 | if [ "$(uname -m)" = "x86_64" ]; then |
16 | echo "TESTING: protocol (test/filters/protocol.exp)" | 26 | echo "TESTING: protocol (test/filters/protocol.exp)" |
17 | ./protocol.exp | 27 | ./protocol.exp |
18 | else | 28 | else |
19 | echo "TESTING SKIP: protocol, not running on x86_64" | 29 | echo "TESTING SKIP: protocol, running only on x86_64" |
20 | fi | 30 | fi |
21 | 31 | ||
22 | echo "TESTING: seccomp bad empty (test/filters/seccomp-bad-empty.exp)" | 32 | echo "TESTING: seccomp bad empty (test/filters/seccomp-bad-empty.exp)" |
@@ -50,9 +60,6 @@ echo "TESTING: seccomp chmod profile - seccomp lists (test/filters/seccomp-chmod | |||
50 | echo "TESTING: seccomp empty (test/filters/seccomp-empty.exp)" | 60 | echo "TESTING: seccomp empty (test/filters/seccomp-empty.exp)" |
51 | ./seccomp-empty.exp | 61 | ./seccomp-empty.exp |
52 | 62 | ||
53 | echo "TESTING: seccomp bad empty (test/filters/seccomp-bad-empty.exp)" | ||
54 | ./seccomp-bad-empty.exp | ||
55 | |||
56 | if [ "$(uname -m)" = "x86_64" ]; then | 63 | if [ "$(uname -m)" = "x86_64" ]; then |
57 | echo "TESTING: seccomp dual filter (test/filters/seccomp-dualfilter.exp)" | 64 | echo "TESTING: seccomp dual filter (test/filters/seccomp-dualfilter.exp)" |
58 | ./seccomp-dualfilter.exp | 65 | ./seccomp-dualfilter.exp |
diff --git a/test/filters/fseccomp.exp b/test/filters/fseccomp.exp new file mode 100755 index 000000000..8a9a8f9dc --- /dev/null +++ b/test/filters/fseccomp.exp | |||
@@ -0,0 +1,138 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2016 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | after 100 | ||
11 | send -- "/usr/lib/firejail/fseccomp debug-syscalls\r" | ||
12 | expect { | ||
13 | timeout {puts "TESTING ERROR 1\n";exit} | ||
14 | "1 - write" | ||
15 | } | ||
16 | |||
17 | after 100 | ||
18 | send -- "/usr/lib/firejail/fseccomp debug-errnos\r" | ||
19 | expect { | ||
20 | timeout {puts "TESTING ERROR 2\n";exit} | ||
21 | "1 - EPERM" | ||
22 | } | ||
23 | |||
24 | after 100 | ||
25 | send -- "/usr/lib/firejail/fseccomp debug-protocols\r" | ||
26 | expect { | ||
27 | timeout {puts "TESTING ERROR 3\n";exit} | ||
28 | "unix, inet, inet6, netlink, packet," | ||
29 | } | ||
30 | |||
31 | after 100 | ||
32 | send -- "/usr/lib/firejail/fseccomp protocol build unix,inet seccomp-test-file\r" | ||
33 | after 100 | ||
34 | send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" | ||
35 | expect { | ||
36 | timeout {puts "TESTING ERROR 4.1\n";exit} | ||
37 | "WHITELIST 41 socket" | ||
38 | } | ||
39 | |||
40 | after 100 | ||
41 | send -- "/usr/lib/firejail/fseccomp secondary 64 seccomp-test-file\r" | ||
42 | after 100 | ||
43 | send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" | ||
44 | expect { | ||
45 | timeout {puts "TESTING ERROR 5.1\n";exit} | ||
46 | "BLACKLIST 165 mount" | ||
47 | } | ||
48 | expect { | ||
49 | timeout {puts "TESTING ERROR 5.2\n";exit} | ||
50 | "BLACKLIST 166 umount2" | ||
51 | } | ||
52 | expect { | ||
53 | timeout {puts "TESTING ERROR 5.3\n";exit} | ||
54 | "RETURN_ALLOW" | ||
55 | } | ||
56 | |||
57 | after 100 | ||
58 | send -- "/usr/lib/firejail/fseccomp default seccomp-test-file\r" | ||
59 | after 100 | ||
60 | send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" | ||
61 | expect { | ||
62 | timeout {puts "TESTING ERROR 6.1\n";exit} | ||
63 | "BLACKLIST 165 mount" | ||
64 | } | ||
65 | expect { | ||
66 | timeout {puts "TESTING ERROR 6.2\n";exit} | ||
67 | "BLACKLIST 166 umount2" | ||
68 | } | ||
69 | expect { | ||
70 | timeout {puts "TESTING ERROR 6.3\n";exit} | ||
71 | "RETURN_ALLOW" | ||
72 | } | ||
73 | |||
74 | after 100 | ||
75 | send -- "/usr/lib/firejail/fseccomp drop seccomp-test-file chmod,chown\r" | ||
76 | after 100 | ||
77 | send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" | ||
78 | expect { | ||
79 | timeout {puts "TESTING ERROR 7.1\n";exit} | ||
80 | "BLACKLIST 165 mount" {puts "TESTING ERROR 7.2\n";exit} | ||
81 | "BLACKLIST 166 umount2" {puts "TESTING ERROR 7.3\n";exit} | ||
82 | "BLACKLIST 90 chmod" | ||
83 | } | ||
84 | expect { | ||
85 | timeout {puts "TESTING ERROR 7.4\n";exit} | ||
86 | "BLACKLIST 92 chown" | ||
87 | } | ||
88 | expect { | ||
89 | timeout {puts "TESTING ERROR 7.5\n";exit} | ||
90 | "RETURN_ALLOW" | ||
91 | } | ||
92 | |||
93 | after 100 | ||
94 | send -- "/usr/lib/firejail/fseccomp default drop seccomp-test-file chmod,chown\r" | ||
95 | after 100 | ||
96 | send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" | ||
97 | expect { | ||
98 | timeout {puts "TESTING ERROR 8.1\n";exit} | ||
99 | "BLACKLIST 165 mount" | ||
100 | } | ||
101 | expect { | ||
102 | timeout {puts "TESTING ERROR 8.2\n";exit} | ||
103 | "BLACKLIST 166 umount2" | ||
104 | } | ||
105 | expect { | ||
106 | timeout {puts "TESTING ERROR 8.3\n";exit} | ||
107 | "BLACKLIST 90 chmod" | ||
108 | } | ||
109 | expect { | ||
110 | timeout {puts "TESTING ERROR 8.4\n";exit} | ||
111 | "BLACKLIST 92 chown" | ||
112 | } | ||
113 | expect { | ||
114 | timeout {puts "TESTING ERROR 8.5\n";exit} | ||
115 | "RETURN_ALLOW" | ||
116 | } | ||
117 | after 100 | ||
118 | send -- "/usr/lib/firejail/fseccomp keep seccomp-test-file chmod,chown\r" | ||
119 | after 100 | ||
120 | send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" | ||
121 | expect { | ||
122 | timeout {puts "TESTING ERROR 9.1\n";exit} | ||
123 | "WHITELIST 90 chmod" | ||
124 | } | ||
125 | expect { | ||
126 | timeout {puts "TESTING ERROR 9.2\n";exit} | ||
127 | "WHITELIST 92 chown" | ||
128 | } | ||
129 | expect { | ||
130 | timeout {puts "TESTING ERROR 9.3\n";exit} | ||
131 | "KILL_PROCESS" | ||
132 | } | ||
133 | |||
134 | |||
135 | |||
136 | after 100 | ||
137 | puts "\nall done\n" | ||
138 | |||