aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/firejail/firejail.h15
-rw-r--r--src/firejail/main.c17
-rw-r--r--src/firejail/protocol.c240
-rw-r--r--src/firejail/sandbox.c5
-rw-r--r--src/firejail/seccomp.h16
5 files changed, 287 insertions, 6 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 91bb420b6..e79cc4a2c 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -109,9 +109,10 @@ typedef struct config_t {
109 109
110 // seccomp 110 // seccomp
111 char *seccomp_list;// optional seccomp list on top of default filter 111 char *seccomp_list;// optional seccomp list on top of default filter
112 char *seccomp_list_drop; // seccomp drop list 112 char *seccomp_list_drop; // seccomp drop list
113 char *seccomp_list_keep; // seccomp keep list 113 char *seccomp_list_keep; // seccomp keep list
114 char **seccomp_list_errno; // seccomp errno[nr] lists 114 char **seccomp_list_errno; // seccomp errno[nr] lists
115 char *protocol; // protocol list
115 116
116 // rlimits 117 // rlimits
117 unsigned rlimit_nofile; 118 unsigned rlimit_nofile;
@@ -357,7 +358,7 @@ void caps_print_filter_name(const char *name);
357const char *syscall_find_nr(int nr); 358const char *syscall_find_nr(int nr);
358// return -1 if error, 0 if no error 359// return -1 if error, 0 if no error
359int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg); 360int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg);
360// print all available syscalls 361// print all available syscallsseccomp
361void syscall_print(void); 362void syscall_print(void);
362 363
363// fs_trace.c 364// fs_trace.c
@@ -427,5 +428,11 @@ void pulseaudio_disable(void);
427void fs_check_bin_list(void); 428void fs_check_bin_list(void);
428void fs_private_bin_list(void); 429void fs_private_bin_list(void);
429 430
431// protocol.c
432void protocol_list();
433void protocol_print_filter_name(const char *name);
434void protocol_print_filter(pid_t pid);
435void protocol_store(const char *prlist);
436void protocol_filter(void);
430#endif 437#endif
431 438
diff --git a/src/firejail/main.c b/src/firejail/main.c
index b59ff699c..e39a41502 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -308,7 +308,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
308 exit(0); 308 exit(0);
309 } 309 }
310 else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) { 310 else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) {
311 // join sandbox by pid or by name 311 // print seccomp filter for a sandbox specified by pid or by name
312 pid_t pid; 312 pid_t pid;
313 if (read_pid(argv[i] + 16, &pid) == 0) 313 if (read_pid(argv[i] + 16, &pid) == 0)
314 seccomp_print_filter(pid); 314 seccomp_print_filter(pid);
@@ -316,6 +316,19 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
316 seccomp_print_filter_name(argv[i] + 16); 316 seccomp_print_filter_name(argv[i] + 16);
317 exit(0); 317 exit(0);
318 } 318 }
319 else if (strcmp(argv[i], "--debug-protocols") == 0) {
320 protocol_list();
321 exit(0);
322 }
323 else if (strncmp(argv[i], "--protocol.print=", 17) == 0) {
324 // print seccomp filter for a sandbox specified by pid or by name
325 pid_t pid;
326 if (read_pid(argv[i] + 17, &pid) == 0)
327 protocol_print_filter(pid);
328 else
329 protocol_print_filter_name(argv[i] + 17);
330 exit(0);
331 }
319#endif 332#endif
320 else if (strncmp(argv[i], "--caps.print=", 13) == 0) { 333 else if (strncmp(argv[i], "--caps.print=", 13) == 0) {
321 // join sandbox by pid or by name 334 // join sandbox by pid or by name
@@ -451,6 +464,8 @@ int main(int argc, char **argv) {
451 // filtering 464 // filtering
452 //************************************* 465 //*************************************
453#ifdef HAVE_SECCOMP 466#ifdef HAVE_SECCOMP
467 else if (strncmp(argv[i], "--protocol=", 11) == 0)
468 protocol_store(argv[i] + 11);
454 else if (strcmp(argv[i], "--seccomp") == 0) { 469 else if (strcmp(argv[i], "--seccomp") == 0) {
455 if (arg_seccomp) { 470 if (arg_seccomp) {
456 fprintf(stderr, "Error: seccomp already enabled\n"); 471 fprintf(stderr, "Error: seccomp already enabled\n");
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c
new file mode 100644
index 000000000..098661339
--- /dev/null
+++ b/src/firejail/protocol.c
@@ -0,0 +1,240 @@
1/*
2 * Copyright (C) 2014, 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 "seccomp.h"
24#include <sys/types.h>
25#include <sys/socket.h>
26
27static char *protocol[] = {
28 "unix",
29 "inet",
30 "inet6",
31 "netlink",
32 "packet",
33 NULL
34};
35
36static struct sock_filter protocol_filter_command[] = {
37 WHITELIST(AF_UNIX),
38 WHITELIST(AF_INET),
39 WHITELIST(AF_INET6),
40 WHITELIST(AF_NETLINK),
41 WHITELIST(AF_PACKET)
42};
43// Note: protocol[] and protocol_filter_command are synchronized
44
45// command length
46struct sock_filter whitelist[] = {
47 WHITELIST(AF_UNIX)
48};
49unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter);
50
51
52
53static int is_protocol(const char *p) {
54 int i = 0;
55 while (protocol[i] != NULL) {
56 if (strcmp(protocol[i], p) == 0)
57 return 1;
58 i++;
59 }
60
61 return 0;
62}
63
64static struct sock_filter *find_protocol_domain(const char *p) {
65 int i = 0;
66 while (protocol[i] != NULL) {
67 if (strcmp(protocol[i], p) == 0)
68 return &protocol_filter_command[i * whitelist_len];
69 i++;
70 }
71
72 return NULL;
73}
74
75// --debug-protocols
76void protocol_list(void) {
77 int i = 0;
78 while (protocol[i] != NULL) {
79 printf("%s, ", protocol[i]);
80 i++;
81 }
82 printf("\n");
83}
84
85// --protocol.print
86void protocol_print_filter_name(const char *name) {
87 (void) name;
88//todo
89}
90
91// --protocol.print
92void protocol_print_filter(pid_t pid) {
93 (void) pid;
94//todo
95}
96
97// check protocol list and store it in cfg structure
98void protocol_store(const char *prlist) {
99 assert(prlist);
100
101 // temporary list
102 char *tmplist = strdup(prlist);
103 if (!tmplist)
104 errExit("strdup");
105
106 // check list
107 char *token = strtok(tmplist, ",");
108 if (!token)
109 goto errout;
110
111 while (token) {
112 if (!is_protocol(token))
113 goto errout;
114 token = strtok(NULL, ",");
115 }
116 free(tmplist);
117
118 // store list
119 cfg.protocol = strdup(prlist);
120 if (!cfg.protocol)
121 errExit("strdup");
122 return;
123
124errout:
125 fprintf(stderr, "Error: invalid protocol list\n");
126 exit(1);
127}
128
129// install protocol filter
130void protocol_filter(void) {
131 assert(cfg.protocol);
132
133 // build the filter
134
135 struct sock_filter filter[32]; // big enough
136 memset(&filter[0], 0, sizeof(filter));
137 uint8_t *ptr = (uint8_t *) &filter[0];
138
139 // header
140 struct sock_filter filter_start[] = {
141 VALIDATE_ARCHITECTURE,
142 EXAMINE_SYSCALL,
143 ONLY(SYS_socket),
144 EXAMINE_ARGUMENT(0)
145 };
146 memcpy(ptr, &filter_start[0], sizeof(filter_start));
147 ptr += sizeof(filter_start);
148
149#if 0
150printf("entries %u\n", (unsigned) (sizeof(filter_start) / sizeof(struct sock_filter)));
151{
152 unsigned j;
153 unsigned char *ptr2 = (unsigned char *) &filter[0];
154 for (j = 0; j < sizeof(filter); j++, ptr2++) {
155 if ((j % (sizeof(struct sock_filter))) == 0)
156 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
157 printf("%02x, ", (*ptr2) & 0xff);
158 }
159 printf("\n");
160}
161#endif
162
163printf("whitelist_len %u, struct sock_filter len %u\n", whitelist_len, (unsigned) sizeof(struct sock_filter));
164
165 // parse list and add commands
166 char *tmplist = strdup(cfg.protocol);
167 if (!tmplist)
168 errExit("strdup");
169 char *token = strtok(tmplist, ",");
170 if (!token)
171 errExit("strtok");
172
173 while (token) {
174 struct sock_filter *domain = find_protocol_domain(token);
175 assert(domain);
176 memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter));
177 ptr += whitelist_len * sizeof(struct sock_filter);
178 token = strtok(NULL, ",");
179
180#if 0
181printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
182{
183 unsigned j;
184 unsigned char *ptr2 = (unsigned char *) &filter[0];
185 for (j = 0; j < sizeof(filter); j++, ptr2++) {
186 if ((j % (sizeof(struct sock_filter))) == 0)
187 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
188 printf("%02x, ", (*ptr2) & 0xff);
189 }
190 printf("\n");
191}
192#endif
193
194
195 }
196 free(tmplist);
197
198 // add end of filter
199 struct sock_filter filter_end[] = {
200 RETURN_ERRNO(ENOTSUP)
201 };
202 memcpy(ptr, &filter_end[0], sizeof(filter_end));
203 ptr += sizeof(filter_end);
204
205#if 0
206printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
207{
208 unsigned j;
209 unsigned char *ptr2 = (unsigned char *) &filter[0];
210 for (j = 0; j < sizeof(filter); j++, ptr2++) {
211 if ((j % (sizeof(struct sock_filter))) == 0)
212 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
213 printf("%02x, ", (*ptr2) & 0xff);
214 }
215 printf("\n");
216}
217#endif
218
219 // install filter
220 unsigned short entries = (unsigned short) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter);
221 struct sock_fprog prog = {
222 .len = entries,
223 .filter = filter,
224 };
225
226 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
227 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
228 return;
229 }
230 else if (arg_debug) {
231 printf("seccomp protocol filter enabled\n");
232 }
233
234#if defined(__x86_64__)
235
236#endif
237
238}
239
240#endif
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index d2c943ea1..427b3fc09 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -426,6 +426,11 @@ int sandbox(void* sandbox_arg) {
426 426
427 // set seccomp 427 // set seccomp
428#ifdef HAVE_SECCOMP 428#ifdef HAVE_SECCOMP
429 // install protocol filter
430 if (cfg.protocol) {
431 protocol_filter();
432 }
433
429 // if a keep list is available, disregard the drop list 434 // if a keep list is available, disregard the drop list
430 if (arg_seccomp == 1) { 435 if (arg_seccomp == 1) {
431 if (cfg.seccomp_list_keep) 436 if (cfg.seccomp_list_keep)
diff --git a/src/firejail/seccomp.h b/src/firejail/seccomp.h
index 19684d4a9..b83fe87ce 100644
--- a/src/firejail/seccomp.h
+++ b/src/firejail/seccomp.h
@@ -92,15 +92,26 @@ struct seccomp_data {
92# define ARCH_NR 0 92# define ARCH_NR 0
93#endif 93#endif
94 94
95
96#define VALIDATE_ARCHITECTURE \ 95#define VALIDATE_ARCHITECTURE \
97 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ 96 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \
98 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ 97 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
99 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 98 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
100 99
100#define VALIDATE_ARCHITECTURE_32_64 \
101 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \
102 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
103 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
104
101#define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ 105#define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
102 (offsetof(struct seccomp_data, nr))) 106 (offsetof(struct seccomp_data, nr)))
103 107
108#define EXAMINE_ARGUMENT(nr) BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
109 (offsetof(struct seccomp_data, args[nr])))
110
111#define ONLY(syscall_nr) \
112 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 1, 0), \
113 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
114
104#define BLACKLIST(syscall_nr) \ 115#define BLACKLIST(syscall_nr) \
105 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ 116 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \
106 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) 117 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
@@ -116,6 +127,9 @@ struct seccomp_data {
116#define RETURN_ALLOW \ 127#define RETURN_ALLOW \
117 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 128 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
118 129
130#define RETURN_ERRNO(nr) \
131 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr)
132
119#define KILL_PROCESS \ 133#define KILL_PROCESS \
120 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) 134 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
121 135