aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/firejail/errno.c214
-rw-r--r--src/firejail/firejail.h9
-rw-r--r--src/firejail/main.c43
-rw-r--r--src/firejail/sandbox.c2
-rw-r--r--src/firejail/seccomp.c144
-rw-r--r--src/firejail/syscall.c6
-rw-r--r--src/man/firejail.txt9
-rw-r--r--src/tools/extract_errnos.sh4
8 files changed, 393 insertions, 38 deletions
diff --git a/src/firejail/errno.c b/src/firejail/errno.c
new file mode 100644
index 000000000..c6c5f8f6a
--- /dev/null
+++ b/src/firejail/errno.c
@@ -0,0 +1,214 @@
1/*
2 * Copyright (C) 2015 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 <errno.h>
24#include <attr/xattr.h>
25
26typedef struct {
27 char *name;
28 int nr;
29} ErrnoEntry;
30
31static ErrnoEntry errnolist[] = {
32//
33// code generated using tools/extract-errnos
34//
35 "EPERM", EPERM,
36 "ENOENT", ENOENT,
37 "ESRCH", ESRCH,
38 "EINTR", EINTR,
39 "EIO", EIO,
40 "ENXIO", ENXIO,
41 "E2BIG", E2BIG,
42 "ENOEXEC", ENOEXEC,
43 "EBADF", EBADF,
44 "ECHILD", ECHILD,
45 "EAGAIN", EAGAIN,
46 "ENOMEM", ENOMEM,
47 "EACCES", EACCES,
48 "EFAULT", EFAULT,
49 "ENOTBLK", ENOTBLK,
50 "EBUSY", EBUSY,
51 "EEXIST", EEXIST,
52 "EXDEV", EXDEV,
53 "ENODEV", ENODEV,
54 "ENOTDIR", ENOTDIR,
55 "EISDIR", EISDIR,
56 "EINVAL", EINVAL,
57 "ENFILE", ENFILE,
58 "EMFILE", EMFILE,
59 "ENOTTY", ENOTTY,
60 "ETXTBSY", ETXTBSY,
61 "EFBIG", EFBIG,
62 "ENOSPC", ENOSPC,
63 "ESPIPE", ESPIPE,
64 "EROFS", EROFS,
65 "EMLINK", EMLINK,
66 "EPIPE", EPIPE,
67 "EDOM", EDOM,
68 "ERANGE", ERANGE,
69 "EDEADLK", EDEADLK,
70 "ENAMETOOLONG", ENAMETOOLONG,
71 "ENOLCK", ENOLCK,
72 "ENOSYS", ENOSYS,
73 "ENOTEMPTY", ENOTEMPTY,
74 "ELOOP", ELOOP,
75 "EWOULDBLOCK", EWOULDBLOCK,
76 "ENOMSG", ENOMSG,
77 "EIDRM", EIDRM,
78 "ECHRNG", ECHRNG,
79 "EL2NSYNC", EL2NSYNC,
80 "EL3HLT", EL3HLT,
81 "EL3RST", EL3RST,
82 "ELNRNG", ELNRNG,
83 "EUNATCH", EUNATCH,
84 "ENOCSI", ENOCSI,
85 "EL2HLT", EL2HLT,
86 "EBADE", EBADE,
87 "EBADR", EBADR,
88 "EXFULL", EXFULL,
89 "ENOANO", ENOANO,
90 "EBADRQC", EBADRQC,
91 "EBADSLT", EBADSLT,
92 "EDEADLOCK", EDEADLOCK,
93 "EBFONT", EBFONT,
94 "ENOSTR", ENOSTR,
95 "ENODATA", ENODATA,
96 "ETIME", ETIME,
97 "ENOSR", ENOSR,
98 "ENONET", ENONET,
99 "ENOPKG", ENOPKG,
100 "EREMOTE", EREMOTE,
101 "ENOLINK", ENOLINK,
102 "EADV", EADV,
103 "ESRMNT", ESRMNT,
104 "ECOMM", ECOMM,
105 "EPROTO", EPROTO,
106 "EMULTIHOP", EMULTIHOP,
107 "EDOTDOT", EDOTDOT,
108 "EBADMSG", EBADMSG,
109 "EOVERFLOW", EOVERFLOW,
110 "ENOTUNIQ", ENOTUNIQ,
111 "EBADFD", EBADFD,
112 "EREMCHG", EREMCHG,
113 "ELIBACC", ELIBACC,
114 "ELIBBAD", ELIBBAD,
115 "ELIBSCN", ELIBSCN,
116 "ELIBMAX", ELIBMAX,
117 "ELIBEXEC", ELIBEXEC,
118 "EILSEQ", EILSEQ,
119 "ERESTART", ERESTART,
120 "ESTRPIPE", ESTRPIPE,
121 "EUSERS", EUSERS,
122 "ENOTSOCK", ENOTSOCK,
123 "EDESTADDRREQ", EDESTADDRREQ,
124 "EMSGSIZE", EMSGSIZE,
125 "EPROTOTYPE", EPROTOTYPE,
126 "ENOPROTOOPT", ENOPROTOOPT,
127 "EPROTONOSUPPORT", EPROTONOSUPPORT,
128 "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT,
129 "EOPNOTSUPP", EOPNOTSUPP,
130 "EPFNOSUPPORT", EPFNOSUPPORT,
131 "EAFNOSUPPORT", EAFNOSUPPORT,
132 "EADDRINUSE", EADDRINUSE,
133 "EADDRNOTAVAIL", EADDRNOTAVAIL,
134 "ENETDOWN", ENETDOWN,
135 "ENETUNREACH", ENETUNREACH,
136 "ENETRESET", ENETRESET,
137 "ECONNABORTED", ECONNABORTED,
138 "ECONNRESET", ECONNRESET,
139 "ENOBUFS", ENOBUFS,
140 "EISCONN", EISCONN,
141 "ENOTCONN", ENOTCONN,
142 "ESHUTDOWN", ESHUTDOWN,
143 "ETOOMANYREFS", ETOOMANYREFS,
144 "ETIMEDOUT", ETIMEDOUT,
145 "ECONNREFUSED", ECONNREFUSED,
146 "EHOSTDOWN", EHOSTDOWN,
147 "EHOSTUNREACH", EHOSTUNREACH,
148 "EALREADY", EALREADY,
149 "EINPROGRESS", EINPROGRESS,
150 "ESTALE", ESTALE,
151 "EUCLEAN", EUCLEAN,
152 "ENOTNAM", ENOTNAM,
153 "ENAVAIL", ENAVAIL,
154 "EISNAM", EISNAM,
155 "EREMOTEIO", EREMOTEIO,
156 "EDQUOT", EDQUOT,
157 "ENOMEDIUM", ENOMEDIUM,
158 "EMEDIUMTYPE", EMEDIUMTYPE,
159 "ECANCELED", ECANCELED,
160 "ENOKEY", ENOKEY,
161 "EKEYEXPIRED", EKEYEXPIRED,
162 "EKEYREVOKED", EKEYREVOKED,
163 "EKEYREJECTED", EKEYREJECTED,
164 "EOWNERDEAD", EOWNERDEAD,
165 "ENOTRECOVERABLE", ENOTRECOVERABLE,
166 "ERFKILL", ERFKILL,
167 "EHWPOISON", EHWPOISON,
168 "ENOTSUP", ENOTSUP,
169 "ENOATTR", ENOATTR,
170};
171
172int errno_highest_nr(void) {
173 int i, max = 0;
174 int elems = sizeof(errnolist) / sizeof(errnolist[0]);
175 for (i = 0; i < elems; i++) {
176 if (errnolist[i].nr > max)
177 max = errnolist[i].nr;
178 }
179
180 return max;
181}
182
183int errno_find_name(const char *name) {
184 int i;
185 int elems = sizeof(errnolist) / sizeof(errnolist[0]);
186 for (i = 0; i < elems; i++) {
187 if (strcasecmp(name, errnolist[i].name) == 0)
188 return errnolist[i].nr;
189 }
190
191 return -1;
192}
193
194char *errno_find_nr(int nr) {
195 int i;
196 int elems = sizeof(errnolist) / sizeof(errnolist[0]);
197 for (i = 0; i < elems; i++) {
198 if (nr == errnolist[i].nr)
199 return errnolist[i].name;
200 }
201
202 return "unknown";
203}
204
205void errno_print(void) {
206 int i;
207 int elems = sizeof(errnolist) / sizeof(errnolist[0]);
208 for (i = 0; i < elems; i++) {
209 printf("%d\t- %s\n", errnolist[i].nr, errnolist[i].name);
210 }
211 printf("\n");
212}
213
214#endif // HAVE_SECCOMP
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index cef4b673c..589fdb42a 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -147,6 +147,7 @@ extern int arg_seccomp; // enable default seccomp filter
147extern char *arg_seccomp_list;// optional seccomp list on top of default filter 147extern char *arg_seccomp_list;// optional seccomp list on top of default filter
148extern char *arg_seccomp_list_drop; // seccomp drop list 148extern char *arg_seccomp_list_drop; // seccomp drop list
149extern char *arg_seccomp_list_keep; // seccomp keep list 149extern char *arg_seccomp_list_keep; // seccomp keep list
150extern char **arg_seccomp_list_errno; // seccomp errno[nr] lists
150 151
151extern int arg_caps_default_filter; // enable default capabilities filter 152extern int arg_caps_default_filter; // enable default capabilities filter
152extern int arg_caps_drop; // drop list 153extern int arg_caps_drop; // drop list
@@ -335,7 +336,7 @@ void caps_print_filter_name(const char *name);
335// syscall.c 336// syscall.c
336const char *syscall_find_nr(int nr); 337const char *syscall_find_nr(int nr);
337// return -1 if error, 0 if no error 338// return -1 if error, 0 if no error
338int syscall_check_list(const char *slist, void (*callback)(int)); 339int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg);
339// print all available syscalls 340// print all available syscalls
340void syscall_print(void); 341void syscall_print(void);
341 342
@@ -392,5 +393,11 @@ void env_apply(void);
392// fs_whitelist.c 393// fs_whitelist.c
393void fs_whitelist(void); 394void fs_whitelist(void);
394 395
396// errno.c
397int errno_highest_errno(void);
398int errno_find_name(const char *name);
399char *errno_find_nr(int nr);
400void errno_print(void);
401
395#endif 402#endif
396 403
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 9d94630ef..ea04ea73f 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -61,6 +61,7 @@ int arg_seccomp = 0; // enable default seccomp filter
61char *arg_seccomp_list = NULL; // optional seccomp list on top of default filter 61char *arg_seccomp_list = NULL; // optional seccomp list on top of default filter
62char *arg_seccomp_list_drop = NULL; // seccomp drop list 62char *arg_seccomp_list_drop = NULL; // seccomp drop list
63char *arg_seccomp_list_keep = NULL; // seccomp keep list 63char *arg_seccomp_list_keep = NULL; // seccomp keep list
64char **arg_seccomp_list_errno = NULL; // seccomp errno[nr] lists
64 65
65int arg_caps_default_filter = 0; // enable default capabilities filter 66int arg_caps_default_filter = 0; // enable default capabilities filter
66int arg_caps_drop = 0; // drop list 67int arg_caps_drop = 0; // drop list
@@ -302,6 +303,10 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
302 syscall_print(); 303 syscall_print();
303 exit(0); 304 exit(0);
304 } 305 }
306 else if (strcmp(argv[i], "--debug-errnos") == 0) {
307 errno_print();
308 exit(0);
309 }
305 else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) { 310 else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) {
306 // join sandbox by pid or by name 311 // join sandbox by pid or by name
307 pid_t pid; 312 pid_t pid;
@@ -387,6 +392,7 @@ int main(int argc, char **argv) {
387 int arg_cgroup = 0; 392 int arg_cgroup = 0;
388 int custom_profile = 0; // custom profile loaded 393 int custom_profile = 0; // custom profile loaded
389 int arg_noprofile = 0; // use generic.profile if none other found/specified 394 int arg_noprofile = 0; // use generic.profile if none other found/specified
395 int highest_errno = errno_highest_nr();
390 396
391 // check if we already have a sandbox running 397 // check if we already have a sandbox running
392 int rv = check_kernel_procs(); 398 int rv = check_kernel_procs();
@@ -478,6 +484,34 @@ int main(int argc, char **argv) {
478 if (!arg_seccomp_list_keep) 484 if (!arg_seccomp_list_keep)
479 errExit("strdup"); 485 errExit("strdup");
480 } 486 }
487 else if (strncmp(argv[i], "--seccomp.e", 11) == 0 && strchr(argv[i], '=')) {
488 if (arg_seccomp && !arg_seccomp_list_errno) {
489 fprintf(stderr, "Error: seccomp already enabled\n");
490 exit(1);
491 }
492 char *eq = strchr(argv[i], '=');
493 char *errnoname = strndup(argv[i] + 10, eq - (argv[i] + 10));
494 int nr = errno_find_name(errnoname);
495 if (nr == -1) {
496 fprintf(stderr, "Error: unknown errno %s\n", errnoname);
497 free(errnoname);
498 exit(1);
499 }
500
501 if (!arg_seccomp_list_errno)
502 arg_seccomp_list_errno = calloc(highest_errno+1, sizeof(arg_seccomp_list_errno[0]));
503
504 if (arg_seccomp_list_errno[nr]) {
505 fprintf(stderr, "Error: errno %s already configured\n", errnoname);
506 free(errnoname);
507 exit(1);
508 }
509 arg_seccomp = 1;
510 arg_seccomp_list_errno[nr] = strdup(eq+1);
511 if (!arg_seccomp_list_errno[nr])
512 errExit("strdup");
513 free(errnoname);
514 }
481#endif 515#endif
482 else if (strcmp(argv[i], "--caps") == 0) 516 else if (strcmp(argv[i], "--caps") == 0)
483 arg_caps_default_filter = 1; 517 arg_caps_default_filter = 1;
@@ -1288,6 +1322,15 @@ int main(int argc, char **argv) {
1288 1322
1289 // wait for the child to finish 1323 // wait for the child to finish
1290 waitpid(child, NULL, 0); 1324 waitpid(child, NULL, 0);
1325
1326 // free globals
1327 if (arg_seccomp_list_errno) {
1328 for (i = 0; i < highest_errno; i++)
1329 free(arg_seccomp_list_errno[i]);
1330 free(arg_seccomp_list_errno);
1331 }
1332
1291 myexit(0); 1333 myexit(0);
1334
1292 return 0; 1335 return 0;
1293} 1336}
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index c1a6d92ec..ddfcc8404 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -410,6 +410,8 @@ int sandbox(void* sandbox_arg) {
410 if (arg_seccomp == 1) { 410 if (arg_seccomp == 1) {
411 if (arg_seccomp_list_keep) 411 if (arg_seccomp_list_keep)
412 seccomp_filter_keep(); // this will also save the fmyilter to MNT_DIR/seccomp file 412 seccomp_filter_keep(); // this will also save the fmyilter to MNT_DIR/seccomp file
413 else if (arg_seccomp_list_errno)
414 seccomp_filter_errno(); // this will also save the filter to MNT_DIR/seccomp file
413 else 415 else
414 seccomp_filter_drop(); // this will also save the filter to MNT_DIR/seccomp file 416 seccomp_filter_drop(); // this will also save the filter to MNT_DIR/seccomp file
415 } 417 }
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index 47988dbf4..4f6b7b326 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -109,6 +109,10 @@ struct seccomp_data {
109 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ 109 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \
110 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 110 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
111 111
112#define ERRNO(syscall_nr, nr) \
113 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \
114 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr)
115
112#define RETURN_ALLOW \ 116#define RETURN_ALLOW \
113 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 117 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
114 118
@@ -157,6 +161,11 @@ void filter_debug(void) {
157 printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); 161 printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr));
158 i += 2; 162 i += 2;
159 } 163 }
164 else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) {
165 int err = *(ptr + 13) << 8 | *(ptr + 12);
166 printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err));
167 i += 2;
168 }
160 else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { 169 else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) {
161 printf(" KILL_PROCESS\n"); 170 printf(" KILL_PROCESS\n");
162 i++; 171 i++;
@@ -216,7 +225,7 @@ static void filter_realloc(void) {
216 sfilter_alloc_size += SECSIZE; 225 sfilter_alloc_size += SECSIZE;
217} 226}
218 227
219static void filter_add_whitelist(int syscall) { 228static void filter_add_whitelist(int syscall, int arg) {
220 assert(sfilter); 229 assert(sfilter);
221 assert(sfilter_alloc_size); 230 assert(sfilter_alloc_size);
222 assert(sfilter_index); 231 assert(sfilter_index);
@@ -242,7 +251,7 @@ static void filter_add_whitelist(int syscall) {
242 sfilter_index += sizeof(filter) / sizeof(struct sock_filter); 251 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
243} 252}
244 253
245static void filter_add_blacklist(int syscall) { 254static void filter_add_blacklist(int syscall, int arg) {
246 assert(sfilter); 255 assert(sfilter);
247 assert(sfilter_alloc_size); 256 assert(sfilter_alloc_size);
248 assert(sfilter_index); 257 assert(sfilter_index);
@@ -268,6 +277,32 @@ static void filter_add_blacklist(int syscall) {
268 sfilter_index += sizeof(filter) / sizeof(struct sock_filter); 277 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
269} 278}
270 279
280static void filter_add_errno(int syscall, int arg) {
281 assert(sfilter);
282 assert(sfilter_alloc_size);
283 assert(sfilter_index);
284// if (arg_debug)
285// printf("Errno syscall %d %d %s\n", syscall, arg, syscall_find_nr(syscall));
286
287 if ((sfilter_index + 2) > sfilter_alloc_size)
288 filter_realloc();
289
290 struct sock_filter filter[] = {
291 ERRNO(syscall, arg)
292 };
293#if 0
294{
295 int i;
296 unsigned char *ptr = (unsigned char *) &filter[0];
297 for (i = 0; i < sizeof(filter); i++, ptr++)
298 printf("%x, ", (*ptr) & 0xff);
299 printf("\n");
300}
301#endif
302 memcpy(&sfilter[sfilter_index], filter, sizeof(filter));
303 sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
304}
305
271static void filter_end_blacklist(void) { 306static void filter_end_blacklist(void) {
272 assert(sfilter); 307 assert(sfilter);
273 assert(sfilter_alloc_size); 308 assert(sfilter_alloc_size);
@@ -405,96 +440,96 @@ int seccomp_filter_drop(void) {
405 // default seccomp 440 // default seccomp
406 if (arg_seccomp_list_drop == NULL) { 441 if (arg_seccomp_list_drop == NULL) {
407#ifdef SYS_mount 442#ifdef SYS_mount
408 filter_add_blacklist(SYS_mount); 443 filter_add_blacklist(SYS_mount, 0);
409#endif 444#endif
410#ifdef SYS_umount2 445#ifdef SYS_umount2
411 filter_add_blacklist(SYS_umount2); 446 filter_add_blacklist(SYS_umount2, 0);
412#endif 447#endif
413#ifdef SYS_ptrace 448#ifdef SYS_ptrace
414 filter_add_blacklist(SYS_ptrace); 449 filter_add_blacklist(SYS_ptrace, 0);
415#endif 450#endif
416#ifdef SYS_kexec_load 451#ifdef SYS_kexec_load
417 filter_add_blacklist(SYS_kexec_load); 452 filter_add_blacklist(SYS_kexec_load, 0);
418#endif 453#endif
419#ifdef SYS_open_by_handle_at 454#ifdef SYS_open_by_handle_at
420 filter_add_blacklist(SYS_open_by_handle_at); 455 filter_add_blacklist(SYS_open_by_handle_at, 0);
421#endif 456#endif
422#ifdef SYS_init_module 457#ifdef SYS_init_module
423 filter_add_blacklist(SYS_init_module); 458 filter_add_blacklist(SYS_init_module, 0);
424#endif 459#endif
425#ifdef SYS_finit_module // introduced in 2013 460#ifdef SYS_finit_module // introduced in 2013
426 filter_add_blacklist(SYS_finit_module); 461 filter_add_blacklist(SYS_finit_module, 0);
427#endif 462#endif
428#ifdef SYS_delete_module 463#ifdef SYS_delete_module
429 filter_add_blacklist(SYS_delete_module); 464 filter_add_blacklist(SYS_delete_module, 0);
430#endif 465#endif
431#ifdef SYS_iopl 466#ifdef SYS_iopl
432 filter_add_blacklist(SYS_iopl); 467 filter_add_blacklist(SYS_iopl, 0);
433#endif 468#endif
434#ifdef SYS_ioperm 469#ifdef SYS_ioperm
435 filter_add_blacklist(SYS_ioperm); 470 filter_add_blacklist(SYS_ioperm, 0);
436#endif 471#endif
437#ifdef SYS_ni_syscall // new io permisions call on arm devices 472#ifdef SYS_ni_syscall // new io permisions call on arm devices
438 filter_add_blacklist(SYS_ni_syscall); 473 filter_add_blacklist(SYS_ni_syscall, 0);
439#endif 474#endif
440#ifdef SYS_swapon 475#ifdef SYS_swapon
441 filter_add_blacklist(SYS_swapon); 476 filter_add_blacklist(SYS_swapon, 0);
442#endif 477#endif
443#ifdef SYS_swapoff 478#ifdef SYS_swapoff
444 filter_add_blacklist(SYS_swapoff); 479 filter_add_blacklist(SYS_swapoff, 0);
445#endif 480#endif
446#ifdef SYS_syslog 481#ifdef SYS_syslog
447 filter_add_blacklist(SYS_syslog); 482 filter_add_blacklist(SYS_syslog, 0);
448#endif 483#endif
449#ifdef SYS_process_vm_readv 484#ifdef SYS_process_vm_readv
450 filter_add_blacklist(SYS_process_vm_readv); 485 filter_add_blacklist(SYS_process_vm_readv, 0);
451#endif 486#endif
452#ifdef SYS_process_vm_writev 487#ifdef SYS_process_vm_writev
453 filter_add_blacklist(SYS_process_vm_writev); 488 filter_add_blacklist(SYS_process_vm_writev, 0);
454#endif 489#endif
455 490
456// mknod removed in 0.9.29 491// mknod removed in 0.9.29
457//#ifdef SYS_mknod 492//#ifdef SYS_mknod
458// filter_add_blacklist(SYS_mknod); 493// filter_add_blacklist(SYS_mknod, 0);
459//#endif 494//#endif
460 495
461 // new syscalls in 0.9,23 496 // new syscalls in 0.9,23
462#ifdef SYS_sysfs 497#ifdef SYS_sysfs
463 filter_add_blacklist(SYS_sysfs); 498 filter_add_blacklist(SYS_sysfs, 0);
464#endif 499#endif
465#ifdef SYS__sysctl 500#ifdef SYS__sysctl
466 filter_add_blacklist(SYS__sysctl); 501 filter_add_blacklist(SYS__sysctl, 0);
467#endif 502#endif
468#ifdef SYS_adjtimex 503#ifdef SYS_adjtimex
469 filter_add_blacklist(SYS_adjtimex); 504 filter_add_blacklist(SYS_adjtimex, 0);
470#endif 505#endif
471#ifdef SYS_clock_adjtime 506#ifdef SYS_clock_adjtime
472 filter_add_blacklist(SYS_clock_adjtime); 507 filter_add_blacklist(SYS_clock_adjtime, 0);
473#endif 508#endif
474#ifdef SYS_lookup_dcookie 509#ifdef SYS_lookup_dcookie
475 filter_add_blacklist(SYS_lookup_dcookie); 510 filter_add_blacklist(SYS_lookup_dcookie, 0);
476#endif 511#endif
477#ifdef SYS_perf_event_open 512#ifdef SYS_perf_event_open
478 filter_add_blacklist(SYS_perf_event_open); 513 filter_add_blacklist(SYS_perf_event_open, 0);
479#endif 514#endif
480#ifdef SYS_fanotify_init 515#ifdef SYS_fanotify_init
481 filter_add_blacklist(SYS_fanotify_init); 516 filter_add_blacklist(SYS_fanotify_init, 0);
482#endif 517#endif
483#ifdef SYS_kcmp 518#ifdef SYS_kcmp
484 filter_add_blacklist(SYS_kcmp); 519 filter_add_blacklist(SYS_kcmp, 0);
485#endif 520#endif
486 } 521 }
487 522
488 // default seccomp filter with additional drop list 523 // default seccomp filter with additional drop list
489 if (arg_seccomp_list && arg_seccomp_list_drop == NULL) { 524 if (arg_seccomp_list && arg_seccomp_list_drop == NULL) {
490 if (syscall_check_list(arg_seccomp_list, filter_add_blacklist)) { 525 if (syscall_check_list(arg_seccomp_list, filter_add_blacklist, 0)) {
491 fprintf(stderr, "Error: cannot load seccomp filter\n"); 526 fprintf(stderr, "Error: cannot load seccomp filter\n");
492 exit(1); 527 exit(1);
493 } 528 }
494 } 529 }
495 // drop list 530 // drop list
496 else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) { 531 else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) {
497 if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist)) { 532 if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist, 0)) {
498 fprintf(stderr, "Error: cannot load seccomp filter\n"); 533 fprintf(stderr, "Error: cannot load seccomp filter\n");
499 exit(1); 534 exit(1);
500 } 535 }
@@ -531,14 +566,14 @@ int seccomp_filter_keep(void) {
531 filter_init(); 566 filter_init();
532 567
533 // these 4 syscalls are used by firejail after the seccomp filter is initialized 568 // these 4 syscalls are used by firejail after the seccomp filter is initialized
534 filter_add_whitelist(SYS_setuid); 569 filter_add_whitelist(SYS_setuid, 0);
535 filter_add_whitelist(SYS_setgid); 570 filter_add_whitelist(SYS_setgid, 0);
536 filter_add_whitelist(SYS_setgroups); 571 filter_add_whitelist(SYS_setgroups, 0);
537 filter_add_whitelist(SYS_dup); 572 filter_add_whitelist(SYS_dup, 0);
538 573
539 // apply keep list 574 // apply keep list
540 if (arg_seccomp_list_keep) { 575 if (arg_seccomp_list_keep) {
541 if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist)) { 576 if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist, 0)) {
542 fprintf(stderr, "Error: cannot load seccomp filter\n"); 577 fprintf(stderr, "Error: cannot load seccomp filter\n");
543 exit(1); 578 exit(1);
544 } 579 }
@@ -569,6 +604,47 @@ int seccomp_filter_keep(void) {
569 return 0; 604 return 0;
570} 605}
571 606
607// errno filter for seccomp option
608int seccomp_filter_errno(void) {
609 int i;
610 int higest_errno = errno_highest_nr();
611 filter_init();
612
613 // apply errno list
614
615 for (i = 0; i < higest_errno; i++) {
616 if (arg_seccomp_list_errno[i]) {
617 if (syscall_check_list(arg_seccomp_list_errno[i], filter_add_errno, i)) {
618 fprintf(stderr, "Error: cannot load seccomp filter\n");
619 exit(1);
620 }
621 }
622 }
623
624 filter_end_blacklist();
625 if (arg_debug)
626 filter_debug();
627
628 // save seccomp filter in /tmp/firejail/mnt/seccomp
629 // in order to use it in --join operations
630 write_seccomp_file();
631
632 struct sock_fprog prog = {
633 .len = sfilter_index,
634 .filter = sfilter,
635 };
636
637 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
638 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
639 return 1;
640 }
641 else if (arg_debug) {
642 printf("seccomp enabled\n");
643 }
644
645 return 0;
646}
647
572 648
573 649
574void seccomp_set(void) { 650void seccomp_set(void) {
diff --git a/src/firejail/syscall.c b/src/firejail/syscall.c
index a74a00662..2ae3da100 100644
--- a/src/firejail/syscall.c
+++ b/src/firejail/syscall.c
@@ -4889,7 +4889,7 @@ static int syscall_find_name(const char *name) {
4889} 4889}
4890 4890
4891// return 1 if error, 0 if OK 4891// return 1 if error, 0 if OK
4892int syscall_check_list(const char *slist, void (*callback)(int)) { 4892int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg) {
4893 // don't allow empty lists 4893 // don't allow empty lists
4894 if (slist == NULL || *slist == '\0') { 4894 if (slist == NULL || *slist == '\0') {
4895 fprintf(stderr, "Error: empty syscall lists are not allowed\n"); 4895 fprintf(stderr, "Error: empty syscall lists are not allowed\n");
@@ -4912,7 +4912,7 @@ int syscall_check_list(const char *slist, void (*callback)(int)) {
4912 if (nr == -1) 4912 if (nr == -1)
4913 fprintf(stderr, "Warning: syscall %s not found\n", start); 4913 fprintf(stderr, "Warning: syscall %s not found\n", start);
4914 else if (callback != NULL) 4914 else if (callback != NULL)
4915 callback(nr); 4915 callback(nr, arg);
4916 4916
4917 start = ptr + 1; 4917 start = ptr + 1;
4918 } 4918 }
@@ -4923,7 +4923,7 @@ int syscall_check_list(const char *slist, void (*callback)(int)) {
4923 if (nr == -1) 4923 if (nr == -1)
4924 fprintf(stderr, "Warning: syscall %s not found\n", start); 4924 fprintf(stderr, "Warning: syscall %s not found\n", start);
4925 else if (callback != NULL) 4925 else if (callback != NULL)
4926 callback(nr); 4926 callback(nr, arg);
4927 } 4927 }
4928 4928
4929 free(str); 4929 free(str);
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 3f4fba00e..3f22a1d2a 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -845,6 +845,15 @@ Example:
845.br 845.br
846$ firejail \-\-shell=none \-\-seccomp.keep=poll,select,[...] transmission-gtk 846$ firejail \-\-shell=none \-\-seccomp.keep=poll,select,[...] transmission-gtk
847.TP 847.TP
848\fB\-\-seccomp.<errno>=syscall,syscall,syscall
849Enable seccomp filter, and return errno for the syscalls specified by the command.
850.br
851
852.br
853Example:
854.br
855$ firejail \-\-shell=none \-\-seccomp.einval=kill kill 1
856.TP
848\fB\-\-seccomp.print=name 857\fB\-\-seccomp.print=name
849Print the seccomp filter for the sandbox started using \-\-name option. 858Print the seccomp filter for the sandbox started using \-\-name option.
850.br 859.br
diff --git a/src/tools/extract_errnos.sh b/src/tools/extract_errnos.sh
new file mode 100644
index 000000000..43b225828
--- /dev/null
+++ b/src/tools/extract_errnos.sh
@@ -0,0 +1,4 @@
1echo -e "#include <errno.h>\n#include <attr/xattr.h>" | \
2 cpp -dD | \
3 grep "^#define E" | \
4 sed -e '{s/#define \(.*\) .*/\t"\1", \1,/g}'