diff options
-rw-r--r-- | src/firejail/errno.c | 207 | ||||
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/main.c | 56 | ||||
-rw-r--r-- | src/firejail/profile.c | 16 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 2 | ||||
-rw-r--r-- | src/firejail/seccomp.c | 72 | ||||
-rw-r--r-- | src/fseccomp/main.c | 2 | ||||
-rw-r--r-- | src/fseccomp/protocol.c | 2 | ||||
-rw-r--r-- | src/fseccomp/syscall.c | 87 | ||||
-rwxr-xr-x | test/filters/seccomp-errno.exp | 44 |
10 files changed, 106 insertions, 385 deletions
diff --git a/src/firejail/errno.c b/src/firejail/errno.c deleted file mode 100644 index 8215c99a1..000000000 --- a/src/firejail/errno.c +++ /dev/null | |||
@@ -1,207 +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 | #ifdef HAVE_SECCOMP | ||
21 | #include "firejail.h" | ||
22 | #include <errno.h> | ||
23 | //#include <attr/xattr.h> | ||
24 | |||
25 | typedef struct { | ||
26 | char *name; | ||
27 | int nr; | ||
28 | } ErrnoEntry; | ||
29 | |||
30 | static ErrnoEntry errnolist[] = { | ||
31 | // | ||
32 | // code generated using tools/extract-errnos | ||
33 | // | ||
34 | {"EPERM", EPERM}, | ||
35 | {"ENOENT", ENOENT}, | ||
36 | {"ESRCH", ESRCH}, | ||
37 | {"EINTR", EINTR}, | ||
38 | {"EIO", EIO}, | ||
39 | {"ENXIO", ENXIO}, | ||
40 | {"E2BIG", E2BIG}, | ||
41 | {"ENOEXEC", ENOEXEC}, | ||
42 | {"EBADF", EBADF}, | ||
43 | {"ECHILD", ECHILD}, | ||
44 | {"EAGAIN", EAGAIN}, | ||
45 | {"ENOMEM", ENOMEM}, | ||
46 | {"EACCES", EACCES}, | ||
47 | {"EFAULT", EFAULT}, | ||
48 | {"ENOTBLK", ENOTBLK}, | ||
49 | {"EBUSY", EBUSY}, | ||
50 | {"EEXIST", EEXIST}, | ||
51 | {"EXDEV", EXDEV}, | ||
52 | {"ENODEV", ENODEV}, | ||
53 | {"ENOTDIR", ENOTDIR}, | ||
54 | {"EISDIR", EISDIR}, | ||
55 | {"EINVAL", EINVAL}, | ||
56 | {"ENFILE", ENFILE}, | ||
57 | {"EMFILE", EMFILE}, | ||
58 | {"ENOTTY", ENOTTY}, | ||
59 | {"ETXTBSY", ETXTBSY}, | ||
60 | {"EFBIG", EFBIG}, | ||
61 | {"ENOSPC", ENOSPC}, | ||
62 | {"ESPIPE", ESPIPE}, | ||
63 | {"EROFS", EROFS}, | ||
64 | {"EMLINK", EMLINK}, | ||
65 | {"EPIPE", EPIPE}, | ||
66 | {"EDOM", EDOM}, | ||
67 | {"ERANGE", ERANGE}, | ||
68 | {"EDEADLK", EDEADLK}, | ||
69 | {"ENAMETOOLONG", ENAMETOOLONG}, | ||
70 | {"ENOLCK", ENOLCK}, | ||
71 | {"ENOSYS", ENOSYS}, | ||
72 | {"ENOTEMPTY", ENOTEMPTY}, | ||
73 | {"ELOOP", ELOOP}, | ||
74 | {"EWOULDBLOCK", EWOULDBLOCK}, | ||
75 | {"ENOMSG", ENOMSG}, | ||
76 | {"EIDRM", EIDRM}, | ||
77 | {"ECHRNG", ECHRNG}, | ||
78 | {"EL2NSYNC", EL2NSYNC}, | ||
79 | {"EL3HLT", EL3HLT}, | ||
80 | {"EL3RST", EL3RST}, | ||
81 | {"ELNRNG", ELNRNG}, | ||
82 | {"EUNATCH", EUNATCH}, | ||
83 | {"ENOCSI", ENOCSI}, | ||
84 | {"EL2HLT", EL2HLT}, | ||
85 | {"EBADE", EBADE}, | ||
86 | {"EBADR", EBADR}, | ||
87 | {"EXFULL", EXFULL}, | ||
88 | {"ENOANO", ENOANO}, | ||
89 | {"EBADRQC", EBADRQC}, | ||
90 | {"EBADSLT", EBADSLT}, | ||
91 | {"EDEADLOCK", EDEADLOCK}, | ||
92 | {"EBFONT", EBFONT}, | ||
93 | {"ENOSTR", ENOSTR}, | ||
94 | {"ENODATA", ENODATA}, | ||
95 | {"ETIME", ETIME}, | ||
96 | {"ENOSR", ENOSR}, | ||
97 | {"ENONET", ENONET}, | ||
98 | {"ENOPKG", ENOPKG}, | ||
99 | {"EREMOTE", EREMOTE}, | ||
100 | {"ENOLINK", ENOLINK}, | ||
101 | {"EADV", EADV}, | ||
102 | {"ESRMNT", ESRMNT}, | ||
103 | {"ECOMM", ECOMM}, | ||
104 | {"EPROTO", EPROTO}, | ||
105 | {"EMULTIHOP", EMULTIHOP}, | ||
106 | {"EDOTDOT", EDOTDOT}, | ||
107 | {"EBADMSG", EBADMSG}, | ||
108 | {"EOVERFLOW", EOVERFLOW}, | ||
109 | {"ENOTUNIQ", ENOTUNIQ}, | ||
110 | {"EBADFD", EBADFD}, | ||
111 | {"EREMCHG", EREMCHG}, | ||
112 | {"ELIBACC", ELIBACC}, | ||
113 | {"ELIBBAD", ELIBBAD}, | ||
114 | {"ELIBSCN", ELIBSCN}, | ||
115 | {"ELIBMAX", ELIBMAX}, | ||
116 | {"ELIBEXEC", ELIBEXEC}, | ||
117 | {"EILSEQ", EILSEQ}, | ||
118 | {"ERESTART", ERESTART}, | ||
119 | {"ESTRPIPE", ESTRPIPE}, | ||
120 | {"EUSERS", EUSERS}, | ||
121 | {"ENOTSOCK", ENOTSOCK}, | ||
122 | {"EDESTADDRREQ", EDESTADDRREQ}, | ||
123 | {"EMSGSIZE", EMSGSIZE}, | ||
124 | {"EPROTOTYPE", EPROTOTYPE}, | ||
125 | {"ENOPROTOOPT", ENOPROTOOPT}, | ||
126 | {"EPROTONOSUPPORT", EPROTONOSUPPORT}, | ||
127 | {"ESOCKTNOSUPPORT", ESOCKTNOSUPPORT}, | ||
128 | {"EOPNOTSUPP", EOPNOTSUPP}, | ||
129 | {"EPFNOSUPPORT", EPFNOSUPPORT}, | ||
130 | {"EAFNOSUPPORT", EAFNOSUPPORT}, | ||
131 | {"EADDRINUSE", EADDRINUSE}, | ||
132 | {"EADDRNOTAVAIL", EADDRNOTAVAIL}, | ||
133 | {"ENETDOWN", ENETDOWN}, | ||
134 | {"ENETUNREACH", ENETUNREACH}, | ||
135 | {"ENETRESET", ENETRESET}, | ||
136 | {"ECONNABORTED", ECONNABORTED}, | ||
137 | {"ECONNRESET", ECONNRESET}, | ||
138 | {"ENOBUFS", ENOBUFS}, | ||
139 | {"EISCONN", EISCONN}, | ||
140 | {"ENOTCONN", ENOTCONN}, | ||
141 | {"ESHUTDOWN", ESHUTDOWN}, | ||
142 | {"ETOOMANYREFS", ETOOMANYREFS}, | ||
143 | {"ETIMEDOUT", ETIMEDOUT}, | ||
144 | {"ECONNREFUSED", ECONNREFUSED}, | ||
145 | {"EHOSTDOWN", EHOSTDOWN}, | ||
146 | {"EHOSTUNREACH", EHOSTUNREACH}, | ||
147 | {"EALREADY", EALREADY}, | ||
148 | {"EINPROGRESS", EINPROGRESS}, | ||
149 | {"ESTALE", ESTALE}, | ||
150 | {"EUCLEAN", EUCLEAN}, | ||
151 | {"ENOTNAM", ENOTNAM}, | ||
152 | {"ENAVAIL", ENAVAIL}, | ||
153 | {"EISNAM", EISNAM}, | ||
154 | {"EREMOTEIO", EREMOTEIO}, | ||
155 | {"EDQUOT", EDQUOT}, | ||
156 | {"ENOMEDIUM", ENOMEDIUM}, | ||
157 | {"EMEDIUMTYPE", EMEDIUMTYPE}, | ||
158 | {"ECANCELED", ECANCELED}, | ||
159 | {"ENOKEY", ENOKEY}, | ||
160 | {"EKEYEXPIRED", EKEYEXPIRED}, | ||
161 | {"EKEYREVOKED", EKEYREVOKED}, | ||
162 | {"EKEYREJECTED", EKEYREJECTED}, | ||
163 | {"EOWNERDEAD", EOWNERDEAD}, | ||
164 | {"ENOTRECOVERABLE", ENOTRECOVERABLE}, | ||
165 | {"ERFKILL", ERFKILL}, | ||
166 | {"EHWPOISON", EHWPOISON}, | ||
167 | {"ENOTSUP", ENOTSUP}, | ||
168 | #ifdef ENOATTR | ||
169 | {"ENOATTR", ENOATTR}, | ||
170 | #endif | ||
171 | }; | ||
172 | |||
173 | int errno_highest_nr(void) { | ||
174 | int i, max = 0; | ||
175 | int elems = sizeof(errnolist) / sizeof(errnolist[0]); | ||
176 | for (i = 0; i < elems; i++) { | ||
177 | if (errnolist[i].nr > max) | ||
178 | max = errnolist[i].nr; | ||
179 | } | ||
180 | |||
181 | return max; | ||
182 | } | ||
183 | |||
184 | int errno_find_name(const char *name) { | ||
185 | EUID_ASSERT(); | ||
186 | |||
187 | int i; | ||
188 | int elems = sizeof(errnolist) / sizeof(errnolist[0]); | ||
189 | for (i = 0; i < elems; i++) { | ||
190 | if (strcasecmp(name, errnolist[i].name) == 0) | ||
191 | return errnolist[i].nr; | ||
192 | } | ||
193 | |||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | char *errno_find_nr(int nr) { | ||
198 | int i; | ||
199 | int elems = sizeof(errnolist) / sizeof(errnolist[0]); | ||
200 | for (i = 0; i < elems; i++) { | ||
201 | if (nr == errnolist[i].nr) | ||
202 | return errnolist[i].name; | ||
203 | } | ||
204 | |||
205 | return "unknown"; | ||
206 | } | ||
207 | #endif // HAVE_SECCOMP | ||
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index cf540ff91..56dbd6868 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -222,7 +222,6 @@ typedef struct config_t { | |||
222 | char *seccomp_list;// optional seccomp list on top of default filter | 222 | char *seccomp_list;// optional seccomp list on top of default filter |
223 | char *seccomp_list_drop; // seccomp drop list | 223 | char *seccomp_list_drop; // seccomp drop list |
224 | char *seccomp_list_keep; // seccomp keep list | 224 | char *seccomp_list_keep; // seccomp keep list |
225 | char **seccomp_list_errno; // seccomp errno[nr] lists | ||
226 | char *protocol; // protocol list | 225 | char *protocol; // protocol list |
227 | 226 | ||
228 | // rlimits | 227 | // rlimits |
@@ -496,12 +495,12 @@ void fs_private_home_list(void); | |||
496 | 495 | ||
497 | 496 | ||
498 | // seccomp.c | 497 | // seccomp.c |
498 | char *seccomp_check_list(const char *str); | ||
499 | int seccomp_load(const char *fname); | 499 | int seccomp_load(const char *fname); |
500 | void seccomp_filter_32(void); | 500 | void seccomp_filter_32(void); |
501 | void seccomp_filter_64(void); | 501 | void seccomp_filter_64(void); |
502 | int seccomp_filter_drop(int enforce_seccomp); | 502 | int seccomp_filter_drop(int enforce_seccomp); |
503 | int seccomp_filter_keep(void); | 503 | int seccomp_filter_keep(void); |
504 | int seccomp_filter_errno(void); | ||
505 | void seccomp_print_filter_name(const char *name); | 504 | void seccomp_print_filter_name(const char *name); |
506 | void seccomp_print_filter(pid_t pid); | 505 | void seccomp_print_filter(pid_t pid); |
507 | 506 | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index fc86f9651..b6f3a7f59 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -851,9 +851,6 @@ int main(int argc, char **argv) { | |||
851 | int custom_profile = 0; // custom profile loaded | 851 | int custom_profile = 0; // custom profile loaded |
852 | char *custom_profile_dir = NULL; // custom profile directory | 852 | char *custom_profile_dir = NULL; // custom profile directory |
853 | int arg_noprofile = 0; // use default.profile if none other found/specified | 853 | int arg_noprofile = 0; // use default.profile if none other found/specified |
854 | #ifdef HAVE_SECCOMP | ||
855 | int highest_errno = errno_highest_nr(); | ||
856 | #endif | ||
857 | 854 | ||
858 | // build /run/firejail directory structure | 855 | // build /run/firejail directory structure |
859 | preproc_build_firejail_dir(); | 856 | preproc_build_firejail_dir(); |
@@ -1155,9 +1152,7 @@ int main(int argc, char **argv) { | |||
1155 | exit(1); | 1152 | exit(1); |
1156 | } | 1153 | } |
1157 | arg_seccomp = 1; | 1154 | arg_seccomp = 1; |
1158 | cfg.seccomp_list = strdup(argv[i] + 10); | 1155 | cfg.seccomp_list = seccomp_check_list(argv[i] + 10); |
1159 | if (!cfg.seccomp_list) | ||
1160 | errExit("strdup"); | ||
1161 | } | 1156 | } |
1162 | else { | 1157 | else { |
1163 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | 1158 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); |
@@ -1171,9 +1166,7 @@ int main(int argc, char **argv) { | |||
1171 | exit(1); | 1166 | exit(1); |
1172 | } | 1167 | } |
1173 | arg_seccomp = 1; | 1168 | arg_seccomp = 1; |
1174 | cfg.seccomp_list_drop = strdup(argv[i] + 15); | 1169 | cfg.seccomp_list_drop = seccomp_check_list(argv[i] + 15); |
1175 | if (!cfg.seccomp_list_drop) | ||
1176 | errExit("strdup"); | ||
1177 | } | 1170 | } |
1178 | else { | 1171 | else { |
1179 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | 1172 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); |
@@ -1187,43 +1180,7 @@ int main(int argc, char **argv) { | |||
1187 | exit(1); | 1180 | exit(1); |
1188 | } | 1181 | } |
1189 | arg_seccomp = 1; | 1182 | arg_seccomp = 1; |
1190 | cfg.seccomp_list_keep = strdup(argv[i] + 15); | 1183 | cfg.seccomp_list_keep = seccomp_check_list(argv[i] + 15); |
1191 | if (!cfg.seccomp_list_keep) | ||
1192 | errExit("strdup"); | ||
1193 | } | ||
1194 | else { | ||
1195 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
1196 | exit(1); | ||
1197 | } | ||
1198 | } | ||
1199 | else if (strncmp(argv[i], "--seccomp.e", 11) == 0 && strchr(argv[i], '=')) { | ||
1200 | if (checkcfg(CFG_SECCOMP)) { | ||
1201 | if (arg_seccomp && !cfg.seccomp_list_errno) { | ||
1202 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
1203 | exit(1); | ||
1204 | } | ||
1205 | char *eq = strchr(argv[i], '='); | ||
1206 | char *errnoname = strndup(argv[i] + 10, eq - (argv[i] + 10)); | ||
1207 | int nr = errno_find_name(errnoname); | ||
1208 | if (nr == -1) { | ||
1209 | fprintf(stderr, "Error: unknown errno %s\n", errnoname); | ||
1210 | free(errnoname); | ||
1211 | exit(1); | ||
1212 | } | ||
1213 | |||
1214 | if (!cfg.seccomp_list_errno) | ||
1215 | cfg.seccomp_list_errno = calloc(highest_errno+1, sizeof(cfg.seccomp_list_errno[0])); | ||
1216 | |||
1217 | if (cfg.seccomp_list_errno[nr]) { | ||
1218 | fprintf(stderr, "Error: errno %s already configured\n", errnoname); | ||
1219 | free(errnoname); | ||
1220 | exit(1); | ||
1221 | } | ||
1222 | arg_seccomp = 1; | ||
1223 | cfg.seccomp_list_errno[nr] = strdup(eq+1); | ||
1224 | if (!cfg.seccomp_list_errno[nr]) | ||
1225 | errExit("strdup"); | ||
1226 | free(errnoname); | ||
1227 | } | 1184 | } |
1228 | else { | 1185 | else { |
1229 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | 1186 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); |
@@ -2606,13 +2563,6 @@ int main(int argc, char **argv) { | |||
2606 | waitpid(child, &status, 0); | 2563 | waitpid(child, &status, 0); |
2607 | 2564 | ||
2608 | // free globals | 2565 | // free globals |
2609 | #ifdef HAVE_SECCOMP | ||
2610 | if (cfg.seccomp_list_errno) { | ||
2611 | for (i = 0; i < highest_errno; i++) | ||
2612 | free(cfg.seccomp_list_errno[i]); | ||
2613 | free(cfg.seccomp_list_errno); | ||
2614 | } | ||
2615 | #endif | ||
2616 | if (cfg.profile) { | 2566 | if (cfg.profile) { |
2617 | ProfileEntry *prf = cfg.profile; | 2567 | ProfileEntry *prf = cfg.profile; |
2618 | while (prf != NULL) { | 2568 | while (prf != NULL) { |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index f7d5e87e6..f3a7eb727 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -529,9 +529,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
529 | #ifdef HAVE_SECCOMP | 529 | #ifdef HAVE_SECCOMP |
530 | if (checkcfg(CFG_SECCOMP)) { | 530 | if (checkcfg(CFG_SECCOMP)) { |
531 | arg_seccomp = 1; | 531 | arg_seccomp = 1; |
532 | cfg.seccomp_list = strdup(ptr + 8); | 532 | cfg.seccomp_list = seccomp_check_list(ptr + 8); |
533 | if (!cfg.seccomp_list) | ||
534 | errExit("strdup"); | ||
535 | } | 533 | } |
536 | else | 534 | else |
537 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | 535 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); |
@@ -545,9 +543,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
545 | #ifdef HAVE_SECCOMP | 543 | #ifdef HAVE_SECCOMP |
546 | if (checkcfg(CFG_SECCOMP)) { | 544 | if (checkcfg(CFG_SECCOMP)) { |
547 | arg_seccomp = 1; | 545 | arg_seccomp = 1; |
548 | cfg.seccomp_list_drop = strdup(ptr + 13); | 546 | cfg.seccomp_list_drop = seccomp_check_list(ptr + 13); |
549 | if (!cfg.seccomp_list_drop) | ||
550 | errExit("strdup"); | ||
551 | } | 547 | } |
552 | else | 548 | else |
553 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | 549 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); |
@@ -560,9 +556,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
560 | #ifdef HAVE_SECCOMP | 556 | #ifdef HAVE_SECCOMP |
561 | if (checkcfg(CFG_SECCOMP)) { | 557 | if (checkcfg(CFG_SECCOMP)) { |
562 | arg_seccomp = 1; | 558 | arg_seccomp = 1; |
563 | cfg.seccomp_list_keep= strdup(ptr + 13); | 559 | cfg.seccomp_list_keep= seccomp_check_list(ptr + 13); |
564 | if (!cfg.seccomp_list_keep) | ||
565 | errExit("strdup"); | ||
566 | } | 560 | } |
567 | else | 561 | else |
568 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | 562 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); |
@@ -576,7 +570,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
576 | arg_caps_list = strdup(ptr + 10); | 570 | arg_caps_list = strdup(ptr + 10); |
577 | if (!arg_caps_list) | 571 | if (!arg_caps_list) |
578 | errExit("strdup"); | 572 | errExit("strdup"); |
579 | // verify seccomp list and exit if problems | 573 | // verify caps list and exit if problems |
580 | if (caps_check_list(arg_caps_list, NULL)) | 574 | if (caps_check_list(arg_caps_list, NULL)) |
581 | exit(1); | 575 | exit(1); |
582 | return 0; | 576 | return 0; |
@@ -588,7 +582,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
588 | arg_caps_list = strdup(ptr + 10); | 582 | arg_caps_list = strdup(ptr + 10); |
589 | if (!arg_caps_list) | 583 | if (!arg_caps_list) |
590 | errExit("strdup"); | 584 | errExit("strdup"); |
591 | // verify seccomp list and exit if problems | 585 | // verify caps list and exit if problems |
592 | if (caps_check_list(arg_caps_list, NULL)) | 586 | if (caps_check_list(arg_caps_list, NULL)) |
593 | exit(1); | 587 | exit(1); |
594 | return 0; | 588 | return 0; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index e3c95283d..556cb1fca 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -847,8 +847,6 @@ assert(0); | |||
847 | if (arg_seccomp == 1) { | 847 | if (arg_seccomp == 1) { |
848 | if (cfg.seccomp_list_keep) | 848 | if (cfg.seccomp_list_keep) |
849 | seccomp_filter_keep(); | 849 | seccomp_filter_keep(); |
850 | else if (cfg.seccomp_list_errno) | ||
851 | seccomp_filter_errno(); | ||
852 | else | 850 | else |
853 | seccomp_filter_drop(enforce_seccomp); | 851 | seccomp_filter_drop(enforce_seccomp); |
854 | } | 852 | } |
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index 74d29fc9d..20807f5b1 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c | |||
@@ -22,6 +22,34 @@ | |||
22 | #include "firejail.h" | 22 | #include "firejail.h" |
23 | #include "../include/seccomp.h" | 23 | #include "../include/seccomp.h" |
24 | 24 | ||
25 | char *seccomp_check_list(const char *str) { | ||
26 | assert(str); | ||
27 | if (strlen(str) == 0) { | ||
28 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | ||
29 | exit(1); | ||
30 | } | ||
31 | |||
32 | int len = strlen(str) + 1; | ||
33 | char *rv = malloc(len); | ||
34 | if (!rv) | ||
35 | errExit("malloc"); | ||
36 | memset(rv, 0, len); | ||
37 | |||
38 | const char *ptr1 = str; | ||
39 | char *ptr2 = rv; | ||
40 | while (*ptr1 != '\0') { | ||
41 | if (isalnum(*ptr1) || *ptr1 == '_' || *ptr1 == ',' || *ptr1 == ':') | ||
42 | *ptr2++ = *ptr1++; | ||
43 | else { | ||
44 | fprintf(stderr, "Error: invalid syscall list\n"); | ||
45 | exit(1); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | return rv; | ||
50 | } | ||
51 | |||
52 | |||
25 | int seccomp_load(const char *fname) { | 53 | int seccomp_load(const char *fname) { |
26 | assert(fname); | 54 | assert(fname); |
27 | 55 | ||
@@ -136,10 +164,6 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
136 | #endif | 164 | #endif |
137 | if (arg_debug) | 165 | if (arg_debug) |
138 | printf("Build default+drop seccomp filter\n"); | 166 | 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"); | ||
141 | exit(1); | ||
142 | } | ||
143 | 167 | ||
144 | // build the seccomp filter as a regular user | 168 | // build the seccomp filter as a regular user |
145 | int rv; | 169 | int rv; |
@@ -157,10 +181,6 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
157 | else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { | 181 | else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { |
158 | if (arg_debug) | 182 | if (arg_debug) |
159 | printf("Build drop seccomp filter\n"); | 183 | 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"); | ||
162 | exit(1); | ||
163 | } | ||
164 | 184 | ||
165 | // build the seccomp filter as a regular user | 185 | // build the seccomp filter as a regular user |
166 | int rv; | 186 | int rv; |
@@ -199,10 +219,6 @@ int seccomp_filter_drop(int enforce_seccomp) { | |||
199 | int seccomp_filter_keep(void) { | 219 | int seccomp_filter_keep(void) { |
200 | if (arg_debug) | 220 | if (arg_debug) |
201 | printf("Build drop seccomp filter\n"); | 221 | printf("Build drop seccomp filter\n"); |
202 | if (strlen(cfg.seccomp_list_keep) == 0) { | ||
203 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | ||
204 | exit(1); | ||
205 | } | ||
206 | 222 | ||
207 | // build the seccomp filter as a regular user | 223 | // build the seccomp filter as a regular user |
208 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, | 224 | int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, |
@@ -216,38 +232,6 @@ int seccomp_filter_keep(void) { | |||
216 | return seccomp_load(RUN_SECCOMP_CFG); | 232 | return seccomp_load(RUN_SECCOMP_CFG); |
217 | } | 233 | } |
218 | 234 | ||
219 | // errno filter for seccomp option | ||
220 | int seccomp_filter_errno(void) { | ||
221 | #if 0 //todo: disabled temporarely, bring it back | ||
222 | int i; | ||
223 | int higest_errno = errno_highest_nr(); | ||
224 | filter_init(); | ||
225 | |||
226 | // apply errno list | ||
227 | |||
228 | for (i = 0; i < higest_errno; i++) { | ||
229 | if (cfg.seccomp_list_errno[i]) { | ||
230 | if (syscall_check_list(cfg.seccomp_list_errno[i], filter_add_errno, i)) { | ||
231 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | ||
232 | exit(1); | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | filter_end_blacklist(); | ||
238 | if (arg_debug) | ||
239 | filter_debug(); | ||
240 | |||
241 | // save seccomp filter in /run/firejail/mnt/seccomp | ||
242 | // in order to use it in --join operations | ||
243 | write_seccomp_file(); | ||
244 | return seccomp_load(RUN_SECCOMP_CFG); | ||
245 | #else | ||
246 | printf("*** --seccomp.<errno> is temporarily disabled, it will be brought back soon ***\n"); | ||
247 | return 0; | ||
248 | #endif | ||
249 | } | ||
250 | |||
251 | void seccomp_print_filter_name(const char *name) { | 235 | void seccomp_print_filter_name(const char *name) { |
252 | EUID_ASSERT(); | 236 | EUID_ASSERT(); |
253 | if (!name || strlen(name) == 0) { | 237 | if (!name || strlen(name) == 0) { |
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c index 22b13bcd9..39e72fdf9 100644 --- a/src/fseccomp/main.c +++ b/src/fseccomp/main.c | |||
@@ -40,7 +40,7 @@ static void usage(void) { | |||
40 | int main(int argc, char **argv) { | 40 | int main(int argc, char **argv) { |
41 | #if 0 | 41 | #if 0 |
42 | { | 42 | { |
43 | system("cat /proc/self/status"); | 43 | //system("cat /proc/self/status"); |
44 | int i; | 44 | int i; |
45 | for (i = 0; i < argc; i++) | 45 | for (i = 0; i < argc; i++) |
46 | printf("*%s* ", argv[i]); | 46 | printf("*%s* ", argv[i]); |
diff --git a/src/fseccomp/protocol.c b/src/fseccomp/protocol.c index 38c5f9d88..7bf560fe1 100644 --- a/src/fseccomp/protocol.c +++ b/src/fseccomp/protocol.c | |||
@@ -107,7 +107,7 @@ void protocol_build_filter(const char *prlist, const char *fname) { | |||
107 | assert(fname); | 107 | assert(fname); |
108 | 108 | ||
109 | #ifndef SYS_socket | 109 | #ifndef SYS_socket |
110 | fprintf(stderr, "Warning: --protocol not supported on this platform\n"); | 110 | fprintf(stderr, "Warning fseccomp: --protocol not supported on this platform\n"); |
111 | return; | 111 | return; |
112 | #else | 112 | #else |
113 | // build the filter | 113 | // build the filter |
diff --git a/src/fseccomp/syscall.c b/src/fseccomp/syscall.c index e2052efde..6696f2b11 100644 --- a/src/fseccomp/syscall.c +++ b/src/fseccomp/syscall.c | |||
@@ -67,12 +67,52 @@ void syscall_print(void) { | |||
67 | printf("\n"); | 67 | printf("\n"); |
68 | } | 68 | } |
69 | 69 | ||
70 | // allowed input: | ||
71 | // - syscall | ||
72 | // - syscall(error) | ||
73 | static void syscall_process_name(const char *name, int *syscall_nr, int *error_nr) { | ||
74 | assert(name); | ||
75 | if (strlen(name) == 0) | ||
76 | goto error; | ||
77 | *error_nr = -1; | ||
78 | |||
79 | // syntax check | ||
80 | char *str = strdup(name); | ||
81 | if (!str) | ||
82 | errExit("strdup"); | ||
83 | |||
84 | char *syscall_name = str; | ||
85 | char *error_name = strchr(str, ':'); | ||
86 | if (error_name) { | ||
87 | *error_name = '\0'; | ||
88 | error_name++; | ||
89 | } | ||
90 | if (strlen(syscall_name) == 0) { | ||
91 | free(str); | ||
92 | goto error; | ||
93 | } | ||
94 | |||
95 | *syscall_nr = syscall_find_name(syscall_name); | ||
96 | if (error_name) { | ||
97 | *error_nr = errno_find_name(error_name); | ||
98 | if (*error_nr == -1) | ||
99 | *syscall_nr = -1; | ||
100 | } | ||
101 | |||
102 | free(str); | ||
103 | return; | ||
104 | |||
105 | error: | ||
106 | fprintf(stderr, "Error fseccomp: invalid syscall list entry %s\n", name); | ||
107 | exit(1); | ||
108 | } | ||
109 | |||
70 | // return 1 if error, 0 if OK | 110 | // return 1 if error, 0 if OK |
71 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg) { | 111 | int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg) { |
72 | // don't allow empty lists | 112 | // don't allow empty lists |
73 | if (slist == NULL || *slist == '\0') { | 113 | if (slist == NULL || *slist == '\0') { |
74 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | 114 | fprintf(stderr, "Error fseccomp: empty syscall lists are not allowed\n"); |
75 | return -1; | 115 | exit(1); |
76 | } | 116 | } |
77 | 117 | ||
78 | // work on a copy of the string | 118 | // work on a copy of the string |
@@ -80,29 +120,28 @@ int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, | |||
80 | if (!str) | 120 | if (!str) |
81 | errExit("strdup"); | 121 | errExit("strdup"); |
82 | 122 | ||
83 | char *ptr = str; | 123 | char *ptr =strtok(str, ","); |
84 | char *start = str; | 124 | if (ptr == NULL) { |
85 | while (*ptr != '\0') { | 125 | fprintf(stderr, "Error fseccomp: empty syscall lists are not allowed\n"); |
86 | if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') | 126 | exit(1); |
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 | } | 127 | } |
100 | if (*start != '\0') { | 128 | |
101 | int nr = syscall_find_name(start); | 129 | while (ptr) { |
102 | if (nr == -1) | 130 | printf("ptr %s\n", ptr); |
103 | fprintf(stderr, "Warning: syscall %s not found\n", start); | 131 | |
104 | else if (callback != NULL) | 132 | int syscall_nr; |
105 | callback(fd, nr, arg); | 133 | int error_nr; |
134 | syscall_process_name(ptr, &syscall_nr, &error_nr); | ||
135 | printf("%d, %d\n", syscall_nr, error_nr); | ||
136 | if (syscall_nr == -1) | ||
137 | fprintf(stderr, "Warning fseccomp: syscall %s not found\n", ptr); | ||
138 | else if (callback != NULL) { | ||
139 | if (error_nr != -1) | ||
140 | filter_add_errno(fd, syscall_nr, error_nr); | ||
141 | else | ||
142 | callback(fd, syscall_nr, arg); | ||
143 | } | ||
144 | ptr = strtok(NULL, ","); | ||
106 | } | 145 | } |
107 | 146 | ||
108 | free(str); | 147 | free(str); |
diff --git a/test/filters/seccomp-errno.exp b/test/filters/seccomp-errno.exp index 4df1948be..c3af2fbe9 100755 --- a/test/filters/seccomp-errno.exp +++ b/test/filters/seccomp-errno.exp | |||
@@ -8,23 +8,23 @@ spawn $env(SHELL) | |||
8 | match_max 100000 | 8 | match_max 100000 |
9 | 9 | ||
10 | send -- "touch seccomp-test-file\r" | 10 | send -- "touch seccomp-test-file\r" |
11 | sleep 1 | 11 | after 100 |
12 | 12 | ||
13 | send -- "firejail --seccomp.enoent=unlinkat rm seccomp-test-file\r" | 13 | send -- "firejail --seccomp=unlinkat:ENOENT rm seccomp-test-file\r" |
14 | expect { | 14 | expect { |
15 | timeout {puts "TESTING ERROR 0\n";exit} | 15 | timeout {puts "TESTING ERROR 0\n";exit} |
16 | "No such file or directory" | 16 | "No such file or directory" |
17 | } | 17 | } |
18 | sleep 1 | 18 | sleep 1 |
19 | 19 | ||
20 | send -- "firejail --seccomp.enoent=unlinkat --debug rm seccomp-test-file\r" | 20 | send -- "firejail --seccomp=unlinkat:ENOENT --debug rm seccomp-test-file\r" |
21 | expect { | 21 | expect { |
22 | timeout {puts "TESTING ERROR 1\n";exit} | 22 | timeout {puts "TESTING ERROR 1\n";exit} |
23 | "unlinkat 2 ENOENT" | 23 | "unlinkat 2 ENOENT" |
24 | } | 24 | } |
25 | sleep 1 | 25 | sleep 1 |
26 | 26 | ||
27 | send -- "firejail --seccomp.enoent=unlinkat,mkdir\r" | 27 | send -- "firejail --seccomp=unlinkat:ENOENT,mkdir:ENOENT\r" |
28 | expect { | 28 | expect { |
29 | timeout {puts "TESTING ERROR 2\n";exit} | 29 | timeout {puts "TESTING ERROR 2\n";exit} |
30 | "Child process initialized" | 30 | "Child process initialized" |
@@ -49,42 +49,6 @@ puts "\n" | |||
49 | send -- "exit\r" | 49 | send -- "exit\r" |
50 | sleep 1 | 50 | sleep 1 |
51 | 51 | ||
52 | |||
53 | send -- "firejail --seccomp.enoent=unlinkat --seccomp.enoent=mkdir\r" | ||
54 | expect { | ||
55 | timeout {puts "TESTING ERROR 5\n";exit} | ||
56 | "errno enoent already configured" | ||
57 | } | ||
58 | sleep 1 | ||
59 | |||
60 | send -- "firejail --seccomp.enoent=unlinkat --seccomp.eperm=mkdir\r" | ||
61 | expect { | ||
62 | timeout {puts "TESTING ERROR 6\n";exit} | ||
63 | "Child process initialized" | ||
64 | } | ||
65 | sleep 1 | ||
66 | send -- "rm seccomp-test-file\r" | ||
67 | expect { | ||
68 | timeout {puts "TESTING ERROR 7\n";exit} | ||
69 | "No such file or directory" | ||
70 | } | ||
71 | after 100 | ||
72 | puts "\n" | ||
73 | |||
74 | send -- "mkdir seccomp-test-dir\r" | ||
75 | expect { | ||
76 | timeout {puts "TESTING ERROR 8\n";exit} | ||
77 | "Operation not permitted" | ||
78 | } | ||
79 | after 100 | ||
80 | puts "\n" | ||
81 | |||
82 | send -- "exit\r" | ||
83 | sleep 1 | ||
84 | |||
85 | |||
86 | |||
87 | |||
88 | send -- "rm seccomp-test-file\r" | 52 | send -- "rm seccomp-test-file\r" |
89 | after 100 | 53 | after 100 |
90 | puts "all done\n" | 54 | puts "all done\n" |