diff options
-rw-r--r-- | src/firejail/checkcfg.c | 24 | ||||
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/main.c | 8 | ||||
-rw-r--r-- | src/firejail/profile.c | 20 | ||||
-rw-r--r-- | src/firejail/x11.c | 200 |
5 files changed, 254 insertions, 0 deletions
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index dff892ea3..56ab7c932 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -27,6 +27,8 @@ static int initialized = 0; | |||
27 | static int cfg_val[CFG_MAX]; | 27 | static int cfg_val[CFG_MAX]; |
28 | char *xephyr_screen = "800x600"; | 28 | char *xephyr_screen = "800x600"; |
29 | char *xephyr_extra_params = ""; | 29 | char *xephyr_extra_params = ""; |
30 | char *xvfb_screen = "800x600x24"; | ||
31 | char *xvfb_extra_params = ""; | ||
30 | char *netfilter_default = NULL; | 32 | char *netfilter_default = NULL; |
31 | 33 | ||
32 | int checkcfg(int val) { | 34 | int checkcfg(int val) { |
@@ -234,6 +236,28 @@ int checkcfg(int val) { | |||
234 | errExit("strdup"); | 236 | errExit("strdup"); |
235 | } | 237 | } |
236 | 238 | ||
239 | // Xvfb screen size | ||
240 | else if (strncmp(ptr, "xvfb-screen ", 12) == 0) { | ||
241 | // expecting three numbers separated by x's | ||
242 | unsigned int n1; | ||
243 | unsigned int n2; | ||
244 | unsigned int n3; | ||
245 | int rv = sscanf(ptr + 12, "%ux%ux%u", &n1, &n2, &n3); | ||
246 | if (rv != 3) | ||
247 | goto errout; | ||
248 | if (asprintf(&xvfb_screen, "%ux%ux%u", n1, n2, n3) == -1) | ||
249 | errExit("asprintf"); | ||
250 | } | ||
251 | |||
252 | // Xvfb extra parameters | ||
253 | else if (strncmp(ptr, "xvfb-extra-params ", 18) == 0) { | ||
254 | if (*xvfb_extra_params != '\0') | ||
255 | goto errout; | ||
256 | xvfb_extra_params = strdup(ptr + 18); | ||
257 | if (!xvfb_extra_params) | ||
258 | errExit("strdup"); | ||
259 | } | ||
260 | |||
237 | // quiet by default | 261 | // quiet by default |
238 | else if (strncmp(ptr, "quiet-by-default ", 17) == 0) { | 262 | else if (strncmp(ptr, "quiet-by-default ", 17) == 0) { |
239 | if (strcmp(ptr + 17, "yes") == 0) | 263 | if (strcmp(ptr + 17, "yes") == 0) |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index cafaf8c4f..aec6f3de4 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -684,6 +684,8 @@ enum { | |||
684 | }; | 684 | }; |
685 | extern char *xephyr_screen; | 685 | extern char *xephyr_screen; |
686 | extern char *xephyr_extra_params; | 686 | extern char *xephyr_extra_params; |
687 | extern char *xvfb_screen; | ||
688 | extern char *xvfb_extra_params; | ||
687 | extern char *netfilter_default; | 689 | extern char *netfilter_default; |
688 | int checkcfg(int val); | 690 | int checkcfg(int val); |
689 | void print_compiletime_support(void); | 691 | void print_compiletime_support(void); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 978ca8cd2..5951e5d16 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -349,6 +349,14 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
349 | else | 349 | else |
350 | exit_err_feature("x11"); | 350 | exit_err_feature("x11"); |
351 | } | 351 | } |
352 | else if (strcmp(argv[i], "--x11=xvfb") == 0) { | ||
353 | if (checkcfg(CFG_X11)) { | ||
354 | x11_start_xvfb(argc, argv); | ||
355 | exit(0); | ||
356 | } | ||
357 | else | ||
358 | exit_err_feature("x11"); | ||
359 | } | ||
352 | #endif | 360 | #endif |
353 | #ifdef HAVE_NETWORK | 361 | #ifdef HAVE_NETWORK |
354 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { | 362 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 271176fcd..9f6688d4a 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -719,6 +719,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
719 | #endif | 719 | #endif |
720 | return 0; | 720 | return 0; |
721 | } | 721 | } |
722 | |||
722 | if (strcmp(ptr, "x11 xpra") == 0) { | 723 | if (strcmp(ptr, "x11 xpra") == 0) { |
723 | #ifdef HAVE_X11 | 724 | #ifdef HAVE_X11 |
724 | if (checkcfg(CFG_X11)) { | 725 | if (checkcfg(CFG_X11)) { |
@@ -738,6 +739,25 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
738 | return 0; | 739 | return 0; |
739 | } | 740 | } |
740 | 741 | ||
742 | if (strcmp(ptr, "x11 xvfb") == 0) { | ||
743 | #ifdef HAVE_X11 | ||
744 | if (checkcfg(CFG_X11)) { | ||
745 | char *x11env = getenv("FIREJAIL_X11"); | ||
746 | if (x11env && strcmp(x11env, "yes") == 0) { | ||
747 | return 0; | ||
748 | } | ||
749 | else { | ||
750 | // start x11 | ||
751 | x11_start_xvfb(cfg.original_argc, cfg.original_argv); | ||
752 | exit(0); | ||
753 | } | ||
754 | } | ||
755 | else | ||
756 | warning_feature_disabled("x11"); | ||
757 | #endif | ||
758 | return 0; | ||
759 | } | ||
760 | |||
741 | if (strcmp(ptr, "x11") == 0) { | 761 | if (strcmp(ptr, "x11") == 0) { |
742 | #ifdef HAVE_X11 | 762 | #ifdef HAVE_X11 |
743 | if (checkcfg(CFG_X11)) { | 763 | if (checkcfg(CFG_X11)) { |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index b668c1c9c..f66848b7c 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -200,6 +200,206 @@ static int random_display_number(void) { | |||
200 | 200 | ||
201 | 201 | ||
202 | #ifdef HAVE_X11 | 202 | #ifdef HAVE_X11 |
203 | |||
204 | void x11_start_xvfb(int argc, char **argv) { | ||
205 | EUID_ASSERT(); | ||
206 | int i; | ||
207 | struct stat s; | ||
208 | pid_t jail = 0; | ||
209 | pid_t server = 0; | ||
210 | |||
211 | setenv("FIREJAIL_X11", "yes", 1); | ||
212 | |||
213 | // mever try to run X servers as root!!! | ||
214 | if (getuid() == 0) { | ||
215 | fprintf(stderr, "Error: X11 sandboxing is not available when running as root\n"); | ||
216 | exit(1); | ||
217 | } | ||
218 | drop_privs(0); | ||
219 | |||
220 | // check xephyr | ||
221 | if (!program_in_path("Xvfb")) { | ||
222 | fprintf(stderr, "\nError: xvfb program was not found in /usr/bin directory, please install it:\n"); | ||
223 | fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xvfb\n"); | ||
224 | fprintf(stderr, " Arch: sudo pacman -S xorg-server-xvfb\n"); | ||
225 | exit(0); | ||
226 | } | ||
227 | |||
228 | int display = random_display_number(); | ||
229 | char *display_str; | ||
230 | if (asprintf(&display_str, ":%d", display) == -1) | ||
231 | errExit("asprintf"); | ||
232 | |||
233 | assert(xvfb_screen); | ||
234 | |||
235 | char *server_argv[256] = { "Xvfb", display_str, "-screen", "0", xvfb_screen }; // rest initialyzed to NULL | ||
236 | unsigned pos = 0; | ||
237 | while (server_argv[pos] != NULL) pos++; | ||
238 | assert(xvfb_extra_params); // should be "" if empty | ||
239 | |||
240 | // parse xvfb_extra_params | ||
241 | // very basic quoting support | ||
242 | char *temp = strdup(xephyr_extra_params); | ||
243 | if (*xephyr_extra_params != '\0') { | ||
244 | if (!temp) | ||
245 | errExit("strdup"); | ||
246 | bool dquote = false; | ||
247 | bool squote = false; | ||
248 | for (i = 0; i < (int) strlen(xvfb_extra_params); i++) { | ||
249 | if (temp[i] == '\"') { | ||
250 | dquote = !dquote; | ||
251 | if (dquote) temp[i] = '\0'; // replace closing quote by \0 | ||
252 | } | ||
253 | if (temp[i] == '\'') { | ||
254 | squote = !squote; | ||
255 | if (squote) temp[i] = '\0'; // replace closing quote by \0 | ||
256 | } | ||
257 | if (!dquote && !squote && temp[i] == ' ') temp[i] = '\0'; | ||
258 | if (dquote && squote) { | ||
259 | fprintf(stderr, "Error: mixed quoting found while parsing xvfb_extra_params\n"); | ||
260 | exit(1); | ||
261 | } | ||
262 | } | ||
263 | if (dquote) { | ||
264 | fprintf(stderr, "Error: unclosed quote found while parsing xephyr_extra_params\n"); | ||
265 | exit(1); | ||
266 | } | ||
267 | |||
268 | for (i = 0; i < (int) strlen(xvfb_extra_params)-1; i++) { | ||
269 | if (pos >= (sizeof(server_argv)/sizeof(*server_argv)) - 2) { | ||
270 | fprintf(stderr, "Error: arg count limit exceeded while parsing xvfb_extra_params\n"); | ||
271 | exit(1); | ||
272 | } | ||
273 | if (temp[i] == '\0' && (temp[i+1] == '\"' || temp[i+1] == '\'')) server_argv[pos++] = temp + i + 2; | ||
274 | else if (temp[i] == '\0' && temp[i+1] != '\0') server_argv[pos++] = temp + i + 1; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | server_argv[pos++] = NULL; | ||
279 | |||
280 | assert(pos < (sizeof(server_argv)/sizeof(*server_argv))); // no overrun | ||
281 | assert(server_argv[pos-1] == NULL); // last element is null | ||
282 | |||
283 | if (arg_debug) { | ||
284 | size_t i = 0; | ||
285 | printf("xvfb server:"); | ||
286 | while (server_argv[i]!=NULL) { | ||
287 | printf(" \"%s\"", server_argv[i]); | ||
288 | i++; | ||
289 | } | ||
290 | putchar('\n'); | ||
291 | } | ||
292 | |||
293 | // remove --x11 arg | ||
294 | char *jail_argv[argc+2]; | ||
295 | int j = 0; | ||
296 | for (i = 0; i < argc; i++) { | ||
297 | if (strcmp(argv[i], "--x11") == 0) | ||
298 | continue; | ||
299 | if (strcmp(argv[i], "--x11=xpra") == 0) | ||
300 | continue; | ||
301 | if (strcmp(argv[i], "--x11=xephyr") == 0) | ||
302 | continue; | ||
303 | if (strcmp(argv[i], "--x11=xvfb") == 0) | ||
304 | continue; | ||
305 | jail_argv[j] = argv[i]; | ||
306 | j++; | ||
307 | } | ||
308 | jail_argv[j] = NULL; | ||
309 | |||
310 | assert(j < argc+2); // no overrun | ||
311 | |||
312 | if (arg_debug) { | ||
313 | size_t i = 0; | ||
314 | printf("xvfb client:"); | ||
315 | while (jail_argv[i]!=NULL) { | ||
316 | printf(" \"%s\"", jail_argv[i]); | ||
317 | i++; | ||
318 | } | ||
319 | putchar('\n'); | ||
320 | } | ||
321 | |||
322 | server = fork(); | ||
323 | if (server < 0) | ||
324 | errExit("fork"); | ||
325 | if (server == 0) { | ||
326 | if (arg_debug) | ||
327 | printf("Starting xvfb...\n"); | ||
328 | |||
329 | // running without privileges - see drop_privs call above | ||
330 | assert(getenv("LD_PRELOAD") == NULL); | ||
331 | execvp(server_argv[0], server_argv); | ||
332 | perror("execvp"); | ||
333 | _exit(1); | ||
334 | } | ||
335 | |||
336 | if (arg_debug) | ||
337 | printf("xephyr server pid %d\n", server); | ||
338 | |||
339 | // check X11 socket | ||
340 | char *fname; | ||
341 | if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) | ||
342 | errExit("asprintf"); | ||
343 | int n = 0; | ||
344 | // wait for x11 server to start | ||
345 | while (++n < 10) { | ||
346 | sleep(1); | ||
347 | if (stat(fname, &s) == 0) | ||
348 | break; | ||
349 | }; | ||
350 | |||
351 | if (n == 10) { | ||
352 | fprintf(stderr, "Error: failed to start xephyr\n"); | ||
353 | exit(1); | ||
354 | } | ||
355 | free(fname); | ||
356 | |||
357 | if (arg_debug) { | ||
358 | printf("X11 sockets: "); fflush(0); | ||
359 | int rv = system("ls /tmp/.X11-unix"); | ||
360 | (void) rv; | ||
361 | } | ||
362 | |||
363 | setenv("DISPLAY", display_str, 1); | ||
364 | // run attach command | ||
365 | jail = fork(); | ||
366 | if (jail < 0) | ||
367 | errExit("fork"); | ||
368 | if (jail == 0) { | ||
369 | if (!arg_quiet) | ||
370 | printf("\n*** Attaching to Xvfb display %d ***\n\n", display); | ||
371 | |||
372 | // running without privileges - see drop_privs call above | ||
373 | assert(getenv("LD_PRELOAD") == NULL); | ||
374 | execvp(jail_argv[0], jail_argv); | ||
375 | perror("execvp"); | ||
376 | _exit(1); | ||
377 | } | ||
378 | |||
379 | // cleanup | ||
380 | free(display_str); | ||
381 | free(temp); | ||
382 | |||
383 | // wait for either server or jail termination | ||
384 | pid_t pid = wait(NULL); | ||
385 | |||
386 | // see which process terminated and kill other | ||
387 | if (pid == server) { | ||
388 | kill(jail, SIGTERM); | ||
389 | } else if (pid == jail) { | ||
390 | kill(server, SIGTERM); | ||
391 | } | ||
392 | |||
393 | // without this closing Xephyr window may mess your terminal: | ||
394 | // "monitoring" process will release terminal before | ||
395 | // jail process ends and releases terminal | ||
396 | wait(NULL); // fulneral | ||
397 | |||
398 | exit(0); | ||
399 | } | ||
400 | |||
401 | |||
402 | |||
203 | //$ Xephyr -ac -br -noreset -screen 800x600 :22 & | 403 | //$ Xephyr -ac -br -noreset -screen 800x600 :22 & |
204 | //$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox | 404 | //$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox |
205 | void x11_start_xephyr(int argc, char **argv) { | 405 | void x11_start_xephyr(int argc, char **argv) { |