diff options
author | 2016-11-28 10:36:04 -0500 | |
---|---|---|
committer | 2016-11-28 10:36:04 -0500 | |
commit | d0c1fcfa273d323a26aa8477130e176dc2435bf5 (patch) | |
tree | 5c0823ed12cabf602ace114a12b53fb3b2872b99 | |
parent | cleanup (diff) | |
download | firejail-d0c1fcfa273d323a26aa8477130e176dc2435bf5.tar.gz firejail-d0c1fcfa273d323a26aa8477130e176dc2435bf5.tar.zst firejail-d0c1fcfa273d323a26aa8477130e176dc2435bf5.zip |
netfilter rework
-rw-r--r-- | src/firejail/firejail.h | 5 | ||||
-rw-r--r-- | src/firejail/netfilter.c | 233 | ||||
-rw-r--r-- | src/firejail/sbox.c | 32 | ||||
-rw-r--r-- | src/firejail/util.c | 42 | ||||
-rw-r--r-- | src/firejail/x11.c | 1 |
5 files changed, 115 insertions, 198 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 4ae3cfd9f..61de17bf8 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -41,7 +41,6 @@ | |||
41 | #define RUN_CPU_CFG "/run/firejail/mnt/cpu" | 41 | #define RUN_CPU_CFG "/run/firejail/mnt/cpu" |
42 | #define RUN_GROUPS_CFG "/run/firejail/mnt/groups" | 42 | #define RUN_GROUPS_CFG "/run/firejail/mnt/groups" |
43 | #define RUN_PROTOCOL_CFG "/run/firejail/mnt/protocol" | 43 | #define RUN_PROTOCOL_CFG "/run/firejail/mnt/protocol" |
44 | #define RUN_CP_COMMAND "/run/firejail/mnt/cp" | ||
45 | #define RUN_HOME_DIR "/run/firejail/mnt/home" | 44 | #define RUN_HOME_DIR "/run/firejail/mnt/home" |
46 | #define RUN_ETC_DIR "/run/firejail/mnt/etc" | 45 | #define RUN_ETC_DIR "/run/firejail/mnt/etc" |
47 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" | 46 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" |
@@ -463,6 +462,7 @@ void create_empty_dir_as_root(const char *dir, mode_t mode); | |||
463 | void create_empty_file_as_root(const char *dir, mode_t mode); | 462 | void create_empty_file_as_root(const char *dir, mode_t mode); |
464 | int set_perms(const char *fname, uid_t uid, gid_t gid, mode_t mode); | 463 | int set_perms(const char *fname, uid_t uid, gid_t gid, mode_t mode); |
465 | void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid); | 464 | void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid); |
465 | char *read_text_file_or_exit(const char *fname); | ||
466 | 466 | ||
467 | // fs_var.c | 467 | // fs_var.c |
468 | void fs_var_log(void); // mounting /var/log | 468 | void fs_var_log(void); // mounting /var/log |
@@ -679,6 +679,8 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar | |||
679 | #define PATH_FIREMON (PREFIX "/bin/firemon") | 679 | #define PATH_FIREMON (PREFIX "/bin/firemon") |
680 | #define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") | 680 | #define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") |
681 | #define PATH_FCOPY (LIBDIR "/firejail/fcopy") | 681 | #define PATH_FCOPY (LIBDIR "/firejail/fcopy") |
682 | #define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" | ||
683 | |||
682 | // bitmapped filters for sbox_run | 684 | // bitmapped filters for sbox_run |
683 | #define SBOX_ROOT (1 << 0) // run the sandbox as root | 685 | #define SBOX_ROOT (1 << 0) // run the sandbox as root |
684 | #define SBOX_USER (1 << 1) // run the sandbox as a regular user | 686 | #define SBOX_USER (1 << 1) // run the sandbox as a regular user |
@@ -686,6 +688,7 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar | |||
686 | #define SBOX_CAPS_NONE (1 << 3) // drop all capabilities | 688 | #define SBOX_CAPS_NONE (1 << 3) // drop all capabilities |
687 | #define SBOX_CAPS_NETWORK (1 << 4) // caps filter for programs running network programs | 689 | #define SBOX_CAPS_NETWORK (1 << 4) // caps filter for programs running network programs |
688 | #define SBOX_ALLOW_STDIN (1 << 5) // don't close stdin | 690 | #define SBOX_ALLOW_STDIN (1 << 5) // don't close stdin |
691 | #define SBOX_STDIN_FROM_FILE (1 << 6) // open file and redirect it to stdin | ||
689 | 692 | ||
690 | // run sbox | 693 | // run sbox |
691 | int sbox_run(unsigned filter, int num, ...); | 694 | int sbox_run(unsigned filter, int num, ...); |
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 | } |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index 65c4e35e9..f28bbaf1a 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -138,18 +138,34 @@ int sbox_run(unsigned filter, int num, ...) { | |||
138 | if (child == 0) { | 138 | if (child == 0) { |
139 | // clean the new process | 139 | // clean the new process |
140 | clearenv(); | 140 | clearenv(); |
141 | int max = 20; // getdtablesize() is overkill for a firejail process | 141 | |
142 | for (i = 3; i < max; i++) | 142 | if (filter & SBOX_STDIN_FROM_FILE) { |
143 | close(i); // close open files | 143 | int fd; |
144 | if ((filter & SBOX_ALLOW_STDIN) == 0) { | 144 | if((fd = open(SBOX_STDIN_FILE, O_RDONLY)) == -1) { |
145 | int fd = open("/dev/null",O_RDWR, 0); | 145 | fprintf(stderr,"Error: cannot open /tmp/netfilter\n"); |
146 | if (fd != -1) { | 146 | exit(1); |
147 | dup2 (fd, STDIN_FILENO); | ||
148 | close(fd); | ||
149 | } | 147 | } |
148 | dup2(fd,STDIN_FILENO); | ||
149 | } | ||
150 | else if ((filter & SBOX_ALLOW_STDIN) == 0) { | ||
151 | int fd = open("/dev/null",O_RDWR, 0); | ||
152 | if (fd != -1) | ||
153 | dup2(fd, STDIN_FILENO); | ||
150 | else // the user could run the sandbox without /dev/null | 154 | else // the user could run the sandbox without /dev/null |
151 | close(STDIN_FILENO); | 155 | close(STDIN_FILENO); |
152 | } | 156 | } |
157 | |||
158 | // close all other file descriptors | ||
159 | int max = 20; // getdtablesize() is overkill for a firejail process | ||
160 | for (i = 3; i < max; i++) | ||
161 | close(i); // close open files | ||
162 | |||
163 | if (arg_debug) { | ||
164 | printf("sbox file descriptors:\n"); | ||
165 | int rv = system("ls -l /proc/self/fd"); | ||
166 | (void) rv; | ||
167 | } | ||
168 | |||
153 | umask(027); | 169 | umask(027); |
154 | 170 | ||
155 | // apply filters | 171 | // apply filters |
diff --git a/src/firejail/util.c b/src/firejail/util.c index c3e00a110..75f2acdb9 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -777,3 +777,45 @@ void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { | |||
777 | 777 | ||
778 | ASSERT_PERMS(fname, uid, gid, mode); | 778 | ASSERT_PERMS(fname, uid, gid, mode); |
779 | } | 779 | } |
780 | |||
781 | char *read_text_file_or_exit(const char *fname) { | ||
782 | assert(fname); | ||
783 | |||
784 | // open file | ||
785 | int fd = open(fname, O_RDONLY); | ||
786 | if (fd == -1) { | ||
787 | fprintf(stderr, "Error: cannot read %s\n", fname); | ||
788 | exit(1); | ||
789 | } | ||
790 | |||
791 | int size = lseek(fd, 0, SEEK_END); | ||
792 | if (size == -1) | ||
793 | goto errexit; | ||
794 | if (lseek(fd, 0 , SEEK_SET) == -1) | ||
795 | goto errexit; | ||
796 | |||
797 | // allocate memory | ||
798 | char *data = malloc(size + 1); // + '\0' | ||
799 | if (data == NULL) | ||
800 | goto errexit; | ||
801 | memset(data, 0, size + 1); | ||
802 | |||
803 | // read file | ||
804 | int rd = 0; | ||
805 | while (rd < size) { | ||
806 | int rv = read(fd, (unsigned char *) data + rd, size - rd); | ||
807 | if (rv == -1) { | ||
808 | goto errexit; | ||
809 | } | ||
810 | rd += rv; | ||
811 | } | ||
812 | |||
813 | // close file | ||
814 | close(fd); | ||
815 | return data; | ||
816 | |||
817 | errexit: | ||
818 | close(fd); | ||
819 | fprintf(stderr, "Error: cannot read %s\n", fname); | ||
820 | exit(1); | ||
821 | } \ No newline at end of file | ||
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index d9b3b23d1..e67260490 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -252,7 +252,6 @@ void x11_start_xephyr(int argc, char **argv) { | |||
252 | } | 252 | } |
253 | 253 | ||
254 | for (i = 0; i < (int) strlen(xephyr_extra_params)-1; i++) { | 254 | for (i = 0; i < (int) strlen(xephyr_extra_params)-1; i++) { |
255 | //todo: if working , add a -2 also in 0.9.44-bugfix | ||
256 | if (pos >= (sizeof(server_argv)/sizeof(*server_argv)) - 2) { | 255 | if (pos >= (sizeof(server_argv)/sizeof(*server_argv)) - 2) { |
257 | fprintf(stderr, "Error: arg count limit exceeded while parsing xephyr_extra_params\n"); | 256 | fprintf(stderr, "Error: arg count limit exceeded while parsing xephyr_extra_params\n"); |
258 | exit(1); | 257 | exit(1); |