diff options
author | netblue30 <netblue30@yahoo.com> | 2016-01-13 11:08:04 -0500 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2016-01-13 11:08:04 -0500 |
commit | bad6d369aeb682ba07d018927154cc833f0b9db6 (patch) | |
tree | 242e49b6349d23190d6ebc65677e71aaea4d215e | |
parent | added kmail profile (diff) | |
download | firejail-bad6d369aeb682ba07d018927154cc833f0b9db6.tar.gz firejail-bad6d369aeb682ba07d018927154cc833f0b9db6.tar.zst firejail-bad6d369aeb682ba07d018927154cc833f0b9db6.zip |
ipv6 support
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/main.c | 7 | ||||
-rw-r--r-- | src/firejail/netfilter.c | 111 | ||||
-rw-r--r-- | src/firejail/profile.c | 8 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 3 | ||||
-rw-r--r-- | src/firejail/usage.c | 3 | ||||
-rw-r--r-- | src/man/firejail.txt | 6 | ||||
-rwxr-xr-x | test/ip6.exp | 46 | ||||
-rw-r--r-- | test/ipv6.net | 8 | ||||
-rwxr-xr-x | test/test.sh | 3 |
10 files changed, 194 insertions, 3 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 15110607d..6b497559d 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -215,7 +215,9 @@ extern int arg_rlimit_sigpending;// rlimit sigpending | |||
215 | extern int arg_nogroups; // disable supplementary groups | 215 | extern int arg_nogroups; // disable supplementary groups |
216 | extern int arg_noroot; // create a new user namespace and disable root user | 216 | extern int arg_noroot; // create a new user namespace and disable root user |
217 | extern int arg_netfilter; // enable netfilter | 217 | extern int arg_netfilter; // enable netfilter |
218 | extern int arg_netfilter6; // enable netfilter6 | ||
218 | extern char *arg_netfilter_file; // netfilter file | 219 | extern char *arg_netfilter_file; // netfilter file |
220 | extern char *arg_netfilter6_file; // netfilter file | ||
219 | extern int arg_doubledash; // double dash | 221 | extern int arg_doubledash; // double dash |
220 | extern int arg_shell_none; // run the program directly without a shell | 222 | extern int arg_shell_none; // run the program directly without a shell |
221 | extern int arg_private_dev; // private dev directory | 223 | extern int arg_private_dev; // private dev directory |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 7b493a351..246ee4bba 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -77,7 +77,9 @@ int arg_rlimit_sigpending = 0; // rlimit fsize | |||
77 | int arg_nogroups = 0; // disable supplementary groups | 77 | int arg_nogroups = 0; // disable supplementary groups |
78 | int arg_noroot = 0; // create a new user namespace and disable root user | 78 | int arg_noroot = 0; // create a new user namespace and disable root user |
79 | int arg_netfilter; // enable netfilter | 79 | int arg_netfilter; // enable netfilter |
80 | int arg_netfilter6; // enable netfilter6 | ||
80 | char *arg_netfilter_file = NULL; // netfilter file | 81 | char *arg_netfilter_file = NULL; // netfilter file |
82 | char *arg_netfilter6_file = NULL; // netfilter6 file | ||
81 | int arg_doubledash = 0; // double dash | 83 | int arg_doubledash = 0; // double dash |
82 | int arg_shell_none = 0; // run the program directly without a shell | 84 | int arg_shell_none = 0; // run the program directly without a shell |
83 | int arg_private_dev = 0; // private dev directory | 85 | int arg_private_dev = 0; // private dev directory |
@@ -1147,6 +1149,11 @@ int main(int argc, char **argv) { | |||
1147 | arg_netfilter_file = argv[i] + 12; | 1149 | arg_netfilter_file = argv[i] + 12; |
1148 | check_netfilter_file(arg_netfilter_file); | 1150 | check_netfilter_file(arg_netfilter_file); |
1149 | } | 1151 | } |
1152 | else if (strncmp(argv[i], "--netfilter6=", 13) == 0) { | ||
1153 | arg_netfilter6 = 1; | ||
1154 | arg_netfilter6_file = argv[i] + 13; | ||
1155 | check_netfilter_file(arg_netfilter6_file); | ||
1156 | } | ||
1150 | 1157 | ||
1151 | //************************************* | 1158 | //************************************* |
1152 | // command | 1159 | // command |
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c index 3f667c871..70fd8801f 100644 --- a/src/firejail/netfilter.c +++ b/src/firejail/netfilter.c | |||
@@ -64,7 +64,7 @@ void netfilter(const char *fname) { | |||
64 | // buffer the filter | 64 | // buffer the filter |
65 | struct stat s; | 65 | struct stat s; |
66 | if (stat(fname, &s) == -1) { | 66 | if (stat(fname, &s) == -1) { |
67 | fprintf(stderr, "Error: cannot find network filter file\n"); | 67 | fprintf(stderr, "Error: cannot find network filter file %s\n", fname); |
68 | exit(1); | 68 | exit(1); |
69 | } | 69 | } |
70 | 70 | ||
@@ -76,13 +76,13 @@ void netfilter(const char *fname) { | |||
76 | /* coverity[toctou] */ | 76 | /* coverity[toctou] */ |
77 | FILE *fp = fopen(fname, "r"); | 77 | FILE *fp = fopen(fname, "r"); |
78 | if (!fp) { | 78 | if (!fp) { |
79 | fprintf(stderr, "Error: cannot open network filter file\n"); | 79 | fprintf(stderr, "Error: cannot open network filter file %s\n", fname); |
80 | exit(1); | 80 | exit(1); |
81 | } | 81 | } |
82 | 82 | ||
83 | size_t sz = fread(filter, 1, s.st_size, fp); | 83 | size_t sz = fread(filter, 1, s.st_size, fp); |
84 | if ((off_t)sz != s.st_size) { | 84 | if ((off_t)sz != s.st_size) { |
85 | fprintf(stderr, "Error: cannot read network filter file\n"); | 85 | fprintf(stderr, "Error: cannot read network filter file %s\n", fname); |
86 | exit(1); | 86 | exit(1); |
87 | } | 87 | } |
88 | fclose(fp); | 88 | fclose(fp); |
@@ -164,3 +164,108 @@ doexit: | |||
164 | if (allocated) | 164 | if (allocated) |
165 | free(filter); | 165 | free(filter); |
166 | } | 166 | } |
167 | |||
168 | void netfilter6(const char *fname) { | ||
169 | if (fname == NULL) | ||
170 | return; | ||
171 | |||
172 | char *filter; | ||
173 | |||
174 | // buffer the filter | ||
175 | struct stat s; | ||
176 | if (stat(fname, &s) == -1) { | ||
177 | fprintf(stderr, "Error: cannot find network filter file %s\n", fname); | ||
178 | exit(1); | ||
179 | } | ||
180 | |||
181 | filter = malloc(s.st_size + 1); // + '\0' | ||
182 | if (!filter) | ||
183 | errExit("malloc"); | ||
184 | memset(filter, 0, s.st_size + 1); | ||
185 | |||
186 | /* coverity[toctou] */ | ||
187 | FILE *fp = fopen(fname, "r"); | ||
188 | if (!fp) { | ||
189 | fprintf(stderr, "Error: cannot open network filter file %s\n", fname); | ||
190 | exit(1); | ||
191 | } | ||
192 | |||
193 | size_t sz = fread(filter, 1, s.st_size, fp); | ||
194 | if ((off_t)sz != s.st_size) { | ||
195 | fprintf(stderr, "Error: cannot read network filter file %s\n", fname); | ||
196 | exit(1); | ||
197 | } | ||
198 | fclose(fp); | ||
199 | |||
200 | // temporarily mount a tempfs on top of /tmp directory | ||
201 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
202 | errExit("mounting /tmp"); | ||
203 | |||
204 | // create the filter file | ||
205 | fp = fopen("/tmp/netfilter6", "w"); | ||
206 | if (!fp) { | ||
207 | fprintf(stderr, "Error: cannot open /tmp/netfilter6 file\n"); | ||
208 | exit(1); | ||
209 | } | ||
210 | fprintf(fp, "%s\n", filter); | ||
211 | fclose(fp); | ||
212 | |||
213 | // find iptables command | ||
214 | char *ip6tables = NULL; | ||
215 | char *ip6tables_restore = NULL; | ||
216 | if (stat("/sbin/ip6tables", &s) == 0) { | ||
217 | ip6tables = "/sbin/ip6tables"; | ||
218 | ip6tables_restore = "/sbin/ip6tables-restore"; | ||
219 | } | ||
220 | else if (stat("/usr/sbin/ip6tables", &s) == 0) { | ||
221 | ip6tables = "/usr/sbin/ip6tables"; | ||
222 | ip6tables_restore = "/usr/sbin/ip6tables-restore"; | ||
223 | } | ||
224 | if (ip6tables == NULL || ip6tables_restore == NULL) { | ||
225 | fprintf(stderr, "Error: ip6tables command not found\n"); | ||
226 | goto doexit; | ||
227 | } | ||
228 | |||
229 | // push filter | ||
230 | pid_t child = fork(); | ||
231 | if (child < 0) | ||
232 | errExit("fork"); | ||
233 | if (child == 0) { | ||
234 | if (arg_debug) | ||
235 | printf("Installing network filter:\n%s\n", filter); | ||
236 | |||
237 | int fd; | ||
238 | if((fd = open("/tmp/netfilter6", O_RDONLY)) == -1) { | ||
239 | fprintf(stderr,"Error: cannot open /tmp/netfilter6\n"); | ||
240 | exit(1); | ||
241 | } | ||
242 | dup2(fd,STDIN_FILENO); | ||
243 | close(fd); | ||
244 | |||
245 | // wipe out environment variables | ||
246 | environ = NULL; | ||
247 | execl(ip6tables_restore, ip6tables_restore, NULL); | ||
248 | // it will never get here!!! | ||
249 | } | ||
250 | // wait for the child to finish | ||
251 | waitpid(child, NULL, 0); | ||
252 | |||
253 | // debug | ||
254 | if (arg_debug) { | ||
255 | child = fork(); | ||
256 | if (child < 0) | ||
257 | errExit("fork"); | ||
258 | if (child == 0) { | ||
259 | environ = NULL; | ||
260 | execl(ip6tables, ip6tables, "-vL", NULL); | ||
261 | // it will never get here!!! | ||
262 | } | ||
263 | // wait for the child to finish | ||
264 | waitpid(child, NULL, 0); | ||
265 | } | ||
266 | |||
267 | doexit: | ||
268 | // unmount /tmp | ||
269 | umount("/tmp"); | ||
270 | free(filter); | ||
271 | } | ||
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 0f6d49868..6286bfe0f 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -157,6 +157,14 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
157 | check_netfilter_file(arg_netfilter_file); | 157 | check_netfilter_file(arg_netfilter_file); |
158 | return 0; | 158 | return 0; |
159 | } | 159 | } |
160 | else if (strncmp(ptr, "netfilter6 ", 11) == 0) { | ||
161 | arg_netfilter6 = 1; | ||
162 | arg_netfilter6_file = strdup(ptr + 11); | ||
163 | if (!arg_netfilter6_file) | ||
164 | errExit("strdup"); | ||
165 | check_netfilter_file(arg_netfilter6_file); | ||
166 | return 0; | ||
167 | } | ||
160 | else if (strcmp(ptr, "net none") == 0) { | 168 | else if (strcmp(ptr, "net none") == 0) { |
161 | arg_nonetwork = 1; | 169 | arg_nonetwork = 1; |
162 | cfg.bridge0.configured = 0; | 170 | cfg.bridge0.configured = 0; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index ac0f62dab..e317579e9 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -322,6 +322,9 @@ int sandbox(void* sandbox_arg) { | |||
322 | if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter | 322 | if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter |
323 | netfilter(arg_netfilter_file); | 323 | netfilter(arg_netfilter_file); |
324 | } | 324 | } |
325 | if (arg_netfilter6 && any_bridge_configured()) { // assuming by default the client filter | ||
326 | netfilter6(arg_netfilter6_file); | ||
327 | } | ||
325 | 328 | ||
326 | // load IBUS env variables | 329 | // load IBUS env variables |
327 | if (arg_nonetwork || any_bridge_configured() || any_interface_configured()) { | 330 | if (arg_nonetwork || any_bridge_configured() || any_interface_configured()) { |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 5eab05076..07ab04021 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -149,6 +149,9 @@ void usage(void) { | |||
149 | printf("\t--netfilter=filename - enable the network filter specified by\n"); | 149 | printf("\t--netfilter=filename - enable the network filter specified by\n"); |
150 | printf("\t\tfilename in the new network namespace. The filter file format\n"); | 150 | printf("\t\tfilename in the new network namespace. The filter file format\n"); |
151 | printf("\t\tis the format of iptables-save and iptable-restore commands.\n\n"); | 151 | printf("\t\tis the format of iptables-save and iptable-restore commands.\n\n"); |
152 | printf("\t--netfilter6=filename - enable the IPv6 network filter specified by\n"); | ||
153 | printf("\t\tfilename in the new network namespace. The filter file format\n"); | ||
154 | printf("\t\tis the format of ip6tables-save and ip6table-restore commands.\n\n"); | ||
152 | 155 | ||
153 | printf("\t--netstats - monitor network statistics for sandboxes creating a new\n"); | 156 | printf("\t--netstats - monitor network statistics for sandboxes creating a new\n"); |
154 | printf("\t\tnetwork namespace.\n\n"); | 157 | printf("\t\tnetwork namespace.\n\n"); |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index c8dd7d786..75e962b56 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -691,6 +691,12 @@ $ firejail --netfilter=/etc/firejail/nolocal.net \\ | |||
691 | .br | 691 | .br |
692 | --net=eth0 firefox | 692 | --net=eth0 firefox |
693 | .TP | 693 | .TP |
694 | \fB\-\-netfilter6=filename | ||
695 | Enable the IPv6 network filter specified by filename in the new network namespace. The filter file format | ||
696 | is the format of ip6tables-save and ip6table-restore commands. | ||
697 | New network namespaces are created using \-\-net option. If a new network namespaces is not created, | ||
698 | \-\-netfilter6 option does nothing. | ||
699 | .TP | ||
694 | \fB\-\-netstats | 700 | \fB\-\-netstats |
695 | Monitor network namespace statistics, see \fBMONITORING\fR section for more details. | 701 | Monitor network namespace statistics, see \fBMONITORING\fR section for more details. |
696 | .br | 702 | .br |
diff --git a/test/ip6.exp b/test/ip6.exp new file mode 100755 index 000000000..4dc11d3dc --- /dev/null +++ b/test/ip6.exp | |||
@@ -0,0 +1,46 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | |||
3 | set timeout 10 | ||
4 | spawn $env(SHELL) | ||
5 | match_max 100000 | ||
6 | |||
7 | send -- "firejail --debug --noprofile --net=eth0 --ip6=2001:0db8:0:f101::1/64 --netfilter6=ipv6.net\r" | ||
8 | expect { | ||
9 | timeout {puts "TESTING ERROR 0\n";exit} | ||
10 | "Installing network filter" | ||
11 | } | ||
12 | expect { | ||
13 | timeout {puts "TESTING ERROR 1\n";exit} | ||
14 | "DROP" | ||
15 | } | ||
16 | expect { | ||
17 | timeout {puts "TESTING ERROR 1\n";exit} | ||
18 | "DROP" | ||
19 | } | ||
20 | expect { | ||
21 | timeout {puts "TESTING ERROR 1\n";exit} | ||
22 | "2001:db8:1f0a:3ec::2/128" | ||
23 | } | ||
24 | expect { | ||
25 | timeout {puts "TESTING ERROR 1\n";exit} | ||
26 | "Child process initialized" | ||
27 | } | ||
28 | sleep 2 | ||
29 | |||
30 | send -- "/sbin/ifconfig\r" | ||
31 | expect { | ||
32 | timeout {puts "TESTING ERROR 1\n";exit} | ||
33 | "inet6 addr" | ||
34 | } | ||
35 | expect { | ||
36 | timeout {puts "TESTING ERROR 1\n";exit} | ||
37 | "2001:db8:0:f101::1/64" | ||
38 | } | ||
39 | expect { | ||
40 | timeout {puts "TESTING ERROR 1\n";exit} | ||
41 | "Scope:Global" | ||
42 | } | ||
43 | |||
44 | |||
45 | puts "\nall done\n" | ||
46 | |||
diff --git a/test/ipv6.net b/test/ipv6.net new file mode 100644 index 000000000..cc8f22943 --- /dev/null +++ b/test/ipv6.net | |||
@@ -0,0 +1,8 @@ | |||
1 | # Generated by ip6tables-save v1.4.14 on Wed Jan 13 10:53:40 2016 | ||
2 | *filter | ||
3 | :INPUT ACCEPT [0:0] | ||
4 | :FORWARD ACCEPT [0:0] | ||
5 | :OUTPUT ACCEPT [0:0] | ||
6 | -A INPUT -s 2001:db8:1f0a:3ec::2/128 -j DROP | ||
7 | COMMIT | ||
8 | # Completed on Wed Jan 13 10:53:40 2016 | ||
diff --git a/test/test.sh b/test/test.sh index ab288cbeb..44bb7ba99 100755 --- a/test/test.sh +++ b/test/test.sh | |||
@@ -256,6 +256,9 @@ echo "TESTING: read/write /dev/shm" | |||
256 | echo "TESTING: quiet" | 256 | echo "TESTING: quiet" |
257 | ./quiet.exp | 257 | ./quiet.exp |
258 | 258 | ||
259 | echo "TESTING: IPv6 support" | ||
260 | ./ip6.exp | ||
261 | |||
259 | echo "TESTING: local network" | 262 | echo "TESTING: local network" |
260 | ./net_local.exp | 263 | ./net_local.exp |
261 | 264 | ||