aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2017-03-01 14:37:45 -0500
committerLibravatar netblue30 <netblue30@yahoo.com>2017-03-01 14:37:45 -0500
commit178374e6cfdea53ca133c4a36c53cf2c042f0992 (patch)
tree7bee24bb468965d68eecac96b97695f95c1ce947
parentmerge #1100 from zackw: removed mask_x11_abstract_socket (diff)
downloadfirejail-178374e6cfdea53ca133c4a36c53cf2c042f0992.tar.gz
firejail-178374e6cfdea53ca133c4a36c53cf2c042f0992.tar.zst
firejail-178374e6cfdea53ca133c4a36c53cf2c042f0992.zip
merge #1100 from zackw: xvfb support
-rw-r--r--src/firejail/checkcfg.c24
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/main.c8
-rw-r--r--src/firejail/profile.c20
-rw-r--r--src/firejail/x11.c200
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;
27static int cfg_val[CFG_MAX]; 27static int cfg_val[CFG_MAX];
28char *xephyr_screen = "800x600"; 28char *xephyr_screen = "800x600";
29char *xephyr_extra_params = ""; 29char *xephyr_extra_params = "";
30char *xvfb_screen = "800x600x24";
31char *xvfb_extra_params = "";
30char *netfilter_default = NULL; 32char *netfilter_default = NULL;
31 33
32int checkcfg(int val) { 34int 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};
685extern char *xephyr_screen; 685extern char *xephyr_screen;
686extern char *xephyr_extra_params; 686extern char *xephyr_extra_params;
687extern char *xvfb_screen;
688extern char *xvfb_extra_params;
687extern char *netfilter_default; 689extern char *netfilter_default;
688int checkcfg(int val); 690int checkcfg(int val);
689void print_compiletime_support(void); 691void 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
204void 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
205void x11_start_xephyr(int argc, char **argv) { 405void x11_start_xephyr(int argc, char **argv) {