diff options
author | Topi Miettinen <toiwoton@gmail.com> | 2019-08-25 18:37:05 +0300 |
---|---|---|
committer | Topi Miettinen <toiwoton@gmail.com> | 2019-08-25 18:37:05 +0300 |
commit | 39f9b1a2229f8624f92bdcf823ef755c15e28de2 (patch) | |
tree | c15cdcdd4abbccfdfbed58764de45827ff2e503c /src | |
parent | Merge pull request #2921 from rusty-snake/allow-common-devel.inc (diff) | |
download | firejail-39f9b1a2229f8624f92bdcf823ef755c15e28de2.tar.gz firejail-39f9b1a2229f8624f92bdcf823ef755c15e28de2.tar.zst firejail-39f9b1a2229f8624f92bdcf823ef755c15e28de2.zip |
Allow exceptions to seccomp lists
Prefix ! can be used to make exceptions to system call blacklists and
whitelists used by seccomp, seccomp.drop and seccomp.keep.
Closes #1366
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/seccomp.c | 4 | ||||
-rw-r--r-- | src/fseccomp/fseccomp.h | 2 | ||||
-rw-r--r-- | src/fseccomp/seccomp.c | 12 | ||||
-rw-r--r-- | src/fseccomp/seccomp_file.c | 48 | ||||
-rw-r--r-- | src/fseccomp/syscall.c | 10 | ||||
-rw-r--r-- | src/man/firejail.txt | 23 |
6 files changed, 79 insertions, 20 deletions
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 81ab18aa1..50fc0384c 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -48,10 +48,10 @@ char *seccomp_check_list(const char *str) { | |||
48 | const char *ptr1 = str; | 48 | const char *ptr1 = str; |
49 | char *ptr2 = rv; | 49 | char *ptr2 = rv; |
50 | while (*ptr1 != '\0') { | 50 | while (*ptr1 != '\0') { |
51 | if (isalnum(*ptr1) || *ptr1 == '_' || *ptr1 == ',' || *ptr1 == ':' || *ptr1 == '@' || *ptr1 == '-') | 51 | if (isalnum(*ptr1) || *ptr1 == '_' || *ptr1 == ',' || *ptr1 == ':' || *ptr1 == '@' || *ptr1 == '-' || *ptr1 == '!') |
52 | *ptr2++ = *ptr1++; | 52 | *ptr2++ = *ptr1++; |
53 | else { | 53 | else { |
54 | fprintf(stderr, "Error: invalid syscall list\n"); | 54 | fprintf(stderr, "Error: invalid syscall list entry %s\n", str); |
55 | exit(1); | 55 | exit(1); |
56 | } | 56 | } |
57 | } | 57 | } |
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h index 593963e76..e1579d098 100644 --- a/src/fseccomp/fseccomp.h +++ b/src/fseccomp/fseccomp.h | |||
@@ -52,7 +52,9 @@ void seccomp_secondary_block(const char *fname); | |||
52 | void write_to_file(int fd, const void *data, int size); | 52 | void write_to_file(int fd, const void *data, int size); |
53 | void filter_init(int fd); | 53 | void filter_init(int fd); |
54 | void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg); | 54 | void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg); |
55 | void filter_add_whitelist_for_excluded(int fd, int syscall, int arg, void *ptrarg); | ||
55 | void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg); | 56 | void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg); |
57 | void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg); | ||
56 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg); | 58 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg); |
57 | void filter_end_blacklist(int fd); | 59 | void filter_end_blacklist(int fd); |
58 | void filter_end_whitelist(int fd); | 60 | void filter_end_whitelist(int fd); |
diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c index 2a719725e..95c20d388 100644 --- a/src/fseccomp/seccomp.c +++ b/src/fseccomp/seccomp.c | |||
@@ -80,6 +80,10 @@ void seccomp_drop(const char *fname1, const char *fname2, char *list, int allow_ | |||
80 | 80 | ||
81 | // build pre-exec filter: don't blacklist any syscalls in @default-keep | 81 | // build pre-exec filter: don't blacklist any syscalls in @default-keep |
82 | filter_init(fd); | 82 | filter_init(fd); |
83 | |||
84 | // allow exceptions in form of !syscall | ||
85 | syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); | ||
86 | |||
83 | char *prelist, *postlist; | 87 | char *prelist, *postlist; |
84 | syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); | 88 | syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); |
85 | if (prelist) | 89 | if (prelist) |
@@ -128,6 +132,10 @@ void seccomp_default_drop(const char *fname1, const char *fname2, char *list, in | |||
128 | // build pre-exec filter: blacklist @default, don't blacklist | 132 | // build pre-exec filter: blacklist @default, don't blacklist |
129 | // any listed syscalls in @default-keep | 133 | // any listed syscalls in @default-keep |
130 | filter_init(fd); | 134 | filter_init(fd); |
135 | |||
136 | // allow exceptions in form of !syscall | ||
137 | syscall_check_list(list, filter_add_whitelist_for_excluded, fd, 0, NULL); | ||
138 | |||
131 | add_default_list(fd, allow_debuggers); | 139 | add_default_list(fd, allow_debuggers); |
132 | char *prelist, *postlist; | 140 | char *prelist, *postlist; |
133 | syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); | 141 | syscalls_in_list(list, "@default-keep", fd, &prelist, &postlist); |
@@ -175,6 +183,10 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list) { | |||
175 | 183 | ||
176 | // build pre-exec filter: whitelist also @default-keep | 184 | // build pre-exec filter: whitelist also @default-keep |
177 | filter_init(fd); | 185 | filter_init(fd); |
186 | |||
187 | // allow exceptions in form of !syscall | ||
188 | syscall_check_list(list, filter_add_blacklist_for_excluded, fd, 0, NULL); | ||
189 | |||
178 | // these syscalls are used by firejail after the seccomp filter is initialized | 190 | // these syscalls are used by firejail after the seccomp filter is initialized |
179 | int r; | 191 | int r; |
180 | r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0, NULL); | 192 | r = syscall_check_list("@default-keep", filter_add_whitelist, fd, 0, NULL); |
diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c index 2e1f317ed..266ef0c55 100644 --- a/src/fseccomp/seccomp_file.c +++ b/src/fseccomp/seccomp_file.c | |||
@@ -60,26 +60,58 @@ void filter_init(int fd) { | |||
60 | write_to_file(fd, filter, sizeof(filter)); | 60 | write_to_file(fd, filter, sizeof(filter)); |
61 | } | 61 | } |
62 | 62 | ||
63 | void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg) { | 63 | static void write_whitelist(int fd, int syscall) { |
64 | (void) arg; | ||
65 | (void) ptrarg; | ||
66 | |||
67 | struct sock_filter filter[] = { | 64 | struct sock_filter filter[] = { |
68 | WHITELIST(syscall) | 65 | WHITELIST(syscall) |
69 | }; | 66 | }; |
70 | write_to_file(fd, filter, sizeof(filter)); | 67 | write_to_file(fd, filter, sizeof(filter)); |
71 | } | 68 | } |
72 | 69 | ||
73 | void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg) { | 70 | static void write_blacklist(int fd, int syscall) { |
74 | (void) arg; | ||
75 | (void) ptrarg; | ||
76 | |||
77 | struct sock_filter filter[] = { | 71 | struct sock_filter filter[] = { |
78 | BLACKLIST(syscall) | 72 | BLACKLIST(syscall) |
79 | }; | 73 | }; |
80 | write_to_file(fd, filter, sizeof(filter)); | 74 | write_to_file(fd, filter, sizeof(filter)); |
81 | } | 75 | } |
82 | 76 | ||
77 | void filter_add_whitelist(int fd, int syscall, int arg, void *ptrarg) { | ||
78 | (void) arg; | ||
79 | (void) ptrarg; | ||
80 | |||
81 | if (syscall >= 0) { | ||
82 | write_whitelist(fd, syscall); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | // handle seccomp list exceptions (seccomp x,y,!z) | ||
87 | void filter_add_whitelist_for_excluded(int fd, int syscall, int arg, void *ptrarg) { | ||
88 | (void) arg; | ||
89 | (void) ptrarg; | ||
90 | |||
91 | if (syscall < 0) { | ||
92 | write_whitelist(fd, -syscall); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg) { | ||
97 | (void) arg; | ||
98 | (void) ptrarg; | ||
99 | |||
100 | if (syscall >= 0) { | ||
101 | write_blacklist(fd, syscall); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | // handle seccomp list exceptions (seccomp x,y,!z) | ||
106 | void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg) { | ||
107 | (void) arg; | ||
108 | (void) ptrarg; | ||
109 | |||
110 | if (syscall < 0) { | ||
111 | write_blacklist(fd, -syscall); | ||
112 | } | ||
113 | } | ||
114 | |||
83 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg) { | 115 | void filter_add_errno(int fd, int syscall, int arg, void *ptrarg) { |
84 | (void) ptrarg; | 116 | (void) ptrarg; |
85 | struct sock_filter filter[] = { | 117 | struct sock_filter filter[] = { |
diff --git a/src/fseccomp/syscall.c b/src/fseccomp/syscall.c index 3b698d2dd..d31b719d6 100644 --- a/src/fseccomp/syscall.c +++ b/src/fseccomp/syscall.c | |||
@@ -497,9 +497,17 @@ int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, | |||
497 | syscall_check_list(new_list, callback, fd, arg, ptrarg); | 497 | syscall_check_list(new_list, callback, fd, arg, ptrarg); |
498 | } | 498 | } |
499 | else { | 499 | else { |
500 | bool negate = false; | ||
501 | if (*ptr == '!') { | ||
502 | negate = true; | ||
503 | ptr++; | ||
504 | } | ||
500 | syscall_process_name(ptr, &syscall_nr, &error_nr); | 505 | syscall_process_name(ptr, &syscall_nr, &error_nr); |
501 | if (syscall_nr == -1) {;} | 506 | if (syscall_nr == -1) {;} |
502 | else if (callback != NULL) { | 507 | else if (callback != NULL) { |
508 | if (negate) { | ||
509 | syscall_nr = -syscall_nr; | ||
510 | } | ||
503 | if (error_nr != -1 && fd != 0) { | 511 | if (error_nr != -1 && fd != 0) { |
504 | filter_add_errno(fd, syscall_nr, error_nr, ptrarg); | 512 | filter_add_errno(fd, syscall_nr, error_nr, ptrarg); |
505 | } | 513 | } |
@@ -522,7 +530,7 @@ static void find_syscall(int fd, int syscall, int arg, void *ptrarg) { | |||
522 | (void)fd; | 530 | (void)fd; |
523 | (void) arg; | 531 | (void) arg; |
524 | SyscallCheckList *ptr = ptrarg; | 532 | SyscallCheckList *ptr = ptrarg; |
525 | if (syscall == ptr->syscall) | 533 | if (abs(syscall) == ptr->syscall) |
526 | ptr->found = true; | 534 | ptr->found = true; |
527 | } | 535 | } |
528 | 536 | ||
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 86b76f58f..afff3d5fa 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -1780,7 +1780,8 @@ system call groups are defined: @clock, @cpu-emulation, @debug, | |||
1780 | @default, @default-nodebuggers, @default-keep, @module, @obsolete, | 1780 | @default, @default-nodebuggers, @default-keep, @module, @obsolete, |
1781 | @privileged, @raw-io, @reboot, @resources and @swap. In addition, a | 1781 | @privileged, @raw-io, @reboot, @resources and @swap. In addition, a |
1782 | system call can be specified by its number instead of name with prefix | 1782 | system call can be specified by its number instead of name with prefix |
1783 | $, so for example $165 would be equal to mount on i386. | 1783 | $, so for example $165 would be equal to mount on i386. Exceptions |
1784 | can be allowed with prefix !. | ||
1784 | 1785 | ||
1785 | .br | 1786 | .br |
1786 | System architecture is strictly imposed only if flag | 1787 | System architecture is strictly imposed only if flag |
@@ -1798,8 +1799,10 @@ Example: | |||
1798 | .br | 1799 | .br |
1799 | $ firejail \-\-seccomp | 1800 | $ firejail \-\-seccomp |
1800 | .TP | 1801 | .TP |
1801 | \fB\-\-seccomp=syscall,@group | 1802 | \fB\-\-seccomp=syscall,@group,!syscall2 |
1802 | Enable seccomp filter, blacklist the default list (@default) and the syscalls or syscall groups specified by the command. | 1803 | Enable seccomp filter, whitelist "syscall2", but blacklist the default |
1804 | list (@default) and the syscalls or syscall groups specified by the | ||
1805 | command. | ||
1803 | .br | 1806 | .br |
1804 | 1807 | ||
1805 | .br | 1808 | .br |
@@ -1863,8 +1866,9 @@ domain with personality(2) system call. | |||
1863 | .br | 1866 | .br |
1864 | 1867 | ||
1865 | .TP | 1868 | .TP |
1866 | \fB\-\-seccomp.drop=syscall,@group | 1869 | \fB\-\-seccomp.drop=syscall,@group,!syscall2 |
1867 | Enable seccomp filter, and blacklist the syscalls or the syscall groups specified by the command. | 1870 | Enable seccomp filter, whitelist "syscall2" but blacklist the |
1871 | syscalls or the syscall groups specified by the command. | ||
1868 | .br | 1872 | .br |
1869 | 1873 | ||
1870 | .br | 1874 | .br |
@@ -1899,10 +1903,11 @@ rm: cannot remove `testfile': Operation not permitted | |||
1899 | 1903 | ||
1900 | 1904 | ||
1901 | .TP | 1905 | .TP |
1902 | \fB\-\-seccomp.keep=syscall,syscall,syscall | 1906 | \fB\-\-seccomp.keep=syscall,@group,!syscall2 |
1903 | Enable seccomp filter, and whitelist the syscalls specified by the | 1907 | Enable seccomp filter, blacklist "syscall2" but whitelist the |
1904 | command. The system calls needed by Firejail (group @default-keep: | 1908 | syscalls or the syscall groups specified by the command. The system |
1905 | prctl, execve) are handled with the preload library. | 1909 | calls needed by Firejail (group @default-keep: prctl, execve) are |
1910 | handled with the preload library. | ||
1906 | .br | 1911 | .br |
1907 | 1912 | ||
1908 | .br | 1913 | .br |