summaryrefslogtreecommitdiffstats
path: root/src/firejail/protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/protocol.c')
-rw-r--r--src/firejail/protocol.c247
1 files changed, 25 insertions, 222 deletions
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c
index 6321c703a..43f30e30a 100644
--- a/src/firejail/protocol.c
+++ b/src/firejail/protocol.c
@@ -18,241 +18,44 @@
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 20
21/*
22 struct sock_filter filter[] = {
23 VALIDATE_ARCHITECTURE,
24 EXAMINE_SYSCALL,
25 ONLY(SYS_socket),
26 EXAMINE_ARGUMENT(0), // allow only AF_INET and AF_INET6, drop everything else
27 WHITELIST(AF_INET),
28 WHITELIST(AF_INET6),
29 WHITELIST(AF_PACKET),
30 RETURN_ERRNO(ENOTSUP)
31 };
32 struct sock_fprog prog = {
33 .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
34 .filter = filter,
35 };
36
37
38 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
39 perror("prctl(NO_NEW_PRIVS)");
40 return 1;
41 }
42 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
43 perror("prctl");
44 return 1;
45 }
46*/
47
48#ifdef HAVE_SECCOMP 21#ifdef HAVE_SECCOMP
49#include "firejail.h" 22#include "firejail.h"
50#include "../include/seccomp.h" 23#include "../include/seccomp.h"
51#include <sys/types.h>
52#include <sys/socket.h>
53
54static char *protocol[] = {
55 "unix",
56 "inet",
57 "inet6",
58 "netlink",
59 "packet",
60 NULL
61};
62
63static struct sock_filter protocol_filter_command[] = {
64 WHITELIST(AF_UNIX),
65 WHITELIST(AF_INET),
66 WHITELIST(AF_INET6),
67 WHITELIST(AF_NETLINK),
68 WHITELIST(AF_PACKET)
69};
70// Note: protocol[] and protocol_filter_command are synchronized
71
72// command length
73struct sock_filter whitelist[] = {
74 WHITELIST(AF_UNIX)
75};
76unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter);
77
78 24
79 25// install protocol filter
80static int is_protocol(const char *p) { 26void protocol_filter(const char *fname) {
81 int i = 0;
82 while (protocol[i] != NULL) {
83 if (strcmp(protocol[i], p) == 0)
84 return 1;
85 i++;
86 }
87
88 return 0;
89}
90
91static struct sock_filter *find_protocol_domain(const char *p) {
92 int i = 0;
93 while (protocol[i] != NULL) {
94 if (strcmp(protocol[i], p) == 0)
95 return &protocol_filter_command[i * whitelist_len];
96 i++;
97 }
98
99 return NULL;
100}
101
102// --debug-protocols
103void protocol_list(void) {
104 EUID_ASSERT();
105
106#ifndef SYS_socket 27#ifndef SYS_socket
107 fprintf(stderr, "Warning: --protocol not supported on this platform\n"); 28 if (arg_debug)
29 printf("No support for --protocol on this platform\n");
108 return; 30 return;
109#endif 31#else
110 32 assert(fname);
111 int i = 0;
112 while (protocol[i] != NULL) {
113 printf("%s, ", protocol[i]);
114 i++;
115 }
116 printf("\n");
117}
118
119 33
120// check protocol list and store it in cfg structure 34 // check file
121void protocol_store(const char *prlist) { 35 struct stat s;
122 EUID_ASSERT(); 36 if (stat(fname, &s) == -1) {
123 assert(prlist); 37 fprintf(stderr, "Error: cannot read protocol filter file\n");
124 38 exit(1);
125 if (cfg.protocol && !arg_quiet) {
126 fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", prlist);
127 return;
128 } 39 }
129 40 int size = s.st_size;
130 // temporary list
131 char *tmplist = strdup(prlist);
132 if (!tmplist)
133 errExit("strdup");
134
135 // check list
136 char *token = strtok(tmplist, ",");
137 if (!token)
138 goto errout;
139
140 while (token) {
141 if (!is_protocol(token))
142 goto errout;
143 token = strtok(NULL, ",");
144 }
145 free(tmplist);
146
147 // store list
148 cfg.protocol = strdup(prlist);
149 if (!cfg.protocol)
150 errExit("strdup");
151 return;
152
153errout:
154 fprintf(stderr, "Error: invalid protocol list\n");
155 exit(1);
156}
157 41
158// install protocol filter 42 // read filter
159void protocol_filter(void) {
160 assert(cfg.protocol);
161 if (arg_debug)
162 printf("Set protocol filter: %s\n", cfg.protocol);
163
164#ifndef SYS_socket
165 (void) find_protocol_domain;
166 fprintf(stderr, "Warning: --protocol not supported on this platform\n");
167 return;
168#else
169 // build the filter
170 struct sock_filter filter[32]; // big enough 43 struct sock_filter filter[32]; // big enough
171 memset(&filter[0], 0, sizeof(filter)); 44 memset(&filter[0], 0, sizeof(filter));
172 uint8_t *ptr = (uint8_t *) &filter[0]; 45 int src = open(fname, O_RDONLY);
173 46 int rd = 0;
174 // header 47 while (rd < size) {
175 struct sock_filter filter_start[] = { 48 int rv = read(src, (unsigned char *) filter + rd, size - rd);
176 VALIDATE_ARCHITECTURE, 49 if (rv == -1) {
177 EXAMINE_SYSCALL, 50 fprintf(stderr, "Error: cannot read %s file\n", fname);
178 ONLY(SYS_socket), 51 exit(1);
179 EXAMINE_ARGUMENT(0) 52 }
180 }; 53 rd += rv;
181 memcpy(ptr, &filter_start[0], sizeof(filter_start));
182 ptr += sizeof(filter_start);
183
184#if 0
185printf("entries %u\n", (unsigned) (sizeof(filter_start) / sizeof(struct sock_filter)));
186{
187 unsigned j;
188 unsigned char *ptr2 = (unsigned char *) &filter[0];
189 for (j = 0; j < sizeof(filter); j++, ptr2++) {
190 if ((j % (sizeof(struct sock_filter))) == 0)
191 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
192 printf("%02x, ", (*ptr2) & 0xff);
193 }
194 printf("\n");
195}
196printf("whitelist_len %u, struct sock_filter len %u\n", whitelist_len, (unsigned) sizeof(struct sock_filter));
197#endif
198
199
200 // parse list and add commands
201 char *tmplist = strdup(cfg.protocol);
202 if (!tmplist)
203 errExit("strdup");
204 char *token = strtok(tmplist, ",");
205 if (!token)
206 errExit("strtok");
207
208 while (token) {
209 struct sock_filter *domain = find_protocol_domain(token);
210 assert(domain);
211 memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter));
212 ptr += whitelist_len * sizeof(struct sock_filter);
213 token = strtok(NULL, ",");
214
215#if 0
216printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
217{
218 unsigned j;
219 unsigned char *ptr2 = (unsigned char *) &filter[0];
220 for (j = 0; j < sizeof(filter); j++, ptr2++) {
221 if ((j % (sizeof(struct sock_filter))) == 0)
222 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
223 printf("%02x, ", (*ptr2) & 0xff);
224 }
225 printf("\n");
226}
227#endif
228
229
230 }
231 free(tmplist);
232
233 // add end of filter
234 struct sock_filter filter_end[] = {
235 RETURN_ERRNO(ENOTSUP)
236 };
237 memcpy(ptr, &filter_end[0], sizeof(filter_end));
238 ptr += sizeof(filter_end);
239
240#if 0
241printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
242{
243 unsigned j;
244 unsigned char *ptr2 = (unsigned char *) &filter[0];
245 for (j = 0; j < sizeof(filter); j++, ptr2++) {
246 if ((j % (sizeof(struct sock_filter))) == 0)
247 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
248 printf("%02x, ", (*ptr2) & 0xff);
249 } 54 }
250 printf("\n"); 55 close(src);
251}
252#endif
253 56
254 // install filter 57 // install filter
255 unsigned short entries = (unsigned short) ((uintptr_t) ptr - (uintptr_t) (filter)) / (unsigned) sizeof(struct sock_filter); 58 unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter);
256 struct sock_fprog prog = { 59 struct sock_fprog prog = {
257 .len = entries, 60 .len = entries,
258 .filter = filter, 61 .filter = filter,
@@ -262,7 +65,7 @@ printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (uns
262 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); 65 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
263 return; 66 return;
264 } 67 }
265#endif // SYS_socket 68#endif
266} 69}
267 70
268void protocol_filter_save(void) { 71void protocol_filter_save(void) {