diff options
author | 2016-08-12 10:18:44 -0400 | |
---|---|---|
committer | 2016-08-12 10:18:44 -0400 | |
commit | 1624a51126c02630366dafc612375604455ddaf8 (patch) | |
tree | 67485f151eb4f75c3f2545313b34eae2d3df5289 /src | |
parent | reverted audit/x11 (diff) | |
parent | --x11=xpra rewrite (diff) | |
download | firejail-1624a51126c02630366dafc612375604455ddaf8.tar.gz firejail-1624a51126c02630366dafc612375604455ddaf8.tar.zst firejail-1624a51126c02630366dafc612375604455ddaf8.zip |
Merge pull request #701 from manevich/x11
rewrite of X11 support
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/x11.c | 265 |
1 files changed, 169 insertions, 96 deletions
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index 090ff6f3b..58908e9df 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -158,16 +158,15 @@ void fs_x11(void) { | |||
158 | 158 | ||
159 | 159 | ||
160 | #ifdef HAVE_X11 | 160 | #ifdef HAVE_X11 |
161 | //$ Xephyr -ac -br -terminate -screen 800x600 :22 & | 161 | //$ Xephyr -ac -br -noreset -screen 800x600 :22 & |
162 | //$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox | 162 | //$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox |
163 | void x11_start_xephyr(int argc, char **argv) { | 163 | void x11_start_xephyr(int argc, char **argv) { |
164 | EUID_ASSERT(); | 164 | EUID_ASSERT(); |
165 | int i; | 165 | size_t i; |
166 | struct stat s; | 166 | struct stat s; |
167 | pid_t client = 0; | 167 | pid_t client = 0; |
168 | pid_t server = 0; | 168 | pid_t server = 0; |
169 | 169 | ||
170 | |||
171 | setenv("FIREJAIL_X11", "yes", 1); | 170 | setenv("FIREJAIL_X11", "yes", 1); |
172 | 171 | ||
173 | // unfortunately, xephyr does a number of weird things when started by root user!!! | 172 | // unfortunately, xephyr does a number of weird things when started by root user!!! |
@@ -186,29 +185,78 @@ void x11_start_xephyr(int argc, char **argv) { | |||
186 | } | 185 | } |
187 | 186 | ||
188 | int display = random_display_number(); | 187 | int display = random_display_number(); |
188 | char *display_str; | ||
189 | if (asprintf(&display_str, ":%d", display) == -1) | ||
190 | errExit("asprintf"); | ||
189 | 191 | ||
190 | // start xephyr | 192 | assert(xephyr_screen); |
191 | char *cmd1; | 193 | char *server_argv[256] = { "Xephyr", "-ac", "-br", "-noreset", "-screen", xephyr_screen }; // rest initialyzed to NULL |
194 | unsigned pos = 0; | ||
195 | while (server_argv[pos] != NULL) pos++; | ||
192 | if (checkcfg(CFG_XEPHYR_WINDOW_TITLE)) { | 196 | if (checkcfg(CFG_XEPHYR_WINDOW_TITLE)) { |
193 | if (asprintf(&cmd1, "Xephyr -ac -br -title \"firejail x11 sandbox\" -terminate -screen %s %s :%d", xephyr_screen, xephyr_extra_params, display) == -1) | 197 | server_argv[pos++] = "-title"; |
194 | errExit("asprintf"); | 198 | server_argv[pos++] = "firejail x11 sandbox"; |
195 | } | ||
196 | else { | ||
197 | if (asprintf(&cmd1, "Xephyr -ac -br -terminate -screen %s %s :%d", xephyr_screen, xephyr_extra_params, display) == -1) | ||
198 | errExit("asprintf"); | ||
199 | } | 199 | } |
200 | 200 | ||
201 | int len = 50; // DISPLAY... | 201 | assert(xephyr_extra_params); // should be "" if empty |
202 | for (i = 0; i < argc; i++) { | 202 | |
203 | len += strlen(argv[i]) + 1; // + ' ' | 203 | // parse xephyr_extra_params |
204 | // very basic quoting support | ||
205 | char *temp = strdup(xephyr_extra_params); | ||
206 | if (xephyr_extra_params != "") { | ||
207 | if (!temp) | ||
208 | errExit("strdup"); | ||
209 | bool dquote = false; | ||
210 | bool squote = false; | ||
211 | for (i = 0; i < strlen(xephyr_extra_params); i++) { | ||
212 | if (temp[i] == '\"') { | ||
213 | dquote = !dquote; | ||
214 | if (dquote) temp[i] = '\0'; // replace closing quote by \0 | ||
215 | } | ||
216 | if (temp[i] == '\'') { | ||
217 | squote = !squote; | ||
218 | if (squote) temp[i] = '\0'; // replace closing quote by \0 | ||
219 | } | ||
220 | if (!dquote && !squote && temp[i] == ' ') temp[i] = '\0'; | ||
221 | if (dquote && squote) { | ||
222 | fprintf(stderr, "Error: mixed quoting found while parsing xephyr_extra_params\n"); | ||
223 | exit(1); | ||
224 | } | ||
225 | } | ||
226 | if (dquote) { | ||
227 | fprintf(stderr, "Error: unclosed quote found while parsing xephyr_extra_params\n"); | ||
228 | exit(1); | ||
229 | } | ||
230 | |||
231 | for (i = 0; i < strlen(xephyr_extra_params)-1; i++) { | ||
232 | if (pos >= (sizeof(server_argv)/sizeof(*server_argv))) { | ||
233 | fprintf(stderr, "Error: arg count limit exceeded while parsing xephyr_extra_params\n"); | ||
234 | exit(1); | ||
235 | } | ||
236 | if (temp[i] == '\0' && (temp[i+1] == '\"' || temp[i+1] == '\'')) server_argv[pos++] = temp + i + 2; | ||
237 | else if (temp[i] == '\0' && temp[i+1] != '\0') server_argv[pos++] = temp + i + 1; | ||
238 | } | ||
204 | } | 239 | } |
205 | 240 | ||
206 | char *cmd2 = malloc(len + 1); // + '\0' | 241 | server_argv[pos++] = display_str; |
207 | if (!cmd2) | 242 | server_argv[pos++] = NULL; |
208 | errExit("malloc"); | 243 | |
244 | assert(pos < (sizeof(server_argv)/sizeof(*server_argv))); // no overrun | ||
245 | assert(server_argv[pos-1] == NULL); // last element is null | ||
209 | 246 | ||
210 | sprintf(cmd2, "DISPLAY=:%d ", display); | 247 | if (arg_debug) { |
211 | char *ptr = cmd2 + strlen(cmd2); | 248 | size_t i = 0; |
249 | printf("xephyr server:"); | ||
250 | while (server_argv[i]!=NULL) { | ||
251 | printf(" \"%s\"", server_argv[i]); | ||
252 | i++; | ||
253 | } | ||
254 | putchar('\n'); | ||
255 | } | ||
256 | |||
257 | // remove --x11 arg | ||
258 | char *client_argv[argc+2]; | ||
259 | size_t j = 0; | ||
212 | for (i = 0; i < argc; i++) { | 260 | for (i = 0; i < argc; i++) { |
213 | if (strcmp(argv[i], "--x11") == 0) | 261 | if (strcmp(argv[i], "--x11") == 0) |
214 | continue; | 262 | continue; |
@@ -216,14 +264,23 @@ void x11_start_xephyr(int argc, char **argv) { | |||
216 | continue; | 264 | continue; |
217 | if (strcmp(argv[i], "--x11=xephyr") == 0) | 265 | if (strcmp(argv[i], "--x11=xephyr") == 0) |
218 | continue; | 266 | continue; |
219 | ptr += sprintf(ptr, "%s ", argv[i]); | 267 | client_argv[j] = argv[i]; |
268 | j++; | ||
269 | } | ||
270 | client_argv[j] = NULL; | ||
271 | |||
272 | assert(j < argc+2); // no overrun | ||
273 | |||
274 | if (arg_debug) { | ||
275 | size_t i = 0; | ||
276 | printf("xephyr client:"); | ||
277 | while (client_argv[i]!=NULL) { | ||
278 | printf(" \"%s\"", client_argv[i]); | ||
279 | i++; | ||
280 | } | ||
281 | putchar('\n'); | ||
220 | } | 282 | } |
221 | if (arg_debug) | ||
222 | printf("xephyr server: %s\n", cmd1); | ||
223 | if (arg_debug) | ||
224 | printf("xephyr client: %s\n", cmd2); | ||
225 | 283 | ||
226 | signal(SIGHUP,SIG_IGN); // fix sleep(1) below | ||
227 | server = fork(); | 284 | server = fork(); |
228 | if (server < 0) | 285 | if (server < 0) |
229 | errExit("fork"); | 286 | errExit("fork"); |
@@ -231,17 +288,14 @@ void x11_start_xephyr(int argc, char **argv) { | |||
231 | if (arg_debug) | 288 | if (arg_debug) |
232 | printf("Starting xephyr...\n"); | 289 | printf("Starting xephyr...\n"); |
233 | 290 | ||
234 | char *a[4]; | 291 | execvp(server_argv[0], server_argv); |
235 | a[0] = "/bin/bash"; | ||
236 | a[1] = "-c"; | ||
237 | a[2] = cmd1; | ||
238 | a[3] = NULL; | ||
239 | |||
240 | execvp(a[0], a); | ||
241 | perror("execvp"); | 292 | perror("execvp"); |
242 | exit(1); | 293 | exit(1); |
243 | } | 294 | } |
244 | 295 | ||
296 | if (arg_debug) | ||
297 | printf("xephyr server pid %d\n", server); | ||
298 | |||
245 | // check X11 socket | 299 | // check X11 socket |
246 | char *fname; | 300 | char *fname; |
247 | if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) | 301 | if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) |
@@ -259,7 +313,6 @@ void x11_start_xephyr(int argc, char **argv) { | |||
259 | exit(1); | 313 | exit(1); |
260 | } | 314 | } |
261 | free(fname); | 315 | free(fname); |
262 | sleep(1); | ||
263 | 316 | ||
264 | if (arg_debug) { | 317 | if (arg_debug) { |
265 | printf("X11 sockets: "); fflush(0); | 318 | printf("X11 sockets: "); fflush(0); |
@@ -267,33 +320,39 @@ void x11_start_xephyr(int argc, char **argv) { | |||
267 | (void) rv; | 320 | (void) rv; |
268 | } | 321 | } |
269 | 322 | ||
323 | setenv("DISPLAY", display_str, 1); | ||
270 | // run attach command | 324 | // run attach command |
271 | client = fork(); | 325 | client = fork(); |
272 | if (client < 0) | 326 | if (client < 0) |
273 | errExit("fork"); | 327 | errExit("fork"); |
274 | if (client == 0) { | 328 | if (client == 0) { |
275 | printf("\n*** Attaching to Xephyr display %d ***\n\n", display); | 329 | printf("\n*** Attaching to Xephyr display %d ***\n\n", display); |
276 | char *a[4]; | 330 | |
277 | a[0] = "/bin/bash"; | 331 | execvp(client_argv[0], client_argv); |
278 | a[1] = "-c"; | ||
279 | a[2] = cmd2; | ||
280 | a[3] = NULL; | ||
281 | |||
282 | execvp(a[0], a); | ||
283 | perror("execvp"); | 332 | perror("execvp"); |
284 | exit(1); | 333 | exit(1); |
285 | } | 334 | } |
286 | sleep(1); | 335 | |
287 | 336 | // cleanup | |
288 | if (!arg_quiet) | 337 | free(display_str); |
289 | printf("Xephyr server pid %d, client pid %d\n", server, client); | 338 | free(temp); |
339 | |||
340 | // wait for either server or client termination | ||
341 | pid_t pid = wait(); | ||
342 | |||
343 | // see which process terminated and kill other | ||
344 | if (pid == server) { | ||
345 | kill(client, SIGTERM); | ||
346 | } else if (pid == client) { | ||
347 | kill(server, SIGTERM); | ||
348 | } | ||
290 | 349 | ||
291 | exit(0); | 350 | exit(0); |
292 | } | 351 | } |
293 | 352 | ||
294 | void x11_start_xpra(int argc, char **argv) { | 353 | void x11_start_xpra(int argc, char **argv) { |
295 | EUID_ASSERT(); | 354 | EUID_ASSERT(); |
296 | int i; | 355 | size_t i; |
297 | struct stat s; | 356 | struct stat s; |
298 | pid_t client = 0; | 357 | pid_t client = 0; |
299 | pid_t server = 0; | 358 | pid_t server = 0; |
@@ -315,40 +374,14 @@ void x11_start_xpra(int argc, char **argv) { | |||
315 | } | 374 | } |
316 | 375 | ||
317 | int display = random_display_number(); | 376 | int display = random_display_number(); |
377 | char *display_str; | ||
378 | if (asprintf(&display_str, ":%d", display) == -1) | ||
379 | errExit("asprintf"); | ||
318 | 380 | ||
319 | // build the start command | 381 | // build the start command |
320 | int len = 50; // xpra start... | 382 | char *server_argv[] = { "xpra", "start", display_str, "--no-daemon", NULL }; |
321 | for (i = 0; i < argc; i++) { | ||
322 | len += strlen(argv[i]) + 1; // + ' ' | ||
323 | } | ||
324 | |||
325 | char *cmd1 = malloc(len + 1); // + '\0' | ||
326 | if (!cmd1) | ||
327 | errExit("malloc"); | ||
328 | |||
329 | sprintf(cmd1, "xpra start :%d --exit-with-children --start-child=\"", display); | ||
330 | char *ptr = cmd1 + strlen(cmd1); | ||
331 | for (i = 0; i < argc; i++) { | ||
332 | if (strcmp(argv[i], "--x11") == 0) | ||
333 | continue; | ||
334 | if (strcmp(argv[i], "--x11=xpra") == 0) | ||
335 | continue; | ||
336 | if (strcmp(argv[i], "--x11=xephyr") == 0) | ||
337 | continue; | ||
338 | ptr += sprintf(ptr, "%s ", argv[i]); | ||
339 | } | ||
340 | sprintf(ptr, "\""); | ||
341 | if (arg_debug) | ||
342 | printf("xpra server: %s\n", cmd1); | ||
343 | |||
344 | // build the attach command | ||
345 | char *cmd2; | ||
346 | if (asprintf(&cmd2, "xpra --title=\"firejail x11 sandbox\" attach :%d", display) == -1) | ||
347 | errExit("asprintf"); | ||
348 | if (arg_debug) | ||
349 | printf("xpra client: %s\n", cmd2); | ||
350 | 383 | ||
351 | signal(SIGHUP,SIG_IGN); // fix sleep(1) below | 384 | // start |
352 | server = fork(); | 385 | server = fork(); |
353 | if (server < 0) | 386 | if (server < 0) |
354 | errExit("fork"); | 387 | errExit("fork"); |
@@ -356,13 +389,7 @@ void x11_start_xpra(int argc, char **argv) { | |||
356 | if (arg_debug) | 389 | if (arg_debug) |
357 | printf("Starting xpra...\n"); | 390 | printf("Starting xpra...\n"); |
358 | 391 | ||
359 | char *a[4]; | 392 | execvp(server_argv[0], server_argv); |
360 | a[0] = "/bin/bash"; | ||
361 | a[1] = "-c"; | ||
362 | a[2] = cmd1; | ||
363 | a[3] = NULL; | ||
364 | |||
365 | execvp(a[0], a); | ||
366 | perror("execvp"); | 393 | perror("execvp"); |
367 | exit(1); | 394 | exit(1); |
368 | } | 395 | } |
@@ -378,13 +405,13 @@ void x11_start_xpra(int argc, char **argv) { | |||
378 | if (stat(fname, &s) == 0) | 405 | if (stat(fname, &s) == 0) |
379 | break; | 406 | break; |
380 | }; | 407 | }; |
408 | // sleep(1); | ||
381 | 409 | ||
382 | if (n == 10) { | 410 | if (n == 10) { |
383 | fprintf(stderr, "Error: failed to start xpra\n"); | 411 | fprintf(stderr, "Error: failed to start xpra\n"); |
384 | exit(1); | 412 | exit(1); |
385 | } | 413 | } |
386 | free(fname); | 414 | free(fname); |
387 | sleep(1); | ||
388 | 415 | ||
389 | if (arg_debug) { | 416 | if (arg_debug) { |
390 | printf("X11 sockets: "); fflush(0); | 417 | printf("X11 sockets: "); fflush(0); |
@@ -392,28 +419,74 @@ void x11_start_xpra(int argc, char **argv) { | |||
392 | (void) rv; | 419 | (void) rv; |
393 | } | 420 | } |
394 | 421 | ||
422 | // build attach command | ||
423 | char *attach_argv[] = { "xpra", "--title=\"firejail x11 sandbox\"", "attach", display_str }; | ||
424 | |||
395 | // run attach command | 425 | // run attach command |
396 | client = fork(); | 426 | client = fork(); |
397 | if (client < 0) | 427 | if (client < 0) |
398 | errExit("fork"); | 428 | errExit("fork"); |
399 | if (client == 0) { | 429 | if (client == 0) { |
400 | printf("\n*** Attaching to xpra display %d ***\n\n", display); | 430 | printf("\n*** Attaching to xpra display %d ***\n\n", display); |
401 | char *a[4]; | 431 | execvp(attach_argv[0], attach_argv); |
402 | a[0] = "/bin/bash"; | ||
403 | a[1] = "-c"; | ||
404 | a[2] = cmd2; | ||
405 | a[3] = NULL; | ||
406 | |||
407 | execvp(a[0], a); | ||
408 | perror("execvp"); | 432 | perror("execvp"); |
409 | exit(1); | 433 | exit(1); |
410 | } | 434 | } |
411 | sleep(1); | ||
412 | |||
413 | if (!arg_quiet) | ||
414 | printf("Xpra server pid %d, client pid %d\n", server, client); | ||
415 | 435 | ||
416 | exit(0); | 436 | setenv("DISPLAY", display_str, 1); |
437 | |||
438 | // build jail command | ||
439 | char *firejail_argv[argc+2]; | ||
440 | unsigned pos = 0; | ||
441 | for (i = 0; i < argc; i++) { | ||
442 | if (strcmp(argv[i], "--x11") == 0) | ||
443 | continue; | ||
444 | if (strcmp(argv[i], "--x11=xpra") == 0) | ||
445 | continue; | ||
446 | if (strcmp(argv[i], "--x11=xephyr") == 0) | ||
447 | continue; | ||
448 | firejail_argv[pos] = argv[i]; | ||
449 | pos++; | ||
450 | } | ||
451 | firejail_argv[pos] = NULL; | ||
452 | |||
453 | assert(pos < argc+2); | ||
454 | assert(!firejail_argv[pos]); | ||
455 | |||
456 | // start jail | ||
457 | pid_t jail = fork(); | ||
458 | if (jail < 0) | ||
459 | errExit("fork"); | ||
460 | if (jail == 0) { | ||
461 | execvp(firejail_argv[0], firejail_argv); | ||
462 | perror("execvp"); | ||
463 | exit(1); | ||
464 | } | ||
465 | |||
466 | if (!arg_quiet) | ||
467 | printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail); | ||
468 | |||
469 | // wait for jail or server to end | ||
470 | while (1) { | ||
471 | pid_t pid = wait(); | ||
472 | |||
473 | if (pid == jail) { | ||
474 | sleep(3); // FIXME: find better way to wait for xpra | ||
475 | char *stop_argv[] = { "xpra", "stop", display_str, NULL }; | ||
476 | pid_t stop = fork(); | ||
477 | if (stop < 0) | ||
478 | errExit("fork"); | ||
479 | if (stop == 0) { | ||
480 | execvp(stop_argv[0], stop_argv); | ||
481 | perror("execvp"); | ||
482 | exit(1); | ||
483 | } | ||
484 | sleep(3); | ||
485 | kill(client, SIGTERM); | ||
486 | kill(server, SIGTERM); | ||
487 | exit(0); | ||
488 | } | ||
489 | } | ||
417 | } | 490 | } |
418 | 491 | ||
419 | void x11_start(int argc, char **argv) { | 492 | void x11_start(int argc, char **argv) { |