diff options
author | 2016-11-28 10:36:04 -0500 | |
---|---|---|
committer | 2016-11-28 10:36:04 -0500 | |
commit | d0c1fcfa273d323a26aa8477130e176dc2435bf5 (patch) | |
tree | 5c0823ed12cabf602ace114a12b53fb3b2872b99 /src/firejail/netfilter.c | |
parent | cleanup (diff) | |
download | firejail-d0c1fcfa273d323a26aa8477130e176dc2435bf5.tar.gz firejail-d0c1fcfa273d323a26aa8477130e176dc2435bf5.tar.zst firejail-d0c1fcfa273d323a26aa8477130e176dc2435bf5.zip |
netfilter rework
Diffstat (limited to 'src/firejail/netfilter.c')
-rw-r--r-- | src/firejail/netfilter.c | 233 |
1 files changed, 45 insertions, 188 deletions
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c index 43f08e45b..ef4915f15 100644 --- a/src/firejail/netfilter.c +++ b/src/firejail/netfilter.c | |||
@@ -61,59 +61,6 @@ void check_netfilter_file(const char *fname) { | |||
61 | 61 | ||
62 | 62 | ||
63 | void netfilter(const char *fname) { | 63 | void netfilter(const char *fname) { |
64 | // default filter | ||
65 | char *filter = client_filter; | ||
66 | |||
67 | // custom filter | ||
68 | int allocated = 0; | ||
69 | if (netfilter_default) | ||
70 | fname = netfilter_default; | ||
71 | if (fname) { | ||
72 | assert(fname); | ||
73 | |||
74 | // open filter file | ||
75 | int fd = open(fname, O_RDONLY); | ||
76 | if (fd == -1) | ||
77 | goto errexit; | ||
78 | int size = lseek(fd, 0, SEEK_END); | ||
79 | if (size == -1) | ||
80 | goto errexit; | ||
81 | if (lseek(fd, 0 , SEEK_SET) == -1) | ||
82 | goto errexit; | ||
83 | |||
84 | // read filter | ||
85 | filter = malloc(size + 1); // + '\0' | ||
86 | if (filter == NULL) | ||
87 | goto errexit; | ||
88 | memset(filter, 0, size + 1); | ||
89 | int rd = 0; | ||
90 | while (rd < size) { | ||
91 | int rv = read(fd, (unsigned char *) filter + rd, size - rd); | ||
92 | if (rv == -1) { | ||
93 | close(fd); | ||
94 | goto errexit; | ||
95 | } | ||
96 | rd += rv; | ||
97 | } | ||
98 | |||
99 | // close file | ||
100 | close(fd); | ||
101 | allocated = 1; | ||
102 | } | ||
103 | |||
104 | // temporarily mount a tempfs on top of /tmp directory | ||
105 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
106 | errExit("mounting /tmp"); | ||
107 | |||
108 | // create the filter file | ||
109 | FILE *fp = fopen("/tmp/netfilter", "w"); | ||
110 | if (!fp) { | ||
111 | fprintf(stderr, "Error: cannot open /tmp/netfilter file\n"); | ||
112 | exit(1); | ||
113 | } | ||
114 | fprintf(fp, "%s\n", filter); | ||
115 | fclose(fp); | ||
116 | |||
117 | // find iptables command | 64 | // find iptables command |
118 | struct stat s; | 65 | struct stat s; |
119 | char *iptables = NULL; | 66 | char *iptables = NULL; |
@@ -127,113 +74,49 @@ void netfilter(const char *fname) { | |||
127 | iptables_restore = "/usr/sbin/iptables-restore"; | 74 | iptables_restore = "/usr/sbin/iptables-restore"; |
128 | } | 75 | } |
129 | if (iptables == NULL || iptables_restore == NULL) { | 76 | if (iptables == NULL || iptables_restore == NULL) { |
130 | fprintf(stderr, "Error: iptables command not found\n"); | 77 | fprintf(stderr, "Error: iptables command not found, netfilter not configured\n"); |
131 | goto doexit; | 78 | return; |
132 | } | 79 | } |
133 | 80 | ||
134 | // push filter | 81 | // read filter |
135 | pid_t child = fork(); | 82 | char *filter = client_filter; |
136 | if (child < 0) | 83 | int allocated = 0; |
137 | errExit("fork"); | 84 | if (netfilter_default) |
138 | if (child == 0) { | 85 | fname = netfilter_default; |
139 | if (arg_debug) | 86 | if (fname) { |
140 | printf("Installing network filter:\n%s\n", filter); | 87 | filter = read_text_file_or_exit(fname); |
141 | 88 | allocated = 1; | |
142 | int fd; | ||
143 | if((fd = open("/tmp/netfilter", O_RDONLY)) == -1) { | ||
144 | fprintf(stderr,"Error: cannot open /tmp/netfilter\n"); | ||
145 | exit(1); | ||
146 | } | ||
147 | dup2(fd,STDIN_FILENO); | ||
148 | |||
149 | // wipe out environment variables | ||
150 | clearenv(); | ||
151 | execl(iptables_restore, iptables_restore, NULL); | ||
152 | perror("execl"); | ||
153 | _exit(1); | ||
154 | } | 89 | } |
155 | // wait for the child to finish | ||
156 | waitpid(child, NULL, 0); | ||
157 | 90 | ||
158 | // debug | 91 | // create the filter file |
159 | if (arg_debug) { | 92 | FILE *fp = fopen(SBOX_STDIN_FILE, "w"); |
160 | child = fork(); | 93 | if (!fp) { |
161 | if (child < 0) | 94 | fprintf(stderr, "Error: cannot open %s\n", SBOX_STDIN_FILE); |
162 | errExit("fork"); | 95 | exit(1); |
163 | if (child == 0) { | ||
164 | // elevate privileges in order to get grsecurity working | ||
165 | if (setreuid(0, 0)) | ||
166 | errExit("setreuid"); | ||
167 | if (setregid(0, 0)) | ||
168 | errExit("setregid"); | ||
169 | environ = NULL; | ||
170 | assert(getenv("LD_PRELOAD") == NULL); | ||
171 | execl(iptables, iptables, "-vL", NULL); | ||
172 | perror("execl"); | ||
173 | _exit(1); | ||
174 | } | ||
175 | // wait for the child to finish | ||
176 | waitpid(child, NULL, 0); | ||
177 | } | 96 | } |
97 | fprintf(fp, "%s\n", filter); | ||
98 | fclose(fp); | ||
99 | |||
178 | 100 | ||
179 | doexit: | 101 | // push filter |
180 | // unmount /tmp | 102 | if (arg_debug) |
181 | umount("/tmp"); | 103 | printf("Installing network filter:\n%s\n", filter); |
104 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP | SBOX_STDIN_FROM_FILE, 1, iptables_restore); | ||
105 | unlink(SBOX_STDIN_FILE); | ||
106 | |||
107 | // debug | ||
108 | if (arg_debug) | ||
109 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, iptables, "-vL"); | ||
182 | 110 | ||
183 | if (allocated) | 111 | if (allocated) |
184 | free(filter); | 112 | free(filter); |
185 | return; | 113 | return; |
186 | |||
187 | errexit: | ||
188 | fprintf(stderr, "Error: cannot read network filter %s\n", fname); | ||
189 | exit(1); | ||
190 | } | 114 | } |
191 | 115 | ||
192 | void netfilter6(const char *fname) { | 116 | void netfilter6(const char *fname) { |
193 | if (fname == NULL) | 117 | if (fname == NULL) |
194 | return; | 118 | return; |
195 | 119 | ||
196 | char *filter; | ||
197 | |||
198 | // open filter file | ||
199 | int fd = open(fname, O_RDONLY); | ||
200 | if (fd == -1) | ||
201 | goto errexit; | ||
202 | int size = lseek(fd, 0, SEEK_END); | ||
203 | if (size == -1) | ||
204 | goto errexit; | ||
205 | if (lseek(fd, 0 , SEEK_SET) == -1) | ||
206 | goto errexit; | ||
207 | |||
208 | // read filter | ||
209 | filter = malloc(size + 1); // + '\0' | ||
210 | if (filter == NULL) | ||
211 | goto errexit; | ||
212 | memset(filter, 0, size + 1); | ||
213 | int rd = 0; | ||
214 | while (rd < size) { | ||
215 | int rv = read(fd, (unsigned char *) filter + rd, size - rd); | ||
216 | if (rv == -1) | ||
217 | goto errexit; | ||
218 | rd += rv; | ||
219 | } | ||
220 | |||
221 | // close file | ||
222 | close(fd); | ||
223 | |||
224 | // temporarily mount a tempfs on top of /tmp directory | ||
225 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
226 | errExit("mounting /tmp"); | ||
227 | |||
228 | // create the filter file | ||
229 | FILE *fp = fopen("/tmp/netfilter6", "w"); | ||
230 | if (!fp) { | ||
231 | fprintf(stderr, "Error: cannot open /tmp/netfilter6 file\n"); | ||
232 | exit(1); | ||
233 | } | ||
234 | fprintf(fp, "%s\n", filter); | ||
235 | fclose(fp); | ||
236 | |||
237 | // find iptables command | 120 | // find iptables command |
238 | char *ip6tables = NULL; | 121 | char *ip6tables = NULL; |
239 | char *ip6tables_restore = NULL; | 122 | char *ip6tables_restore = NULL; |
@@ -247,56 +130,30 @@ void netfilter6(const char *fname) { | |||
247 | ip6tables_restore = "/usr/sbin/ip6tables-restore"; | 130 | ip6tables_restore = "/usr/sbin/ip6tables-restore"; |
248 | } | 131 | } |
249 | if (ip6tables == NULL || ip6tables_restore == NULL) { | 132 | if (ip6tables == NULL || ip6tables_restore == NULL) { |
250 | fprintf(stderr, "Error: ip6tables command not found\n"); | 133 | fprintf(stderr, "Error: ip6tables command not found, netfilter6 not configured\n"); |
251 | goto doexit; | 134 | return; |
252 | } | 135 | } |
253 | 136 | ||
254 | // push filter | 137 | // create the filter file |
255 | pid_t child = fork(); | 138 | char *filter = read_text_file_or_exit(fname); |
256 | if (child < 0) | 139 | FILE *fp = fopen(SBOX_STDIN_FILE, "w"); |
257 | errExit("fork"); | 140 | if (!fp) { |
258 | if (child == 0) { | 141 | fprintf(stderr, "Error: cannot open /tmp/netfilter6 file\n"); |
259 | if (arg_debug) | 142 | exit(1); |
260 | printf("Installing network filter:\n%s\n", filter); | ||
261 | |||
262 | int fd; | ||
263 | if((fd = open("/tmp/netfilter6", O_RDONLY)) == -1) { | ||
264 | fprintf(stderr,"Error: cannot open /tmp/netfilter6\n"); | ||
265 | exit(1); | ||
266 | } | ||
267 | dup2(fd,STDIN_FILENO); | ||
268 | |||
269 | // wipe out environment variables | ||
270 | clearenv(); | ||
271 | execl(ip6tables_restore, ip6tables_restore, NULL); | ||
272 | perror("execl"); | ||
273 | _exit(1); | ||
274 | } | 143 | } |
275 | // wait for the child to finish | 144 | fprintf(fp, "%s\n", filter); |
276 | waitpid(child, NULL, 0); | 145 | fclose(fp); |
277 | 146 | ||
147 | // push filter | ||
148 | if (arg_debug) | ||
149 | printf("Installing network filter:\n%s\n", filter); | ||
150 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP | SBOX_STDIN_FROM_FILE, 1, ip6tables_restore); | ||
151 | unlink(SBOX_STDIN_FILE); | ||
152 | |||
278 | // debug | 153 | // debug |
279 | if (arg_debug) { | 154 | if (arg_debug) |
280 | child = fork(); | 155 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, ip6tables, "-vL"); |
281 | if (child < 0) | ||
282 | errExit("fork"); | ||
283 | if (child == 0) { | ||
284 | clearenv(); | ||
285 | execl(ip6tables, ip6tables, "-vL", NULL); | ||
286 | perror("execl"); | ||
287 | _exit(1); | ||
288 | } | ||
289 | // wait for the child to finish | ||
290 | waitpid(child, NULL, 0); | ||
291 | } | ||
292 | 156 | ||
293 | doexit: | ||
294 | // unmount /tmp | ||
295 | umount("/tmp"); | ||
296 | free(filter); | 157 | free(filter); |
297 | return; | 158 | return; |
298 | |||
299 | errexit: | ||
300 | fprintf(stderr, "Error: cannot read network filter %s\n", fname); | ||
301 | exit(1); | ||
302 | } | 159 | } |