aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-01-13 11:08:04 -0500
committerLibravatar netblue30 <netblue30@yahoo.com>2016-01-13 11:08:04 -0500
commitbad6d369aeb682ba07d018927154cc833f0b9db6 (patch)
tree242e49b6349d23190d6ebc65677e71aaea4d215e
parentadded kmail profile (diff)
downloadfirejail-bad6d369aeb682ba07d018927154cc833f0b9db6.tar.gz
firejail-bad6d369aeb682ba07d018927154cc833f0b9db6.tar.zst
firejail-bad6d369aeb682ba07d018927154cc833f0b9db6.zip
ipv6 support
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/main.c7
-rw-r--r--src/firejail/netfilter.c111
-rw-r--r--src/firejail/profile.c8
-rw-r--r--src/firejail/sandbox.c3
-rw-r--r--src/firejail/usage.c3
-rw-r--r--src/man/firejail.txt6
-rwxr-xr-xtest/ip6.exp46
-rw-r--r--test/ipv6.net8
-rwxr-xr-xtest/test.sh3
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
215extern int arg_nogroups; // disable supplementary groups 215extern int arg_nogroups; // disable supplementary groups
216extern int arg_noroot; // create a new user namespace and disable root user 216extern int arg_noroot; // create a new user namespace and disable root user
217extern int arg_netfilter; // enable netfilter 217extern int arg_netfilter; // enable netfilter
218extern int arg_netfilter6; // enable netfilter6
218extern char *arg_netfilter_file; // netfilter file 219extern char *arg_netfilter_file; // netfilter file
220extern char *arg_netfilter6_file; // netfilter file
219extern int arg_doubledash; // double dash 221extern int arg_doubledash; // double dash
220extern int arg_shell_none; // run the program directly without a shell 222extern int arg_shell_none; // run the program directly without a shell
221extern int arg_private_dev; // private dev directory 223extern 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
77int arg_nogroups = 0; // disable supplementary groups 77int arg_nogroups = 0; // disable supplementary groups
78int arg_noroot = 0; // create a new user namespace and disable root user 78int arg_noroot = 0; // create a new user namespace and disable root user
79int arg_netfilter; // enable netfilter 79int arg_netfilter; // enable netfilter
80int arg_netfilter6; // enable netfilter6
80char *arg_netfilter_file = NULL; // netfilter file 81char *arg_netfilter_file = NULL; // netfilter file
82char *arg_netfilter6_file = NULL; // netfilter6 file
81int arg_doubledash = 0; // double dash 83int arg_doubledash = 0; // double dash
82int arg_shell_none = 0; // run the program directly without a shell 84int arg_shell_none = 0; // run the program directly without a shell
83int arg_private_dev = 0; // private dev directory 85int 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
168void 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
267doexit:
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
695Enable the IPv6 network filter specified by filename in the new network namespace. The filter file format
696is the format of ip6tables-save and ip6table-restore commands.
697New 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
695Monitor network namespace statistics, see \fBMONITORING\fR section for more details. 701Monitor 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
3set timeout 10
4spawn $env(SHELL)
5match_max 100000
6
7send -- "firejail --debug --noprofile --net=eth0 --ip6=2001:0db8:0:f101::1/64 --netfilter6=ipv6.net\r"
8expect {
9 timeout {puts "TESTING ERROR 0\n";exit}
10 "Installing network filter"
11}
12expect {
13 timeout {puts "TESTING ERROR 1\n";exit}
14 "DROP"
15}
16expect {
17 timeout {puts "TESTING ERROR 1\n";exit}
18 "DROP"
19}
20expect {
21 timeout {puts "TESTING ERROR 1\n";exit}
22 "2001:db8:1f0a:3ec::2/128"
23}
24expect {
25 timeout {puts "TESTING ERROR 1\n";exit}
26 "Child process initialized"
27}
28sleep 2
29
30send -- "/sbin/ifconfig\r"
31expect {
32 timeout {puts "TESTING ERROR 1\n";exit}
33 "inet6 addr"
34}
35expect {
36 timeout {puts "TESTING ERROR 1\n";exit}
37 "2001:db8:0:f101::1/64"
38}
39expect {
40 timeout {puts "TESTING ERROR 1\n";exit}
41 "Scope:Global"
42}
43
44
45puts "\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
7COMMIT
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"
256echo "TESTING: quiet" 256echo "TESTING: quiet"
257./quiet.exp 257./quiet.exp
258 258
259echo "TESTING: IPv6 support"
260./ip6.exp
261
259echo "TESTING: local network" 262echo "TESTING: local network"
260./net_local.exp 263./net_local.exp
261 264