From c6fc14e5327c4c13399b1d1e548b92816ac4ac6f Mon Sep 17 00:00:00 2001 From: netblue30 Date: Sat, 26 Mar 2016 09:38:27 -0400 Subject: x11 xephyr support --- src/firejail/firejail.h | 6 +- src/firejail/main.c | 20 +++++ src/firejail/usage.c | 5 +- src/firejail/x11.c | 200 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 210 insertions(+), 21 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 0e2ae16c2..d729504a2 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -527,10 +527,10 @@ void fs_mkdir(const char *name); // x11.c void fs_x11(void); -void x11_start(int argc, char **argv); int x11_display(void); -// return 1 if xpra is installed on the system -int x11_check_xpra(void); +void x11_start(int argc, char **argv); +void x11_start_xpra(int argc, char **argv); +void x11_start_xephyr(int argc, char **argv); // ls.c #define SANDBOX_FS_LS 0 diff --git a/src/firejail/main.c b/src/firejail/main.c index 1f8907e4c..0269ff585 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -287,6 +287,26 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { exit(1); } } + else if (strcmp(argv[i], "--x11=xpra") == 0) { + if (checkcfg(CFG_X11)) { + x11_start_xpra(argc, argv); + exit(0); + } + else { + fprintf(stderr, "Error: --x11 feature is disabled in Firejail configuration file\n"); + exit(1); + } + } + else if (strcmp(argv[i], "--x11=xephyr") == 0) { + if (checkcfg(CFG_X11)) { + x11_start_xephyr(argc, argv); + exit(0); + } + else { + fprintf(stderr, "Error: --x11 feature is disabled in Firejail configuration file\n"); + exit(1); + } + } #endif #ifdef HAVE_NETWORK else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 7bc6ea47a..da5fd4e2f 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -245,7 +245,10 @@ void usage(void) { printf(" --user=new_user - switch the user before starting the sandbox.\n\n"); printf(" --version - print program version and exit.\n\n"); printf(" --whitelist=dirname_or_filename - whitelist directory or file.\n\n"); - printf(" --x11 - enable x11 server.\n\n"); + printf(" --x11 - enable X11 server. The software checks first if Xpra is installed,\n"); + printf("\tthen it checks if Xephyr is installed.\n\n"); + printf(" --x11=xpra - enable Xpra X11 server.\n\n"); + printf(" --x11=xephyr - enable Xephyr X11 server. The window size is 800x600.\n\n"); printf(" --zsh - use /usr/bin/zsh as default shell.\n\n"); printf("\n"); printf("\n"); diff --git a/src/firejail/x11.c b/src/firejail/x11.c index a7bd9fd29..10e89ea7e 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c @@ -27,7 +27,7 @@ #include // return 1 if xpra is installed on the system -int x11_check_xpra(void) { +static int x11_check_xpra(void) { struct stat s; // check xpra @@ -37,6 +37,42 @@ int x11_check_xpra(void) { return 1; } +// return 1 if xephyr is installed on the system +static int x11_check_xephyr(void) { + struct stat s; + + // check xpra + if (stat("/usr/bin/Xephyr", &s) == -1) + return 0; + + return 1; +} + +static int random_display_number(void) { + int i; + int found = 1; + int display; + for (i = 0; i < 100; i++) { + display = rand() % 1024; + if (display < 10) + continue; + char *fname; + if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) + errExit("asprintf"); + struct stat s; + if (stat(fname, &s) == -1) { + found = 1; + break; + } + } + if (!found) { + fprintf(stderr, "Error: cannot pick up a random X11 display number, exiting...\n"); + exit(1); + } + + return display; +} + // return display number, -1 if not configured int x11_display(void) { // extract display @@ -120,7 +156,9 @@ void fs_x11(void) { #ifdef HAVE_X11 -void x11_start(int argc, char **argv) { +//$ Xephyr -ac -br -noreset -screen 800x600 :22 & +//$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox +void x11_start_xephyr(int argc, char **argv) { EUID_ASSERT(); int i; struct stat s; @@ -136,29 +174,129 @@ void x11_start(int argc, char **argv) { // check xpra if (x11_check_xpra() == 0) { - fprintf(stderr, "\nError: Xpra program was not found in /usr/bin directory, please install it:\n"); - fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); + fprintf(stderr, "\nError: Xephyr program was not found in /usr/bin directory, please install it:\n"); + fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xserver-xephyr\n"); exit(0); } - int display; - int found = 1; - for (i = 0; i < 100; i++) { - display = rand() % 1024; - if (display < 10) + int display = random_display_number(); + + // start xephyr + char *cmd1; + if (asprintf(&cmd1, "Xephyr -ac -br -noreset -screen 800x600 :%d", display) == -1) + errExit("asprintf"); + + int len = 50; // DISPLAY... + for (i = 0; i < argc; i++) { + len += strlen(argv[i]) + 1; // + ' ' + } + + char *cmd2 = malloc(len + 1); // + '\0' + if (!cmd2) + errExit("malloc"); + + sprintf(cmd2, "DISPLAY=:%d ", display); + char *ptr = cmd2 + strlen(cmd2); + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "--x11") == 0) continue; - char *fname; - if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) - errExit("asprintf"); - if (stat(fname, &s) == -1) { - found = 1; + ptr += sprintf(ptr, "%s ", argv[i]); + } + if (arg_debug) + printf("xephyr server: %s\n", cmd1); + if (arg_debug) + printf("xephyr client: %s\n", cmd2); + + signal(SIGHUP,SIG_IGN); // fix sleep(1) below + server = fork(); + if (server < 0) + errExit("fork"); + if (server == 0) { + if (arg_debug) + printf("Starting xpra...\n"); + + char *a[4]; + a[0] = "/bin/bash"; + a[1] = "-c"; + a[2] = cmd1; + a[3] = NULL; + + execvp(a[0], a); + perror("execvp"); + exit(1); + } + + // check X11 socket + char *fname; + if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) + errExit("asprintf"); + int n = 0; + // wait for x11 server to start + while (++n < 10) { + sleep(1); + if (stat(fname, &s) == 0) break; - } + }; + + if (n == 10) { + fprintf(stderr, "Error: failed to start xpra\n"); + exit(1); } - if (!found) { - fprintf(stderr, "Error: cannot pick up a random X11 display number, exiting...\n"); + free(fname); + sleep(1); + + if (arg_debug) { + printf("X11 sockets: "); fflush(0); + int rv = system("ls /tmp/.X11-unix"); + (void) rv; + } + + // run attach command + client = fork(); + if (client < 0) + errExit("fork"); + if (client == 0) { + printf("\n*** Attaching to Xephyr display %d ***\n\n", display); + char *a[4]; + a[0] = "/bin/bash"; + a[1] = "-c"; + a[2] = cmd2; + a[3] = NULL; + + execvp(a[0], a); + perror("execvp"); exit(1); } + sleep(1); + + if (!arg_quiet) + printf("Xphyr server pid %d, client pid %d\n", server, client); + + exit(0); +} + +void x11_start_xpra(int argc, char **argv) { + EUID_ASSERT(); + int i; + struct stat s; + pid_t client = 0; + pid_t server = 0; + + + // unfortunately, xpra does a number of wired things when started by root user!!! + if (getuid() == 0) { + fprintf(stderr, "Error: this feature is not available when running as root\n"); + exit(1); + } + + // check xpra + if (x11_check_xpra() == 0) { + fprintf(stderr, "\nError: Xpra program was not found in /usr/bin directory, please install it:\n"); + fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); + exit(0); + } + + int display = random_display_number(); // build the start command int len = 50; // xpra start... @@ -255,4 +393,32 @@ void x11_start(int argc, char **argv) { exit(0); } + +void x11_start(int argc, char **argv) { + EUID_ASSERT(); + int i; + struct stat s; + pid_t client = 0; + pid_t server = 0; + + + // unfortunately, xpra does a number of wired things when started by root user!!! + if (getuid() == 0) { + fprintf(stderr, "Error: this feature is not available when running as root\n"); + exit(1); + } + + // check xpra + if (x11_check_xpra() == 1) + x11_start_xpra(argc, argv); + else if (x11_check_xephyr() == 1) + x11_start_xephyr(argc, argv); + else { + fprintf(stderr, "\nError: Xpra or Xephyr not found in /usr/bin directory, please install one of them:\n"); + fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); + fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xserver-xephyr\n"); + exit(0); + } +} + #endif -- cgit v1.2.3-70-g09d2