aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-11-02 07:49:01 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2016-11-02 07:49:01 -0400
commit72b93c5761b5e42c5742e192f46bac1696c36f4c (patch)
tree3951e01a771ea3e8f11b8364991bb47f752f011f
parentfixed /run/firejail/mnt problem introduced recently (diff)
downloadfirejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.tar.gz
firejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.tar.zst
firejail-72b93c5761b5e42c5742e192f46bac1696c36f4c.zip
major cleanup
-rw-r--r--src/firejail/errno.c2
-rw-r--r--src/firejail/firejail.h24
-rw-r--r--src/firejail/join.c6
-rw-r--r--src/firejail/preproc.c31
-rw-r--r--src/firejail/protocol.c46
-rw-r--r--src/firejail/sandbox.c33
-rw-r--r--src/firejail/seccomp.c873
-rw-r--r--src/firejail/syscall.c105
-rw-r--r--src/firejail/util.c4
-rw-r--r--src/fnet/Makefile.in4
-rw-r--r--src/fseccomp/Makefile.in4
-rw-r--r--src/fseccomp/errno.c43
-rw-r--r--src/fseccomp/fseccomp.h50
-rw-r--r--src/fseccomp/main.c49
-rw-r--r--src/fseccomp/seccomp.c292
-rw-r--r--src/fseccomp/seccomp_file.c108
-rw-r--r--src/fseccomp/seccomp_print.c116
-rw-r--r--src/fseccomp/seccomp_secondary.c183
-rw-r--r--src/fseccomp/syscall.c84
-rwxr-xr-xtest/filters/filters.sh15
-rwxr-xr-xtest/filters/fseccomp.exp138
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
499int seccomp_load(const char *fname);
500void seccomp_filter_32(void);
501void seccomp_filter_64(void);
494int seccomp_filter_drop(int enforce_seccomp); 502int seccomp_filter_drop(int enforce_seccomp);
495int seccomp_filter_keep(void); 503int seccomp_filter_keep(void);
496void seccomp_set(void); 504int seccomp_filter_errno(void);
497void seccomp_print_filter_name(const char *name); 505void seccomp_print_filter_name(const char *name);
498void seccomp_print_filter(pid_t pid); 506void seccomp_print_filter(pid_t pid);
499int seccomp_filter_errno(void);
500 507
501// caps.c 508// caps.c
502int caps_default_filter(void); 509int caps_default_filter(void);
@@ -591,13 +598,10 @@ void fs_check_bin_list(void);
591void fs_private_bin_list(void); 598void fs_private_bin_list(void);
592 599
593// protocol.c 600// protocol.c
594void protocol_list();
595void protocol_print_filter_name(const char *name);
596void protocol_print_filter(pid_t pid);
597void protocol_store(const char *prlist);
598void protocol_filter(const char *fname);
599void protocol_filter_save(void); 601void protocol_filter_save(void);
600void protocol_filter_load(const char *fname); 602void protocol_filter_load(const char *fname);
603void protocol_print_filter_name(const char *name);
604void protocol_print_filter(pid_t pid);
601 605
602// restrict_users.c 606// restrict_users.c
603void restrict_users(void); 607void 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
68void preproc_mount_mnt_dir(void) { 68void 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
26void 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
71void protocol_filter_save(void) { 25void 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 25int seccomp_load(const char *fname) {
26static struct sock_filter *sfilter = NULL; 26 assert(fname);
27static int sfilter_alloc_size = 0;
28static int sfilter_index = 0;
29
30// debug filter
31void 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
88static 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
124static 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
143static 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
170static 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
197static 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
223static 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
249static 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
277static 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
297static 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
338void seccomp_filter_32(void) { 71void 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
411void seccomp_filter_64(void) { 88void 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
486int seccomp_filter_drop(int enforce_seccomp) { 106int 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
735int seccomp_filter_keep(void) { 199int 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
778int seccomp_filter_errno(void) { 220int 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, 246printf("*** --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
820void 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
839void seccomp_print_filter_name(const char *name) { 251void 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
25typedef struct {
26 char *name;
27 int nr;
28} SyscallEntry;
29
30static 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
40const 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
52static 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
64int 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)
30CFLAGS += -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 30CFLAGS += -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
31LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread 31LDFLAGS += -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
36fnet: $(OBJS) ../lib/libnetlink.o ../lib/common.o 36fnet: $(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
39clean:; rm -f *.o fnet 39clean:; 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)
30CFLAGS += -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 30CFLAGS += -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
31LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread 31LDFLAGS += -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
36fseccomp: $(OBJS) ../lib/libnetlink.o ../lib/common.o 36fseccomp: $(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
39clean:; rm -f *.o fseccomp 39clean:; 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
173int 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
184char *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
154void errno_print(void) { 197void 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
10void syscall_print(void); 29void syscall_print(void);
30int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg);
31int syscall_find_name(const char *name);
32char *syscall_find_nr(int nr);
11 33
12// errno.c 34// errno.c
13void errno_print(void); 35void errno_print(void);
36int errno_find_name(const char *name);
37char *errno_find_nr(int nr);
14 38
15// protocol.c 39// protocol.c
16void protocol_print(void); 40void protocol_print(void);
17void protocol_build_filter(const char *prlist, const char *fname); 41void protocol_build_filter(const char *prlist, const char *fname);
42
43// seccomp_secondary.c
44void seccomp_secondary_64(const char *fname);
45void seccomp_secondary_32(const char *fname);
46
47// seccomp_file.c
48void filter_init(int fd);
49void filter_add_whitelist(int fd, int syscall, int arg);
50void filter_add_blacklist(int fd, int syscall, int arg);
51void filter_add_errno(int fd, int syscall, int arg);
52void filter_end_blacklist(int fd);
53void filter_end_whitelist(int fd);
54
55// seccomp.c
56// default list
57void seccomp_default(const char *fname, int allow_debuggers);
58// drop list
59void seccomp_drop(const char *fname, char *list, int allow_debuggers);
60// default+drop list
61void seccomp_default_drop(const char *fname, char *list, int allow_debuggers);
62// whitelisted filter
63void seccomp_keep(const char *fname, char *list);
64
65// seccomp_print
66void 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
3static void usage(void) { 22static 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
11int main(int argc, char **argv) { 40int 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
24static 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
198void 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
218void 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
242void 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
265void 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
24static 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
39void 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
70void 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
79void 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
88void 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
95void filter_end_blacklist(int fd) {
96 struct sock_filter filter[] = {
97 RETURN_ALLOW
98 };
99 write_to_file(fd, filter, sizeof(filter));
100}
101
102void 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
24static struct sock_filter *filter = NULL;
25static int filter_cnt = 0;
26
27static 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
61void 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
24void 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
105void 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
39int 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
50char *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
19void syscall_print(void) { 61void 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
71int 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)"
12echo "TESTING: capabilities (test/filters/caps.exp)" 12echo "TESTING: capabilities (test/filters/caps.exp)"
13./caps.exp 13./caps.exp
14 14
15rm -f seccomp-test-file
16if [ "$(uname -m)" = "x86_64" ]; then
17 echo "TESTING: fseccomp (test/filters/fseccomp.exp)"
18 ./fseccomp.exp
19else
20 echo "TESTING SKIP: fseccomp test implemented only for x86_64"
21fi
22rm -f seccomp-test-file
23
24
15if [ "$(uname -m)" = "x86_64" ]; then 25if [ "$(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
18else 28else
19 echo "TESTING SKIP: protocol, not running on x86_64" 29 echo "TESTING SKIP: protocol, running only on x86_64"
20fi 30fi
21 31
22echo "TESTING: seccomp bad empty (test/filters/seccomp-bad-empty.exp)" 32echo "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
50echo "TESTING: seccomp empty (test/filters/seccomp-empty.exp)" 60echo "TESTING: seccomp empty (test/filters/seccomp-empty.exp)"
51./seccomp-empty.exp 61./seccomp-empty.exp
52 62
53echo "TESTING: seccomp bad empty (test/filters/seccomp-bad-empty.exp)"
54./seccomp-bad-empty.exp
55
56if [ "$(uname -m)" = "x86_64" ]; then 63if [ "$(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
6set timeout 10
7spawn $env(SHELL)
8match_max 100000
9
10after 100
11send -- "/usr/lib/firejail/fseccomp debug-syscalls\r"
12expect {
13 timeout {puts "TESTING ERROR 1\n";exit}
14 "1 - write"
15}
16
17after 100
18send -- "/usr/lib/firejail/fseccomp debug-errnos\r"
19expect {
20 timeout {puts "TESTING ERROR 2\n";exit}
21 "1 - EPERM"
22}
23
24after 100
25send -- "/usr/lib/firejail/fseccomp debug-protocols\r"
26expect {
27 timeout {puts "TESTING ERROR 3\n";exit}
28 "unix, inet, inet6, netlink, packet,"
29}
30
31after 100
32send -- "/usr/lib/firejail/fseccomp protocol build unix,inet seccomp-test-file\r"
33after 100
34send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r"
35expect {
36 timeout {puts "TESTING ERROR 4.1\n";exit}
37 "WHITELIST 41 socket"
38}
39
40after 100
41send -- "/usr/lib/firejail/fseccomp secondary 64 seccomp-test-file\r"
42after 100
43send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r"
44expect {
45 timeout {puts "TESTING ERROR 5.1\n";exit}
46 "BLACKLIST 165 mount"
47}
48expect {
49 timeout {puts "TESTING ERROR 5.2\n";exit}
50 "BLACKLIST 166 umount2"
51}
52expect {
53 timeout {puts "TESTING ERROR 5.3\n";exit}
54 "RETURN_ALLOW"
55}
56
57after 100
58send -- "/usr/lib/firejail/fseccomp default seccomp-test-file\r"
59after 100
60send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r"
61expect {
62 timeout {puts "TESTING ERROR 6.1\n";exit}
63 "BLACKLIST 165 mount"
64}
65expect {
66 timeout {puts "TESTING ERROR 6.2\n";exit}
67 "BLACKLIST 166 umount2"
68}
69expect {
70 timeout {puts "TESTING ERROR 6.3\n";exit}
71 "RETURN_ALLOW"
72}
73
74after 100
75send -- "/usr/lib/firejail/fseccomp drop seccomp-test-file chmod,chown\r"
76after 100
77send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r"
78expect {
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}
84expect {
85 timeout {puts "TESTING ERROR 7.4\n";exit}
86 "BLACKLIST 92 chown"
87}
88expect {
89 timeout {puts "TESTING ERROR 7.5\n";exit}
90 "RETURN_ALLOW"
91}
92
93after 100
94send -- "/usr/lib/firejail/fseccomp default drop seccomp-test-file chmod,chown\r"
95after 100
96send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r"
97expect {
98 timeout {puts "TESTING ERROR 8.1\n";exit}
99 "BLACKLIST 165 mount"
100}
101expect {
102 timeout {puts "TESTING ERROR 8.2\n";exit}
103 "BLACKLIST 166 umount2"
104}
105expect {
106 timeout {puts "TESTING ERROR 8.3\n";exit}
107 "BLACKLIST 90 chmod"
108}
109expect {
110 timeout {puts "TESTING ERROR 8.4\n";exit}
111 "BLACKLIST 92 chown"
112}
113expect {
114 timeout {puts "TESTING ERROR 8.5\n";exit}
115 "RETURN_ALLOW"
116}
117after 100
118send -- "/usr/lib/firejail/fseccomp keep seccomp-test-file chmod,chown\r"
119after 100
120send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r"
121expect {
122 timeout {puts "TESTING ERROR 9.1\n";exit}
123 "WHITELIST 90 chmod"
124}
125expect {
126 timeout {puts "TESTING ERROR 9.2\n";exit}
127 "WHITELIST 92 chown"
128}
129expect {
130 timeout {puts "TESTING ERROR 9.3\n";exit}
131 "KILL_PROCESS"
132}
133
134
135
136after 100
137puts "\nall done\n"
138