aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README1
-rw-r--r--README.md37
-rw-r--r--RELNOTES1
-rw-r--r--src/firejail/caps.c6
-rw-r--r--src/firejail/checkcfg.c24
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/fs.c2
-rw-r--r--src/firejail/main.c12
-rw-r--r--src/firejail/output.c66
-rw-r--r--src/firejail/profile.c23
-rw-r--r--src/firejail/usage.c1
-rw-r--r--src/firejail/x11.c664
-rw-r--r--src/firemon/arp.c2
-rw-r--r--src/firemon/caps.c6
-rw-r--r--src/firemon/cgroup.c2
-rw-r--r--src/firemon/cpu.c6
-rw-r--r--src/firemon/interface.c2
-rw-r--r--src/firemon/list.c2
-rw-r--r--src/firemon/procevent.c21
-rw-r--r--src/firemon/route.c2
-rw-r--r--src/firemon/seccomp.c6
-rw-r--r--src/firemon/usage.c1
-rw-r--r--src/firemon/x11.c2
-rw-r--r--src/man/firejail-profile.txt7
-rw-r--r--src/man/firejail.txt70
-rw-r--r--src/man/firemon.txt3
-rwxr-xr-xtest/apps-x11-xorg/firefox.exp4
-rwxr-xr-xtest/apps-x11-xorg/icedove.exp4
-rwxr-xr-xtest/apps-x11-xorg/transmission-gtk.exp4
-rwxr-xr-xtest/environment/nice.exp41
-rwxr-xr-xtest/environment/output.exp22
-rwxr-xr-xtest/filters/debug.exp45
-rwxr-xr-xtest/filters/filters.sh3
-rwxr-xr-xtest/root/git.exp51
-rwxr-xr-xtest/root/root.sh3
-rwxr-xr-xtest/utils/join.exp8
36 files changed, 833 insertions, 324 deletions
diff --git a/README b/README
index 71e329792..277d686ac 100644
--- a/README
+++ b/README
@@ -126,6 +126,7 @@ Zack Weinberg (https://github.com/zackw)
126 - rework fcopy, --follow-link support in fcopy 126 - rework fcopy, --follow-link support in fcopy
127 - follow link support in --private-bin 127 - follow link support in --private-bin
128 - wait_for_other function rewrite 128 - wait_for_other function rewrite
129 - xvfb X11 server support
129Austin S. Hemmelgarn (https://github.com/Ferroin) 130Austin S. Hemmelgarn (https://github.com/Ferroin)
130 - unbound profile update 131 - unbound profile update
131Igor Bukanov (https://github.com/ibukanov) 132Igor Bukanov (https://github.com/ibukanov)
diff --git a/README.md b/README.md
index 687877c73..20d624243 100644
--- a/README.md
+++ b/README.md
@@ -145,6 +145,43 @@ Added AppImage type 2 support, and support for passing command line arguments to
145 145
146 $ firejail --git-uninstall 146 $ firejail --git-uninstall
147 147
148 --x11=xvfb
149 Start Xvfb X11 server and attach the sandbox to this server.
150 Xvfb, short for X virtual framebuffer, performs all graphical
151 operations in memory without showing any screen output. Xvfb is
152 mainly used for remote access and software testing on headless
153 servers.
154
155 On Debian platforms Xvfb is installed with the command sudo apt-
156 get install xvfb. This feature is not available when running as
157 root.
158
159 Example: remote VNC access
160
161 On the server we start a sandbox using Xvfb and openbox window
162 manager. The default size of Xvfb screen is 800x600 - it can be
163 changed in /etc/firejail/firejail.config (xvfb-screen). Some
164 sort of networking (--net) is required in order to isolate the
165 abstract sockets used by other X servers.
166
167 $ firejail --net=none --x11=xvfb openbox
168
169 *** Attaching to Xvfb display 792 ***
170
171 Reading profile /etc/firejail/openbox.profile
172 Reading profile /etc/firejail/disable-common.inc
173 Reading profile /etc/firejail/disable-common.local
174 Parent pid 5400, child pid 5401
175
176 On the server we also start a VNC server and attach it to the
177 display handled by our Xvfb server (792).
178
179 $ x11vnc -display :792
180
181 On the client machine we start a VNC viewer and use it to con‐
182 nect to our server:
183
184 $ vncviewer
148 185
149````` 186`````
150## New Profiles 187## New Profiles
diff --git a/RELNOTES b/RELNOTES
index 54078875b..80bede268 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -31,6 +31,7 @@ firejail (0.9.45) baseline; urgency=low
31 * feature: added a number o Python scripts for handling sandboxes 31 * feature: added a number o Python scripts for handling sandboxes
32 * feature: allow local customization using .local files under /etc/firejail 32 * feature: allow local customization using .local files under /etc/firejail
33 * feature: follow-symlink-as-user runtime config option in /etc/firejail/firejail.config 33 * feature: follow-symlink-as-user runtime config option in /etc/firejail/firejail.config
34 * feature: xvfb X11 server support (--x11=xvfb)
34 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire, 35 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire,
35 * new profiles: mumble, zoom, Guayadeque, qemu, keypass2, xed, pluma, 36 * new profiles: mumble, zoom, Guayadeque, qemu, keypass2, xed, pluma,
36 * new profiles: Cryptocat, Bless, Gnome 2048, Gnome Calculator, 37 * new profiles: Cryptocat, Bless, Gnome 2048, Gnome Calculator,
diff --git a/src/firejail/caps.c b/src/firejail/caps.c
index 521187e3a..30693f7a0 100644
--- a/src/firejail/caps.c
+++ b/src/firejail/caps.c
@@ -183,8 +183,10 @@ static int caps_find_name(const char *name) {
183// return 1 if error, 0 if OK 183// return 1 if error, 0 if OK
184void caps_check_list(const char *clist, void (*callback)(int)) { 184void caps_check_list(const char *clist, void (*callback)(int)) {
185 // don't allow empty lists 185 // don't allow empty lists
186 if (clist == NULL || *clist == '\0') 186 if (clist == NULL || *clist == '\0') {
187 goto errexit; 187 fprintf(stderr, "Error: empty capabilities list\n");
188 exit(1);
189 }
188 190
189 // work on a copy of the string 191 // work on a copy of the string
190 char *str = strdup(clist); 192 char *str = strdup(clist);
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 fbf83abb3..aec6f3de4 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -644,7 +644,6 @@ void fs_mkdir(const char *name);
644void fs_mkfile(const char *name); 644void fs_mkfile(const char *name);
645 645
646// x11.c 646// x11.c
647extern int mask_x11_abstract_socket;
648void fs_x11(void); 647void fs_x11(void);
649int x11_display(void); 648int x11_display(void);
650void x11_start(int argc, char **argv); 649void x11_start(int argc, char **argv);
@@ -685,6 +684,8 @@ enum {
685}; 684};
686extern char *xephyr_screen; 685extern char *xephyr_screen;
687extern char *xephyr_extra_params; 686extern char *xephyr_extra_params;
687extern char *xvfb_screen;
688extern char *xvfb_extra_params;
688extern char *netfilter_default; 689extern char *netfilter_default;
689int checkcfg(int val); 690int checkcfg(int val);
690void print_compiletime_support(void); 691void print_compiletime_support(void);
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index c386f70cf..a06f3a35d 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -1084,7 +1084,6 @@ void fs_check_chroot_dir(const char *rootdir) {
1084 1084
1085 // check x11 socket directory 1085 // check x11 socket directory
1086 if (getenv("FIREJAIL_X11")) { 1086 if (getenv("FIREJAIL_X11")) {
1087 mask_x11_abstract_socket = 1;
1088 char *name; 1087 char *name;
1089 if (asprintf(&name, "%s/tmp/.X11-unix", rootdir) == -1) 1088 if (asprintf(&name, "%s/tmp/.X11-unix", rootdir) == -1)
1090 errExit("asprintf"); 1089 errExit("asprintf");
@@ -1117,7 +1116,6 @@ void fs_chroot(const char *rootdir) {
1117 1116
1118 // x11 1117 // x11
1119 if (getenv("FIREJAIL_X11")) { 1118 if (getenv("FIREJAIL_X11")) {
1120 mask_x11_abstract_socket = 1;
1121 char *newx11; 1119 char *newx11;
1122 if (asprintf(&newx11, "%s/tmp/.X11-unix", rootdir) == -1) 1120 if (asprintf(&newx11, "%s/tmp/.X11-unix", rootdir) == -1)
1123 errExit("asprintf"); 1121 errExit("asprintf");
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 310795abf..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) {
@@ -2182,10 +2190,6 @@ int main(int argc, char **argv) {
2182 fprintf(stderr, "Warning: --trace and --tracelog are mutually exclusive; --tracelog disabled\n"); 2190 fprintf(stderr, "Warning: --trace and --tracelog are mutually exclusive; --tracelog disabled\n");
2183 } 2191 }
2184 2192
2185 // disable x11 abstract socket
2186 if (getenv("FIREJAIL_X11"))
2187 mask_x11_abstract_socket = 1;
2188
2189 // check user namespace (--noroot) options 2193 // check user namespace (--noroot) options
2190 if (arg_noroot) { 2194 if (arg_noroot) {
2191 if (arg_overlay) { 2195 if (arg_overlay) {
diff --git a/src/firejail/output.c b/src/firejail/output.c
index 4872c57ba..cea4f4e28 100644
--- a/src/firejail/output.c
+++ b/src/firejail/output.c
@@ -26,50 +26,45 @@ void check_output(int argc, char **argv) {
26 EUID_ASSERT(); 26 EUID_ASSERT();
27 27
28 int i; 28 int i;
29 char *outfile = NULL; 29 int outindex = 0;
30 30
31 int found = 0;
32 for (i = 1; i < argc; i++) { 31 for (i = 1; i < argc; i++) {
33 if (strncmp(argv[i], "--output=", 9) == 0) { 32 if (strncmp(argv[i], "--output=", 9) == 0) {
34 found = 1; 33 outindex = i;
35 invalid_filename(argv[i] + 9);
36 outfile = argv[i] + 9;
37
38 // do not accept directories, links, and files with ".."
39 if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) {
40 fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n");
41 exit(1);
42 }
43
44 struct stat s;
45 if (stat(outfile, &s) == 0) {
46 // check permissions
47 if (s.st_uid != getuid() || s.st_gid != getgid()) {
48 fprintf(stderr, "Error: the output file needs to be owned by the current user.\n");
49 exit(1);
50 }
51
52 // check hard links
53 if (s.st_nlink != 1) {
54 fprintf(stderr, "Error: no hard links allowed.\n");
55 exit(1);
56 }
57 }
58
59 /* coverity[toctou] */
60 FILE *fp = fopen(outfile, "a");
61 if (!fp) {
62 fprintf(stderr, "Error: cannot open output file %s\n", outfile);
63 exit(1);
64 }
65 fclose(fp);
66 break; 34 break;
67 } 35 }
68 } 36 }
69 if (!found) 37 if (!outindex)
70 return; 38 return;
71 39
72 40
41 // check filename
42 drop_privs(0);
43 char *outfile = NULL;
44 invalid_filename(argv[outindex] + 9);
45 outfile = argv[outindex] + 9;
46
47 // do not accept directories, links, and files with ".."
48 if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) {
49 fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n");
50 exit(1);
51 }
52
53 struct stat s;
54 if (stat(outfile, &s) == 0) {
55 // check permissions
56 if (s.st_uid != getuid() || s.st_gid != getgid()) {
57 fprintf(stderr, "Error: the output file needs to be owned by the current user.\n");
58 exit(1);
59 }
60
61 // check hard links
62 if (s.st_nlink != 1) {
63 fprintf(stderr, "Error: no hard links allowed.\n");
64 exit(1);
65 }
66 }
67
73 // build the new command line 68 // build the new command line
74 int len = 0; 69 int len = 0;
75 for (i = 0; i < argc; i++) { 70 for (i = 0; i < argc; i++) {
@@ -90,7 +85,6 @@ void check_output(int argc, char **argv) {
90 sprintf(ptr, "2>&1 | %s/firejail/ftee %s", LIBDIR, outfile); 85 sprintf(ptr, "2>&1 | %s/firejail/ftee %s", LIBDIR, outfile);
91 86
92 // run command 87 // run command
93 drop_privs(0);
94 char *a[4]; 88 char *a[4];
95 a[0] = "/bin/bash"; 89 a[0] = "/bin/bash";
96 a[1] = "-c"; 90 a[1] = "-c";
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 5684a2d95..9f6688d4a 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -696,7 +696,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
696 if (checkcfg(CFG_X11)) { 696 if (checkcfg(CFG_X11)) {
697 char *x11env = getenv("FIREJAIL_X11"); 697 char *x11env = getenv("FIREJAIL_X11");
698 if (x11env && strcmp(x11env, "yes") == 0) { 698 if (x11env && strcmp(x11env, "yes") == 0) {
699 mask_x11_abstract_socket = 1;
700 return 0; 699 return 0;
701 } 700 }
702 else { 701 else {
@@ -720,12 +719,12 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
720#endif 719#endif
721 return 0; 720 return 0;
722 } 721 }
722
723 if (strcmp(ptr, "x11 xpra") == 0) { 723 if (strcmp(ptr, "x11 xpra") == 0) {
724#ifdef HAVE_X11 724#ifdef HAVE_X11
725 if (checkcfg(CFG_X11)) { 725 if (checkcfg(CFG_X11)) {
726 char *x11env = getenv("FIREJAIL_X11"); 726 char *x11env = getenv("FIREJAIL_X11");
727 if (x11env && strcmp(x11env, "yes") == 0) { 727 if (x11env && strcmp(x11env, "yes") == 0) {
728 mask_x11_abstract_socket = 1;
729 return 0; 728 return 0;
730 } 729 }
731 else { 730 else {
@@ -740,12 +739,30 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
740 return 0; 739 return 0;
741 } 740 }
742 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
743 if (strcmp(ptr, "x11") == 0) { 761 if (strcmp(ptr, "x11") == 0) {
744#ifdef HAVE_X11 762#ifdef HAVE_X11
745 if (checkcfg(CFG_X11)) { 763 if (checkcfg(CFG_X11)) {
746 char *x11env = getenv("FIREJAIL_X11"); 764 char *x11env = getenv("FIREJAIL_X11");
747 if (x11env && strcmp(x11env, "yes") == 0) { 765 if (x11env && strcmp(x11env, "yes") == 0) {
748 mask_x11_abstract_socket = 1;
749 return 0; 766 return 0;
750 } 767 }
751 else { 768 else {
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index ae3993aec..4d2054a72 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -205,6 +205,7 @@ void usage(void) {
205 printf(" --x11=xephyr - enable Xephyr X11 server. The window size is 800x600.\n"); 205 printf(" --x11=xephyr - enable Xephyr X11 server. The window size is 800x600.\n");
206 printf(" --x11=xorg - enable X11 security extension.\n"); 206 printf(" --x11=xorg - enable X11 security extension.\n");
207 printf(" --x11=xpra - enable Xpra X11 server.\n"); 207 printf(" --x11=xpra - enable Xpra X11 server.\n");
208 printf(" --x11=xvfb - enable Xvfb X11 server.\n");
208 printf(" --zsh - use /usr/bin/zsh as default shell.\n"); 209 printf(" --zsh - use /usr/bin/zsh as default shell.\n");
209 printf("\n"); 210 printf("\n");
210 printf("Examples:\n"); 211 printf("Examples:\n");
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 5bbc327a6..b72b46f0d 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -31,46 +31,45 @@
31#include <sys/wait.h> 31#include <sys/wait.h>
32#include <errno.h> 32#include <errno.h>
33#include <limits.h> 33#include <limits.h>
34int mask_x11_abstract_socket = 0;
35
36 34
37// Parse the DISPLAY environment variable and return a display number. 35// Parse the DISPLAY environment variable and return a display number.
38// Returns -1 if DISPLAY is not set, or is set to anything other than :ddd. 36// Returns -1 if DISPLAY is not set, or is set to anything other than :ddd.
39int x11_display(void) { 37int x11_display(void) {
40 const char *display_str = getenv("DISPLAY"); 38 const char *display_str = getenv("DISPLAY");
41 char *endp; 39 char *endp;
42 unsigned long display; 40 unsigned long display;
43 41
44 if (!display_str) { 42 if (!display_str) {
45 if (arg_debug) 43 if (arg_debug)
46 fputs("DISPLAY is not set\n", stderr); 44 fputs("DISPLAY is not set\n", stderr);
47 return -1; 45 return -1;
48 } 46 }
49 47
50 if (display_str[0] != ':' || display_str[1] < '0' || display_str[1] > '9') { 48 if (display_str[0] != ':' || display_str[1] < '0' || display_str[1] > '9') {
51 if (arg_debug) 49 if (arg_debug)
52 fprintf(stderr, "unsupported DISPLAY form '%s'\n", display_str); 50 fprintf(stderr, "unsupported DISPLAY form '%s'\n", display_str);
53 return -1; 51 return -1;
54 } 52 }
55 53
56 errno = 0; 54 errno = 0;
57 display = strtoul(display_str+1, &endp, 10); 55 display = strtoul(display_str+1, &endp, 10);
58 if (endp == display_str+1 || (*endp != '\0' && *endp != '.')) { // handling DISPLAY=:0 and also :0.0 56 // handling DISPLAY=:0 and also :0.0
59 if (arg_debug) 57 if (endp == display_str+1 || (*endp != '\0' && *endp != '.')) {
60 fprintf(stderr, "unsupported DISPLAY form '%s'\n", display_str); 58 if (arg_debug)
61 return -1; 59 fprintf(stderr, "unsupported DISPLAY form '%s'\n", display_str);
62 } 60 return -1;
63 if (errno || display > (unsigned long)INT_MAX) { 61 }
64 if (arg_debug) 62 if (errno || display > (unsigned long)INT_MAX) {
65 fprintf(stderr, "display number %s is outside the valid range\n", 63 if (arg_debug)
66 display_str+1); 64 fprintf(stderr, "display number %s is outside the valid range\n",
67 return -1; 65 display_str+1);
68 } 66 return -1;
69 67 }
70 if (arg_debug) 68
71 fprintf(stderr, "DISPLAY=%s parsed as %lu\n", display_str, display); 69 if (arg_debug)
72 70 fprintf(stderr, "DISPLAY=%s parsed as %lu\n", display_str, display);
73 return (int)display; 71
72 return (int)display;
74} 73}
75 74
76 75
@@ -78,34 +77,34 @@ int x11_display(void) {
78// check for X11 abstract sockets 77// check for X11 abstract sockets
79static int x11_abstract_sockets_present(void) { 78static int x11_abstract_sockets_present(void) {
80 79
81 EUID_ROOT(); // grsecurity fix 80 EUID_ROOT(); // grsecurity fix
82 FILE *fp = fopen("/proc/net/unix", "r"); 81 FILE *fp = fopen("/proc/net/unix", "r");
83 if (!fp) 82 if (!fp)
84 errExit("fopen"); 83 errExit("fopen");
85 EUID_USER(); 84 EUID_USER();
86 85
87 char *linebuf = 0; 86 char *linebuf = 0;
88 size_t bufsz = 0; 87 size_t bufsz = 0;
89 int found = 0; 88 int found = 0;
90 errno = 0; 89 errno = 0;
91 90
92 for (;;) { 91 for (;;) {
93 if (getline(&linebuf, &bufsz, fp) == -1) { 92 if (getline(&linebuf, &bufsz, fp) == -1) {
94 if (errno) 93 if (errno)
95 errExit("getline"); 94 errExit("getline");
96 break; 95 break;
97 } 96 }
98 // The last space-separated field in 'linebuf' is the 97 // The last space-separated field in 'linebuf' is the
99 // pathname of the socket. Abstract sockets' pathnames 98 // pathname of the socket. Abstract sockets' pathnames
100 // all begin with '@/', normal ones begin with '/'. 99 // all begin with '@/', normal ones begin with '/'.
101 char *p = strrchr(linebuf, ' '); 100 char *p = strrchr(linebuf, ' ');
102 if (!p) { 101 if (!p) {
103 fputs("error parsing /proc/net/unix\n", stderr); 102 fputs("error parsing /proc/net/unix\n", stderr);
104 exit(1); 103 exit(1);
105 } 104 }
106 if (strncmp(p+1, "@/tmp/.X11-unix/", 16) == 0) { 105 if (strncmp(p+1, "@/tmp/.X11-unix/", 16) == 0) {
107 found = 1; 106 found = 1;
108 break; 107 break;
109 } 108 }
110 } 109 }
111 110
@@ -114,94 +113,289 @@ static int x11_abstract_sockets_present(void) {
114 return found; 113 return found;
115} 114}
116 115
116
117// Choose a random, unallocated display number. This has an inherent 117// Choose a random, unallocated display number. This has an inherent
118// and unavoidable TOCTOU race, since we cannot create either the 118// and unavoidable TOCTOU race, since we cannot create either the
119// socket or a lockfile ourselves. 119// socket or a lockfile ourselves.
120static int random_display_number(void) { 120static int random_display_number(void) {
121 int display; 121 int display;
122 int found = 0; 122 int found = 0;
123 int i; 123 int i;
124 124
125 struct sockaddr_un sa; 125 struct sockaddr_un sa;
126 // The -1 here is because we need space to inject a 126 // The -1 here is because we need space to inject a
127 // leading nul byte. 127 // leading nul byte.
128 int sun_pathmax = (int)(sizeof sa.sun_path - 1); 128 int sun_pathmax = (int)(sizeof sa.sun_path - 1);
129 assert((size_t)sun_pathmax == sizeof sa.sun_path - 1); 129 assert((size_t)sun_pathmax == sizeof sa.sun_path - 1);
130 int sun_pathlen; 130 int sun_pathlen;
131 131
132 int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 132 int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
133 if (sockfd == -1) 133 if (sockfd == -1)
134 errExit("socket"); 134 errExit("socket");
135 135
136 for (i = 0; i < 100; i++) { 136 for (i = 0; i < 100; i++) {
137 // We try display numbers in the range 21 through 1000. 137 // We try display numbers in the range 21 through 1000.
138 // Normal X servers typically use displays in the 0-10 range; 138 // Normal X servers typically use displays in the 0-10 range;
139 // ssh's X11 forwarding uses 10-20, and login screens 139 // ssh's X11 forwarding uses 10-20, and login screens
140 // (e.g. gdm3) may use displays above 1000. 140 // (e.g. gdm3) may use displays above 1000.
141 display = rand() % 979 + 21; 141 display = rand() % 979 + 21;
142 142
143 // The display number might be claimed by a server listening 143 // The display number might be claimed by a server listening
144 // in _either_ the normal or the abstract namespace; they 144 // in _either_ the normal or the abstract namespace; they
145 // don't necessarily do both. The easiest way to check is 145 // don't necessarily do both. The easiest way to check is
146 // to try to connect, both ways. 146 // to try to connect, both ways.
147 memset(&sa, 0, sizeof sa); 147 memset(&sa, 0, sizeof sa);
148 sa.sun_family = AF_UNIX; 148 sa.sun_family = AF_UNIX;
149 sun_pathlen = snprintf(sa.sun_path, sun_pathmax, 149 sun_pathlen = snprintf(sa.sun_path, sun_pathmax,
150 "/tmp/.X11-unix/X%d", display); 150 "/tmp/.X11-unix/X%d", display);
151 if (sun_pathlen >= sun_pathmax) { 151 if (sun_pathlen >= sun_pathmax) {
152 fprintf(stderr, "sun_path too small for display :%d" 152 fprintf(stderr, "sun_path too small for display :%d"
153 " (only %d bytes usable)\n", display, sun_pathmax); 153 " (only %d bytes usable)\n", display, sun_pathmax);
154 exit(1); 154 exit(1);
155 } 155 }
156 156
157 if (connect(sockfd, (struct sockaddr *)&sa, 157 if (connect(sockfd, (struct sockaddr *)&sa,
158 offsetof(struct sockaddr_un, sun_path) + sun_pathlen + 1) == 0) { 158 offsetof(struct sockaddr_un, sun_path) + sun_pathlen + 1) == 0) {
159 close(sockfd); 159 close(sockfd);
160 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 160 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
161 if (sockfd == -1) 161 if (sockfd == -1)
162 errExit("socket"); 162 errExit("socket");
163 continue; 163 continue;
164 } 164 }
165 if (errno != ECONNREFUSED && errno != ENOENT) 165 if (errno != ECONNREFUSED && errno != ENOENT)
166 errExit("connect"); 166 errExit("connect");
167 167
168 // Name not claimed in the normal namespace; now try it 168 // Name not claimed in the normal namespace; now try it
169 // in the abstract namespace. Note that abstract-namespace 169 // in the abstract namespace. Note that abstract-namespace
170 // names are NOT nul-terminated; they extend to the length 170 // names are NOT nul-terminated; they extend to the length
171 // specified as the third argument to 'connect'. 171 // specified as the third argument to 'connect'.
172 memmove(sa.sun_path + 1, sa.sun_path, sun_pathlen + 1); 172 memmove(sa.sun_path + 1, sa.sun_path, sun_pathlen + 1);
173 sa.sun_path[0] = '\0'; 173 sa.sun_path[0] = '\0';
174 if (connect(sockfd, (struct sockaddr *)&sa, 174 if (connect(sockfd, (struct sockaddr *)&sa,
175 offsetof(struct sockaddr_un, sun_path) + 1 + sun_pathlen) == 0) { 175 offsetof(struct sockaddr_un, sun_path) + 1 + sun_pathlen) == 0) {
176 close(sockfd); 176 close(sockfd);
177 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 177 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
178 if (sockfd == -1) 178 if (sockfd == -1)
179 errExit("socket"); 179 errExit("socket");
180 continue; 180 continue;
181 } 181 }
182 if (errno != ECONNREFUSED && errno != ENOENT) 182 if (errno != ECONNREFUSED && errno != ENOENT)
183 errExit("connect"); 183 errExit("connect");
184 184
185 // This display number is unclaimed. Of course, it could 185 // This display number is unclaimed. Of course, it could
186 // be claimed before we get around to doing it... 186 // be claimed before we get around to doing it...
187 found = 1; 187 found = 1;
188 break; 188 break;
189 } 189 }
190 close(sockfd); 190 close(sockfd);
191 191
192 if (!found) { 192 if (!found) {
193 fputs("Error: cannot find an unallocated X11 display number, " 193 fputs("Error: cannot find an unallocated X11 display number, "
194 "exiting...\n", stderr); 194 "exiting...\n", stderr);
195 exit(1); 195 exit(1);
196 } 196 }
197 return display; 197 return display;
198} 198}
199#endif 199#endif
200 200
201#ifdef HAVE_X11
202void x11_start_xvfb(int argc, char **argv) {
203 EUID_ASSERT();
204 int i;
205 struct stat s;
206 pid_t jail = 0;
207 pid_t server = 0;
201 208
209 setenv("FIREJAIL_X11", "yes", 1);
210
211 // mever try to run X servers as root!!!
212 if (getuid() == 0) {
213 fprintf(stderr, "Error: X11 sandboxing is not available when running as root\n");
214 exit(1);
215 }
216 drop_privs(0);
217
218 // check xephyr
219 if (!program_in_path("Xvfb")) {
220 fprintf(stderr, "\nError: Xvfb program was not found in /usr/bin directory, please install it:\n");
221 fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xvfb\n");
222 fprintf(stderr, " Arch: sudo pacman -S xorg-server-xvfb\n");
223 exit(0);
224 }
225
226 int display = random_display_number();
227 char *display_str;
228 if (asprintf(&display_str, ":%d", display) == -1)
229 errExit("asprintf");
230
231 assert(xvfb_screen);
232
233 char *server_argv[256] = { // rest initialyzed to NULL
234 "Xvfb", display_str, "-screen", "0", xvfb_screen
235 };
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 // replace closing quote by \0
252 if (dquote) temp[i] = '\0';
253 }
254 if (temp[i] == '\'') {
255 squote = !squote;
256 // replace closing quote by \0
257 if (squote) temp[i] = '\0';
258 }
259 if (!dquote && !squote && temp[i] == ' ') temp[i] = '\0';
260 if (dquote && squote) {
261 fprintf(stderr, "Error: mixed quoting found while parsing xvfb_extra_params\n");
262 exit(1);
263 }
264 }
265 if (dquote) {
266 fprintf(stderr, "Error: unclosed quote found while parsing xephyr_extra_params\n");
267 exit(1);
268 }
269
270 for (i = 0; i < (int) strlen(xvfb_extra_params)-1; i++) {
271 if (pos >= (sizeof(server_argv)/sizeof(*server_argv)) - 2) {
272 fprintf(stderr, "Error: arg count limit exceeded while parsing xvfb_extra_params\n");
273 exit(1);
274 }
275 if (temp[i] == '\0' && (temp[i+1] == '\"' || temp[i+1] == '\'')) server_argv[pos++] = temp + i + 2;
276 else if (temp[i] == '\0' && temp[i+1] != '\0') server_argv[pos++] = temp + i + 1;
277 }
278 }
279
280 server_argv[pos++] = NULL;
281
282 assert(pos < (sizeof(server_argv)/sizeof(*server_argv))); // no overrun
283 assert(server_argv[pos-1] == NULL); // last element is null
284
285 if (arg_debug) {
286 size_t i = 0;
287 printf("xvfb server:");
288 while (server_argv[i]!=NULL) {
289 printf(" \"%s\"", server_argv[i]);
290 i++;
291 }
292 putchar('\n');
293 }
294
295 // remove --x11 arg
296 char *jail_argv[argc+2];
297 int j = 0;
298 for (i = 0; i < argc; i++) {
299 if (strncmp(argv[i], "--x11", 5) == 0)
300 continue;
301 jail_argv[j] = argv[i];
302 j++;
303 }
304 jail_argv[j] = NULL;
305
306 assert(j < argc+2); // no overrun
307
308 if (arg_debug) {
309 size_t i = 0;
310 printf("xvfb client:");
311 while (jail_argv[i]!=NULL) {
312 printf(" \"%s\"", jail_argv[i]);
313 i++;
314 }
315 putchar('\n');
316 }
317
318 server = fork();
319 if (server < 0)
320 errExit("fork");
321 if (server == 0) {
322 if (arg_debug)
323 printf("Starting xvfb...\n");
324
325 // running without privileges - see drop_privs call above
326 assert(getenv("LD_PRELOAD") == NULL);
327 execvp(server_argv[0], server_argv);
328 perror("execvp");
329 _exit(1);
330 }
331
332 if (arg_debug)
333 printf("xephyr server pid %d\n", server);
334
335 // check X11 socket
336 char *fname;
337 if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1)
338 errExit("asprintf");
339 int n = 0;
340 // wait for x11 server to start
341 while (++n < 10) {
342 sleep(1);
343 if (stat(fname, &s) == 0)
344 break;
345 };
346
347 if (n == 10) {
348 fprintf(stderr, "Error: failed to start xephyr\n");
349 exit(1);
350 }
351 free(fname);
352
353 if (arg_debug) {
354 printf("X11 sockets: "); fflush(0);
355 int rv = system("ls /tmp/.X11-unix");
356 (void) rv;
357 }
358
359 setenv("DISPLAY", display_str, 1);
360 // run attach command
361 jail = fork();
362 if (jail < 0)
363 errExit("fork");
364 if (jail == 0) {
365 if (!arg_quiet)
366 printf("\n*** Attaching to Xvfb display %d ***\n\n", display);
367
368 // running without privileges - see drop_privs call above
369 assert(getenv("LD_PRELOAD") == NULL);
370 execvp(jail_argv[0], jail_argv);
371 perror("execvp");
372 _exit(1);
373 }
374
375 // cleanup
376 free(display_str);
377 free(temp);
378
379 // wait for either server or jail termination
380 pid_t pid = wait(NULL);
381
382 // see which process terminated and kill other
383 if (pid == server) {
384 kill(jail, SIGTERM);
385 }
386 else if (pid == jail) {
387 kill(server, SIGTERM);
388 }
389
390 // without this closing Xephyr window may mess your terminal:
391 // "monitoring" process will release terminal before
392 // jail process ends and releases terminal
393 wait(NULL); // fulneral
394
395 exit(0);
396}
202 397
203 398
204#ifdef HAVE_X11
205//$ Xephyr -ac -br -noreset -screen 800x600 :22 & 399//$ Xephyr -ac -br -noreset -screen 800x600 :22 &
206//$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox 400//$ DISPLAY=:22 firejail --net=eth0 --blacklist=/tmp/.X11-unix/x0 firefox
207void x11_start_xephyr(int argc, char **argv) { 401void x11_start_xephyr(int argc, char **argv) {
@@ -210,7 +404,7 @@ void x11_start_xephyr(int argc, char **argv) {
210 struct stat s; 404 struct stat s;
211 pid_t jail = 0; 405 pid_t jail = 0;
212 pid_t server = 0; 406 pid_t server = 0;
213 407
214 setenv("FIREJAIL_X11", "yes", 1); 408 setenv("FIREJAIL_X11", "yes", 1);
215 409
216 // unfortunately, xephyr does a number of weird things when started by root user!!! 410 // unfortunately, xephyr does a number of weird things when started by root user!!!
@@ -227,14 +421,16 @@ void x11_start_xephyr(int argc, char **argv) {
227 fprintf(stderr, " Arch: sudo pacman -S xorg-server-xephyr\n"); 421 fprintf(stderr, " Arch: sudo pacman -S xorg-server-xephyr\n");
228 exit(0); 422 exit(0);
229 } 423 }
230 424
231 int display = random_display_number(); 425 int display = random_display_number();
232 char *display_str; 426 char *display_str;
233 if (asprintf(&display_str, ":%d", display) == -1) 427 if (asprintf(&display_str, ":%d", display) == -1)
234 errExit("asprintf"); 428 errExit("asprintf");
235 429
236 assert(xephyr_screen); 430 assert(xephyr_screen);
237 char *server_argv[256] = { "Xephyr", "-ac", "-br", "-noreset", "-screen", xephyr_screen }; // rest initialyzed to NULL 431 char *server_argv[256] = { // rest initialyzed to NULL
432 "Xephyr", "-ac", "-br", "-noreset", "-screen", xephyr_screen
433 };
238 unsigned pos = 0; 434 unsigned pos = 0;
239 while (server_argv[pos] != NULL) pos++; 435 while (server_argv[pos] != NULL) pos++;
240 if (checkcfg(CFG_XEPHYR_WINDOW_TITLE)) { 436 if (checkcfg(CFG_XEPHYR_WINDOW_TITLE)) {
@@ -242,7 +438,7 @@ void x11_start_xephyr(int argc, char **argv) {
242 server_argv[pos++] = "firejail x11 sandbox"; 438 server_argv[pos++] = "firejail x11 sandbox";
243 } 439 }
244 440
245 assert(xephyr_extra_params); // should be "" if empty 441 assert(xephyr_extra_params); // should be "" if empty
246 442
247 // parse xephyr_extra_params 443 // parse xephyr_extra_params
248 // very basic quoting support 444 // very basic quoting support
@@ -255,11 +451,13 @@ void x11_start_xephyr(int argc, char **argv) {
255 for (i = 0; i < (int) strlen(xephyr_extra_params); i++) { 451 for (i = 0; i < (int) strlen(xephyr_extra_params); i++) {
256 if (temp[i] == '\"') { 452 if (temp[i] == '\"') {
257 dquote = !dquote; 453 dquote = !dquote;
258 if (dquote) temp[i] = '\0'; // replace closing quote by \0 454 // replace closing quote by \0
455 if (dquote) temp[i] = '\0';
259 } 456 }
260 if (temp[i] == '\'') { 457 if (temp[i] == '\'') {
261 squote = !squote; 458 squote = !squote;
262 if (squote) temp[i] = '\0'; // replace closing quote by \0 459 // replace closing quote by \0
460 if (squote) temp[i] = '\0';
263 } 461 }
264 if (!dquote && !squote && temp[i] == ' ') temp[i] = '\0'; 462 if (!dquote && !squote && temp[i] == ' ') temp[i] = '\0';
265 if (dquote && squote) { 463 if (dquote && squote) {
@@ -281,13 +479,14 @@ void x11_start_xephyr(int argc, char **argv) {
281 else if (temp[i] == '\0' && temp[i+1] != '\0') server_argv[pos++] = temp + i + 1; 479 else if (temp[i] == '\0' && temp[i+1] != '\0') server_argv[pos++] = temp + i + 1;
282 } 480 }
283 } 481 }
284 482
285 server_argv[pos++] = display_str; 483 server_argv[pos++] = display_str;
286 server_argv[pos++] = NULL; 484 server_argv[pos++] = NULL;
287 485
288 assert(pos < (sizeof(server_argv)/sizeof(*server_argv))); // no overrun 486 // no overrun
289 assert(server_argv[pos-1] == NULL); // last element is null 487 assert(pos < (sizeof(server_argv)/sizeof(*server_argv)));
290 488 assert(server_argv[pos-1] == NULL); // last element is null
489
291 if (arg_debug) { 490 if (arg_debug) {
292 size_t i = 0; 491 size_t i = 0;
293 printf("xephyr server:"); 492 printf("xephyr server:");
@@ -302,18 +501,14 @@ void x11_start_xephyr(int argc, char **argv) {
302 char *jail_argv[argc+2]; 501 char *jail_argv[argc+2];
303 int j = 0; 502 int j = 0;
304 for (i = 0; i < argc; i++) { 503 for (i = 0; i < argc; i++) {
305 if (strcmp(argv[i], "--x11") == 0) 504 if (strncmp(argv[i], "--x11", 5) == 0)
306 continue;
307 if (strcmp(argv[i], "--x11=xpra") == 0)
308 continue;
309 if (strcmp(argv[i], "--x11=xephyr") == 0)
310 continue; 505 continue;
311 jail_argv[j] = argv[i]; 506 jail_argv[j] = argv[i];
312 j++; 507 j++;
313 } 508 }
314 jail_argv[j] = NULL; 509 jail_argv[j] = NULL;
315 510
316 assert(j < argc+2); // no overrun 511 assert(j < argc+2); // no overrun
317 512
318 if (arg_debug) { 513 if (arg_debug) {
319 size_t i = 0; 514 size_t i = 0;
@@ -324,7 +519,7 @@ void x11_start_xephyr(int argc, char **argv) {
324 } 519 }
325 putchar('\n'); 520 putchar('\n');
326 } 521 }
327 522
328 server = fork(); 523 server = fork();
329 if (server < 0) 524 if (server < 0)
330 errExit("fork"); 525 errExit("fork");
@@ -333,7 +528,7 @@ void x11_start_xephyr(int argc, char **argv) {
333 printf("Starting xephyr...\n"); 528 printf("Starting xephyr...\n");
334 529
335 // running without privileges - see drop_privs call above 530 // running without privileges - see drop_privs call above
336 assert(getenv("LD_PRELOAD") == NULL); 531 assert(getenv("LD_PRELOAD") == NULL);
337 execvp(server_argv[0], server_argv); 532 execvp(server_argv[0], server_argv);
338 perror("execvp"); 533 perror("execvp");
339 _exit(1); 534 _exit(1);
@@ -353,17 +548,17 @@ void x11_start_xephyr(int argc, char **argv) {
353 if (stat(fname, &s) == 0) 548 if (stat(fname, &s) == 0)
354 break; 549 break;
355 }; 550 };
356 551
357 if (n == 10) { 552 if (n == 10) {
358 fprintf(stderr, "Error: failed to start xephyr\n"); 553 fprintf(stderr, "Error: failed to start xephyr\n");
359 exit(1); 554 exit(1);
360 } 555 }
361 free(fname); 556 free(fname);
362 557
363 if (arg_debug) { 558 if (arg_debug) {
364 printf("X11 sockets: "); fflush(0); 559 printf("X11 sockets: "); fflush(0);
365 int rv = system("ls /tmp/.X11-unix"); 560 int rv = system("ls /tmp/.X11-unix");
366 (void) rv; 561 (void) rv;
367 } 562 }
368 563
369 setenv("DISPLAY", display_str, 1); 564 setenv("DISPLAY", display_str, 1);
@@ -376,7 +571,7 @@ void x11_start_xephyr(int argc, char **argv) {
376 printf("\n*** Attaching to Xephyr display %d ***\n\n", display); 571 printf("\n*** Attaching to Xephyr display %d ***\n\n", display);
377 572
378 // running without privileges - see drop_privs call above 573 // running without privileges - see drop_privs call above
379 assert(getenv("LD_PRELOAD") == NULL); 574 assert(getenv("LD_PRELOAD") == NULL);
380 execvp(jail_argv[0], jail_argv); 575 execvp(jail_argv[0], jail_argv);
381 perror("execvp"); 576 perror("execvp");
382 _exit(1); 577 _exit(1);
@@ -392,25 +587,27 @@ void x11_start_xephyr(int argc, char **argv) {
392 // see which process terminated and kill other 587 // see which process terminated and kill other
393 if (pid == server) { 588 if (pid == server) {
394 kill(jail, SIGTERM); 589 kill(jail, SIGTERM);
395 } else if (pid == jail) { 590 }
591 else if (pid == jail) {
396 kill(server, SIGTERM); 592 kill(server, SIGTERM);
397 } 593 }
398 594
399 // without this closing Xephyr window may mess your terminal: 595 // without this closing Xephyr window may mess your terminal:
400 // "monitoring" process will release terminal before 596 // "monitoring" process will release terminal before
401 // jail process ends and releases terminal 597 // jail process ends and releases terminal
402 wait(NULL); // fulneral 598 wait(NULL); // fulneral
403 599
404 exit(0); 600 exit(0);
405} 601}
406 602
603
407void x11_start_xpra(int argc, char **argv) { 604void x11_start_xpra(int argc, char **argv) {
408 EUID_ASSERT(); 605 EUID_ASSERT();
409 int i; 606 int i;
410 struct stat s; 607 struct stat s;
411 pid_t client = 0; 608 pid_t client = 0;
412 pid_t server = 0; 609 pid_t server = 0;
413 610
414 setenv("FIREJAIL_X11", "yes", 1); 611 setenv("FIREJAIL_X11", "yes", 1);
415 612
416 // unfortunately, xpra does a number of weird things when started by root user!!! 613 // unfortunately, xpra does a number of weird things when started by root user!!!
@@ -426,7 +623,7 @@ void x11_start_xpra(int argc, char **argv) {
426 fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); 623 fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n");
427 exit(0); 624 exit(0);
428 } 625 }
429 626
430 int display = random_display_number(); 627 int display = random_display_number();
431 char *display_str; 628 char *display_str;
432 if (asprintf(&display_str, ":%d", display) == -1) 629 if (asprintf(&display_str, ":%d", display) == -1)
@@ -455,9 +652,9 @@ void x11_start_xpra(int argc, char **argv) {
455 dup2(fd_null,1); 652 dup2(fd_null,1);
456 dup2(fd_null,2); 653 dup2(fd_null,2);
457 } 654 }
458 655
459 // running without privileges - see drop_privs call above 656 // running without privileges - see drop_privs call above
460 assert(getenv("LD_PRELOAD") == NULL); 657 assert(getenv("LD_PRELOAD") == NULL);
461 execvp(server_argv[0], server_argv); 658 execvp(server_argv[0], server_argv);
462 perror("execvp"); 659 perror("execvp");
463 _exit(1); 660 _exit(1);
@@ -477,18 +674,18 @@ void x11_start_xpra(int argc, char **argv) {
477 if (stat(fname, &s) == 0) 674 if (stat(fname, &s) == 0)
478 break; 675 break;
479 } 676 }
480 677
481 if (n == 10) { 678 if (n == 10) {
482 fprintf(stderr, "Error: failed to start xpra\n"); 679 fprintf(stderr, "Error: failed to start xpra\n");
483 exit(1); 680 exit(1);
484 } 681 }
485 free(fname); 682 free(fname);
486 683
487 if (arg_debug) { 684 if (arg_debug) {
488 printf("X11 sockets: "); fflush(0); 685 printf("X11 sockets: "); fflush(0);
489 int rv = system("ls /tmp/.X11-unix"); 686 int rv = system("ls /tmp/.X11-unix");
490 (void) rv; 687 (void) rv;
491 } 688 }
492 689
493 // build attach command 690 // build attach command
494 char *attach_argv[] = { "xpra", "--title=\"firejail x11 sandbox\"", "attach", display_str, NULL }; 691 char *attach_argv[] = { "xpra", "--title=\"firejail x11 sandbox\"", "attach", display_str, NULL };
@@ -508,7 +705,7 @@ void x11_start_xpra(int argc, char **argv) {
508 printf("\n*** Attaching to xpra display %d ***\n\n", display); 705 printf("\n*** Attaching to xpra display %d ***\n\n", display);
509 706
510 // running without privileges - see drop_privs call above 707 // running without privileges - see drop_privs call above
511 assert(getenv("LD_PRELOAD") == NULL); 708 assert(getenv("LD_PRELOAD") == NULL);
512 execvp(attach_argv[0], attach_argv); 709 execvp(attach_argv[0], attach_argv);
513 perror("execvp"); 710 perror("execvp");
514 _exit(1); 711 _exit(1);
@@ -520,11 +717,7 @@ void x11_start_xpra(int argc, char **argv) {
520 char *firejail_argv[argc+2]; 717 char *firejail_argv[argc+2];
521 int pos = 0; 718 int pos = 0;
522 for (i = 0; i < argc; i++) { 719 for (i = 0; i < argc; i++) {
523 if (strcmp(argv[i], "--x11") == 0) 720 if (strncmp(argv[i], "--x11", 5) == 0)
524 continue;
525 if (strcmp(argv[i], "--x11=xpra") == 0)
526 continue;
527 if (strcmp(argv[i], "--x11=xephyr") == 0)
528 continue; 721 continue;
529 firejail_argv[pos] = argv[i]; 722 firejail_argv[pos] = argv[i];
530 pos++; 723 pos++;
@@ -540,8 +733,8 @@ void x11_start_xpra(int argc, char **argv) {
540 errExit("fork"); 733 errExit("fork");
541 if (jail == 0) { 734 if (jail == 0) {
542 // running without privileges - see drop_privs call above 735 // running without privileges - see drop_privs call above
543 assert(getenv("LD_PRELOAD") == NULL); 736 assert(getenv("LD_PRELOAD") == NULL);
544 if (firejail_argv[0]) // shut up llvm scan-build 737 if (firejail_argv[0]) // shut up llvm scan-build
545 execvp(firejail_argv[0], firejail_argv); 738 execvp(firejail_argv[0], firejail_argv);
546 perror("execvp"); 739 perror("execvp");
547 exit(1); 740 exit(1);
@@ -550,8 +743,8 @@ void x11_start_xpra(int argc, char **argv) {
550 if (!arg_quiet) 743 if (!arg_quiet)
551 printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail); 744 printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail);
552 745
553 sleep(1); // let jail start 746 sleep(1); // adding a delay in order to let the server start
554 747
555 // wait for jail or server to end 748 // wait for jail or server to end
556 while (1) { 749 while (1) {
557 pid_t pid = wait(NULL); 750 pid_t pid = wait(NULL);
@@ -568,7 +761,7 @@ void x11_start_xpra(int argc, char **argv) {
568 dup2(fd_null,2); 761 dup2(fd_null,2);
569 } 762 }
570 // running without privileges - see drop_privs call above 763 // running without privileges - see drop_privs call above
571 assert(getenv("LD_PRELOAD") == NULL); 764 assert(getenv("LD_PRELOAD") == NULL);
572 execvp(stop_argv[0], stop_argv); 765 execvp(stop_argv[0], stop_argv);
573 perror("execvp"); 766 perror("execvp");
574 _exit(1); 767 _exit(1);
@@ -588,7 +781,7 @@ void x11_start_xpra(int argc, char **argv) {
588 else 781 else
589 printf("xpra server successfully stopped in %d secs\n", n); 782 printf("xpra server successfully stopped in %d secs\n", n);
590 } 783 }
591 784
592 // kill xpra server and xpra client 785 // kill xpra server and xpra client
593 kill(client, SIGTERM); 786 kill(client, SIGTERM);
594 kill(server, SIGTERM); 787 kill(server, SIGTERM);
@@ -604,6 +797,7 @@ void x11_start_xpra(int argc, char **argv) {
604 } 797 }
605} 798}
606 799
800
607void x11_start(int argc, char **argv) { 801void x11_start(int argc, char **argv) {
608 EUID_ASSERT(); 802 EUID_ASSERT();
609 803
@@ -628,7 +822,7 @@ void x11_start(int argc, char **argv) {
628#endif 822#endif
629 823
630// Porting notes: 824// Porting notes:
631// 825//
632// 1. merge #1100 from zackw: 826// 1. merge #1100 from zackw:
633// Attempting to run xauth -f directly on a file in /run/firejail/mnt/ directory fails on Debian 8 827// Attempting to run xauth -f directly on a file in /run/firejail/mnt/ directory fails on Debian 8
634// with this message: 828// with this message:
@@ -653,7 +847,7 @@ void x11_xorg(void) {
653 struct stat s; 847 struct stat s;
654 if (stat("/usr/bin/xauth", &s) == -1) { 848 if (stat("/usr/bin/xauth", &s) == -1) {
655 fprintf(stderr, "Error: xauth utility not found in PATH. Please install it:\n" 849 fprintf(stderr, "Error: xauth utility not found in PATH. Please install it:\n"
656 " Debian/Ubuntu/Mint: sudo apt-get install xauth\n"); 850 " Debian/Ubuntu/Mint: sudo apt-get install xauth\n");
657 exit(1); 851 exit(1);
658 } 852 }
659 if (s.st_uid != 0 && s.st_gid != 0) { 853 if (s.st_uid != 0 && s.st_gid != 0) {
@@ -695,8 +889,8 @@ void x11_xorg(void) {
695 __gcov_flush(); 889 __gcov_flush();
696#endif 890#endif
697 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-v", "-f", tmpfname, 891 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-v", "-f", tmpfname,
698 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL); 892 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL);
699 893
700 _exit(127); 894 _exit(127);
701 } 895 }
702 896
@@ -705,16 +899,19 @@ void x11_xorg(void) {
705 if (waitpid(child, &status, 0) != child) 899 if (waitpid(child, &status, 0) != child)
706 errExit("waitpid"); 900 errExit("waitpid");
707 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 901 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
708 /* success */ 902 /* success */
709 } else if (WIFEXITED(status)) { 903 }
904 else if (WIFEXITED(status)) {
710 fprintf(stderr, "Failed to create untrusted X cookie: xauth: exit %d\n", 905 fprintf(stderr, "Failed to create untrusted X cookie: xauth: exit %d\n",
711 WEXITSTATUS(status)); 906 WEXITSTATUS(status));
712 exit(1); 907 exit(1);
713 } else if (WIFSIGNALED(status)) { 908 }
909 else if (WIFSIGNALED(status)) {
714 fprintf(stderr, "Failed to create untrusted X cookie: xauth: %s\n", 910 fprintf(stderr, "Failed to create untrusted X cookie: xauth: %s\n",
715 strsignal(WTERMSIG(status))); 911 strsignal(WTERMSIG(status)));
716 exit(1); 912 exit(1);
717 } else { 913 }
914 else {
718 fprintf(stderr, "Failed to create untrusted X cookie: " 915 fprintf(stderr, "Failed to create untrusted X cookie: "
719 "xauth: un-decodable exit status %04x\n", status); 916 "xauth: un-decodable exit status %04x\n", status);
720 exit(1); 917 exit(1);
@@ -728,10 +925,11 @@ void x11_xorg(void) {
728 } 925 }
729 if (set_perms(tmpfname, getuid(), getgid(), 0600)) 926 if (set_perms(tmpfname, getuid(), getgid(), 0600))
730 errExit("set_perms"); 927 errExit("set_perms");
731 928
732 // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted 929 // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted
733 // automatically when the sandbox is closed (rename doesn't work) 930 // automatically when the sandbox is closed (rename doesn't work)
734 if (copy_file(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600)) { // root needed 931 // root needed
932 if (copy_file(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600)) {
735 fprintf(stderr, "Error: cannot create the new .Xauthority file\n"); 933 fprintf(stderr, "Error: cannot create the new .Xauthority file\n");
736 exit(1); 934 exit(1);
737 } 935 }
@@ -740,7 +938,6 @@ void x11_xorg(void) {
740 /* coverity[toctou] */ 938 /* coverity[toctou] */
741 unlink(tmpfname); 939 unlink(tmpfname);
742 umount("/tmp"); 940 umount("/tmp");
743
744 941
745 // Ensure there is already a file in the usual location, so that bind-mount below will work. 942 // Ensure there is already a file in the usual location, so that bind-mount below will work.
746 // todo: fix TOCTOU races, currently managed by imposing /usr/bin/xauth as executable 943 // todo: fix TOCTOU races, currently managed by imposing /usr/bin/xauth as executable
@@ -765,9 +962,10 @@ void x11_xorg(void) {
765 if (set_perms(dest, getuid(), getgid(), 0600)) 962 if (set_perms(dest, getuid(), getgid(), 0600))
766 errExit("set_perms"); 963 errExit("set_perms");
767 free(dest); 964 free(dest);
768#endif 965#endif
769} 966}
770 967
968
771void fs_x11(void) { 969void fs_x11(void) {
772#ifdef HAVE_X11 970#ifdef HAVE_X11
773 int display = x11_display(); 971 int display = x11_display();
@@ -786,63 +984,62 @@ void fs_x11(void) {
786 if (arg_debug || arg_debug_whitelists) 984 if (arg_debug || arg_debug_whitelists)
787 fprintf(stderr, "Masking all X11 sockets except %s\n", x11file); 985 fprintf(stderr, "Masking all X11 sockets except %s\n", x11file);
788 986
789 // Move the real /tmp/.X11-unix to a scratch location 987 // Move the real /tmp/.X11-unix to a scratch location
790 // so we can still access x11file after we mount a 988 // so we can still access x11file after we mount a
791 // tmpfs over /tmp/.X11-unix. 989 // tmpfs over /tmp/.X11-unix.
792 int rv = mkdir(RUN_WHITELIST_X11_DIR, 0700); 990 int rv = mkdir(RUN_WHITELIST_X11_DIR, 0700);
793 if (rv == -1) 991 if (rv == -1)
794 errExit("mkdir"); 992 errExit("mkdir");
795 if (set_perms(RUN_WHITELIST_X11_DIR, 0, 0, 0700)) 993 if (set_perms(RUN_WHITELIST_X11_DIR, 0, 0, 0700))
796 errExit("set_perms"); 994 errExit("set_perms");
797 995
798 if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0) 996 if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0)
799 errExit("mount bind"); 997 errExit("mount bind");
800 998
801 // This directory must be mode 1777, or Xlib will barf. 999 // This directory must be mode 1777, or Xlib will barf.
802 if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", 1000 if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs",
803 MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC, 1001 MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC,
804 "mode=1777,uid=0,gid=0") < 0) 1002 "mode=1777,uid=0,gid=0") < 0)
805 errExit("mounting tmpfs on /tmp/.X11-unix"); 1003 errExit("mounting tmpfs on /tmp/.X11-unix");
806 fs_logger("tmpfs /tmp/.X11-unix"); 1004 fs_logger("tmpfs /tmp/.X11-unix");
807 1005
808 // create an empty file which will have the desired socket bind-mounted over it 1006 // create an empty file which will have the desired socket bind-mounted over it
809 int fd = open(x11file, O_RDWR|O_CREAT|O_EXCL, x11stat.st_mode & ~S_IFMT); 1007 int fd = open(x11file, O_RDWR|O_CREAT|O_EXCL, x11stat.st_mode & ~S_IFMT);
810 if (fd < 0) 1008 if (fd < 0)
811 errExit(x11file); 1009 errExit(x11file);
812 if (fchown(fd, x11stat.st_uid, x11stat.st_gid)) 1010 if (fchown(fd, x11stat.st_uid, x11stat.st_gid))
813 errExit("fchown"); 1011 errExit("fchown");
814 close(fd); 1012 close(fd);
815 1013
816 // do the mount 1014 // do the mount
817 char *wx11file; 1015 char *wx11file;
818 if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1) 1016 if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1)
819 errExit("asprintf"); 1017 errExit("asprintf");
820 if (mount(wx11file, x11file, NULL, MS_BIND|MS_REC, NULL) < 0) 1018 if (mount(wx11file, x11file, NULL, MS_BIND|MS_REC, NULL) < 0)
821 errExit("mount bind"); 1019 errExit("mount bind");
822 fs_logger2("whitelist", x11file); 1020 fs_logger2("whitelist", x11file);
823 1021
824 free(x11file); 1022 free(x11file);
825 free(wx11file); 1023 free(wx11file);
826 1024
827 // block access to RUN_WHITELIST_X11_DIR 1025 // block access to RUN_WHITELIST_X11_DIR
828 if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, 0, MS_BIND, 0) < 0) 1026 if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, 0, MS_BIND, 0) < 0)
829 errExit("mount"); 1027 errExit("mount");
830 fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); 1028 fs_logger2("blacklist", RUN_WHITELIST_X11_DIR);
831#endif 1029#endif
832} 1030}
833 1031
1032
834void x11_block(void) { 1033void x11_block(void) {
835#ifdef HAVE_X11 1034#ifdef HAVE_X11
836 mask_x11_abstract_socket = 1;
837
838 // check abstract socket presence and network namespace options 1035 // check abstract socket presence and network namespace options
839 if ((!arg_nonetwork && !cfg.bridge0.configured && !cfg.interface0.configured) 1036 if ((!arg_nonetwork && !cfg.bridge0.configured && !cfg.interface0.configured)
840 && x11_abstract_sockets_present()) { 1037 && x11_abstract_sockets_present()) {
841 fprintf(stderr, "ERROR: --x11=none specified, but abstract X11 socket still accessible.\n" 1038 fprintf(stderr, "ERROR: --x11=none specified, but abstract X11 socket still accessible.\n"
842 "Additional setup required. To block abstract X11 socket you can either:\n" 1039 "Additional setup required. To block abstract X11 socket you can either:\n"
843 " * use network namespace in firejail (--net=none, --net=...)\n" 1040 " * use network namespace in firejail (--net=none, --net=...)\n"
844 " * add \"-nolisten local\" to xserver options\n" 1041 " * add \"-nolisten local\" to xserver options\n"
845 " (eg. to your display manager config, or /etc/X11/xinit/xserverrc)\n"); 1042 " (eg. to your display manager config, or /etc/X11/xinit/xserverrc)\n");
846 exit(1); 1043 exit(1);
847 } 1044 }
848 1045
@@ -867,4 +1064,3 @@ void x11_block(void) {
867 env_store("XAUTHORITY", RMENV); 1064 env_store("XAUTHORITY", RMENV);
868#endif 1065#endif
869} 1066}
870
diff --git a/src/firemon/arp.c b/src/firemon/arp.c
index cef48fb0d..d30983e4a 100644
--- a/src/firemon/arp.c
+++ b/src/firemon/arp.c
@@ -80,7 +80,7 @@ void arp(pid_t pid, int print_procs) {
80 for (i = 0; i < max_pids; i++) { 80 for (i = 0; i < max_pids; i++) {
81 if (pids[i].level == 1) { 81 if (pids[i].level == 1) {
82 if (print_procs || pid == 0) 82 if (print_procs || pid == 0)
83 pid_print_list(i, 0); 83 pid_print_list(i, arg_nowrap);
84 int child = find_child(i); 84 int child = find_child(i);
85 if (child != -1) { 85 if (child != -1) {
86 char *fname; 86 char *fname;
diff --git a/src/firemon/caps.c b/src/firemon/caps.c
index 8837c9ee7..a13b784a2 100644
--- a/src/firemon/caps.c
+++ b/src/firemon/caps.c
@@ -38,9 +38,7 @@ static void print_caps(int pid) {
38 if (strncmp(buf, "CapBnd:", 7) == 0) { 38 if (strncmp(buf, "CapBnd:", 7) == 0) {
39 printf(" %s", buf); 39 printf(" %s", buf);
40 fflush(0); 40 fflush(0);
41 free(file); 41 break;
42 fclose(fp);
43 return;
44 } 42 }
45 } 43 }
46 fclose(fp); 44 fclose(fp);
@@ -55,7 +53,7 @@ void caps(pid_t pid, int print_procs) {
55 for (i = 0; i < max_pids; i++) { 53 for (i = 0; i < max_pids; i++) {
56 if (pids[i].level == 1) { 54 if (pids[i].level == 1) {
57 if (print_procs || pid == 0) 55 if (print_procs || pid == 0)
58 pid_print_list(i, 0); 56 pid_print_list(i, arg_nowrap);
59 int child = find_child(i); 57 int child = find_child(i);
60 if (child != -1) 58 if (child != -1)
61 print_caps(child); 59 print_caps(child);
diff --git a/src/firemon/cgroup.c b/src/firemon/cgroup.c
index bbb28f619..48427210b 100644
--- a/src/firemon/cgroup.c
+++ b/src/firemon/cgroup.c
@@ -52,7 +52,7 @@ void cgroup(pid_t pid, int print_procs) {
52 for (i = 0; i < max_pids; i++) { 52 for (i = 0; i < max_pids; i++) {
53 if (pids[i].level == 1) { 53 if (pids[i].level == 1) {
54 if (print_procs || pid == 0) 54 if (print_procs || pid == 0)
55 pid_print_list(i, 0); 55 pid_print_list(i, arg_nowrap);
56 int child = find_child(i); 56 int child = find_child(i);
57 if (child != -1) 57 if (child != -1)
58 print_cgroup(child); 58 print_cgroup(child);
diff --git a/src/firemon/cpu.c b/src/firemon/cpu.c
index 47c935686..2a6979573 100644
--- a/src/firemon/cpu.c
+++ b/src/firemon/cpu.c
@@ -39,9 +39,7 @@ static void print_cpu(int pid) {
39 if (strncmp(buf, "Cpus_allowed_list:", 18) == 0) { 39 if (strncmp(buf, "Cpus_allowed_list:", 18) == 0) {
40 printf(" %s", buf); 40 printf(" %s", buf);
41 fflush(0); 41 fflush(0);
42 free(file); 42 break;
43 fclose(fp);
44 return;
45 } 43 }
46 } 44 }
47 fclose(fp); 45 fclose(fp);
@@ -56,7 +54,7 @@ void cpu(pid_t pid, int print_procs) {
56 for (i = 0; i < max_pids; i++) { 54 for (i = 0; i < max_pids; i++) {
57 if (pids[i].level == 1) { 55 if (pids[i].level == 1) {
58 if (print_procs || pid == 0) 56 if (print_procs || pid == 0)
59 pid_print_list(i, 0); 57 pid_print_list(i, arg_nowrap);
60 int child = find_child(i); 58 int child = find_child(i);
61 if (child != -1) 59 if (child != -1)
62 print_cpu(child); 60 print_cpu(child);
diff --git a/src/firemon/interface.c b/src/firemon/interface.c
index ba3c9fceb..77dd1f277 100644
--- a/src/firemon/interface.c
+++ b/src/firemon/interface.c
@@ -163,7 +163,7 @@ void interface(pid_t pid, int print_procs) {
163 for (i = 0; i < max_pids; i++) { 163 for (i = 0; i < max_pids; i++) {
164 if (pids[i].level == 1) { 164 if (pids[i].level == 1) {
165 if (print_procs || pid == 0) 165 if (print_procs || pid == 0)
166 pid_print_list(i, 0); 166 pid_print_list(i, arg_nowrap);
167 int child = find_child(i); 167 int child = find_child(i);
168 if (child != -1) { 168 if (child != -1) {
169 print_sandbox(child); 169 print_sandbox(child);
diff --git a/src/firemon/list.c b/src/firemon/list.c
index 1df737e8c..2152df31f 100644
--- a/src/firemon/list.c
+++ b/src/firemon/list.c
@@ -26,7 +26,7 @@ void list(void) {
26 int i; 26 int i;
27 for (i = 0; i < max_pids; i++) { 27 for (i = 0; i < max_pids; i++) {
28 if (pids[i].level == 1) 28 if (pids[i].level == 1)
29 pid_print_list(i, 0); 29 pid_print_list(i, arg_nowrap);
30 } 30 }
31} 31}
32 32
diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c
index ebcb7a72c..378bdefe9 100644
--- a/src/firemon/procevent.c
+++ b/src/firemon/procevent.c
@@ -150,10 +150,8 @@ doexit:
150static int procevent_netlink_setup(void) { 150static int procevent_netlink_setup(void) {
151 // open socket for process event connector 151 // open socket for process event connector
152 int sock; 152 int sock;
153 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR)) < 0) { 153 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR)) < 0)
154 fprintf(stderr, "Error: cannot open netlink socket\n"); 154 goto errexit;
155 exit(1);
156 }
157 155
158 // bind socket 156 // bind socket
159 struct sockaddr_nl addr; 157 struct sockaddr_nl addr;
@@ -161,10 +159,8 @@ static int procevent_netlink_setup(void) {
161 addr.nl_pid = getpid(); 159 addr.nl_pid = getpid();
162 addr.nl_family = AF_NETLINK; 160 addr.nl_family = AF_NETLINK;
163 addr.nl_groups = CN_IDX_PROC; 161 addr.nl_groups = CN_IDX_PROC;
164 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 162 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
165 fprintf(stderr, "Error: cannot bind to netlink socket\n"); 163 goto errexit;
166 exit(1);
167 }
168 164
169 // send monitoring message 165 // send monitoring message
170 struct nlmsghdr nlmsghdr; 166 struct nlmsghdr nlmsghdr;
@@ -189,12 +185,13 @@ static int procevent_netlink_setup(void) {
189 iov[2].iov_base = &op; 185 iov[2].iov_base = &op;
190 iov[2].iov_len = sizeof(op); 186 iov[2].iov_len = sizeof(op);
191 187
192 if (writev(sock, iov, 3) == -1) { 188 if (writev(sock, iov, 3) == -1)
193 fprintf(stderr, "Error: cannot write to netlink socket\n"); 189 goto errexit;
194 exit(1);
195 }
196 190
197 return sock; 191 return sock;
192errexit:
193 fprintf(stderr, "Error: netlink socket problem\n");
194 exit(1);
198} 195}
199 196
200 197
diff --git a/src/firemon/route.c b/src/firemon/route.c
index dff594431..145daa152 100644
--- a/src/firemon/route.c
+++ b/src/firemon/route.c
@@ -189,7 +189,7 @@ void route(pid_t pid, int print_procs) {
189 for (i = 0; i < max_pids; i++) { 189 for (i = 0; i < max_pids; i++) {
190 if (pids[i].level == 1) { 190 if (pids[i].level == 1) {
191 if (print_procs || pid == 0) 191 if (print_procs || pid == 0)
192 pid_print_list(i, 0); 192 pid_print_list(i, arg_nowrap);
193 int child = find_child(i); 193 int child = find_child(i);
194 if (child != -1) { 194 if (child != -1) {
195 char *fname; 195 char *fname;
diff --git a/src/firemon/seccomp.c b/src/firemon/seccomp.c
index d50692b37..e530fa1c3 100644
--- a/src/firemon/seccomp.c
+++ b/src/firemon/seccomp.c
@@ -37,9 +37,7 @@ static void print_seccomp(int pid) {
37 if (strncmp(buf, "Seccomp:", 8) == 0) { 37 if (strncmp(buf, "Seccomp:", 8) == 0) {
38 printf(" %s", buf); 38 printf(" %s", buf);
39 fflush(0); 39 fflush(0);
40 fclose(fp); 40 break;
41 free(file);
42 return;
43 } 41 }
44 } 42 }
45 fclose(fp); 43 fclose(fp);
@@ -54,7 +52,7 @@ void seccomp(pid_t pid, int print_procs) {
54 for (i = 0; i < max_pids; i++) { 52 for (i = 0; i < max_pids; i++) {
55 if (pids[i].level == 1) { 53 if (pids[i].level == 1) {
56 if (print_procs || pid == 0) 54 if (print_procs || pid == 0)
57 pid_print_list(i, 0); 55 pid_print_list(i, arg_nowrap);
58 int child = find_child(i); 56 int child = find_child(i);
59 if (child != -1) 57 if (child != -1)
60 print_seccomp(child); 58 print_seccomp(child);
diff --git a/src/firemon/usage.c b/src/firemon/usage.c
index 1768237b3..20f2c071b 100644
--- a/src/firemon/usage.c
+++ b/src/firemon/usage.c
@@ -37,6 +37,7 @@ void usage(void) {
37 printf("\t--name=name - print information only about named sandbox.\n\n"); 37 printf("\t--name=name - print information only about named sandbox.\n\n");
38 printf("\t--netstats - monitor network statistics for sandboxes creating a new\n"); 38 printf("\t--netstats - monitor network statistics for sandboxes creating a new\n");
39 printf("\t\tnetwork namespace.\n\n"); 39 printf("\t\tnetwork namespace.\n\n");
40 printf("\t--nowrap - enable line wrapping in terminals.\n\n");
40 printf("\t--route - print route table for each sandbox.\n\n"); 41 printf("\t--route - print route table for each sandbox.\n\n");
41 printf("\t--seccomp - print seccomp configuration for each sandbox.\n\n"); 42 printf("\t--seccomp - print seccomp configuration for each sandbox.\n\n");
42 printf("\t--tree - print a tree of all sandboxed processes.\n\n"); 43 printf("\t--tree - print a tree of all sandboxed processes.\n\n");
diff --git a/src/firemon/x11.c b/src/firemon/x11.c
index 97cfffe64..c923c8ef8 100644
--- a/src/firemon/x11.c
+++ b/src/firemon/x11.c
@@ -30,7 +30,7 @@ void x11(pid_t pid, int print_procs) {
30 for (i = 0; i < max_pids; i++) { 30 for (i = 0; i < max_pids; i++) {
31 if (pids[i].level == 1) { 31 if (pids[i].level == 1) {
32 if (print_procs || pid == 0) 32 if (print_procs || pid == 0)
33 pid_print_list(i, 0); 33 pid_print_list(i, arg_nowrap);
34 34
35 char *x11file; 35 char *x11file;
36 // todo: use macro from src/firejail/firejail.h for /run/firejail/x11 directory 36 // todo: use macro from src/firejail/firejail.h for /run/firejail/x11 directory
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index aa1aec567..d60d48072 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -310,13 +310,16 @@ Remove DISPLAY and XAUTHORITY environment variables.
310Stop with error message if X11 abstract socket will be accessible in jail. 310Stop with error message if X11 abstract socket will be accessible in jail.
311.TP 311.TP
312\fBx11 xephyr 312\fBx11 xephyr
313Enable X11 sandboxing with xephyr. 313Enable X11 sandboxing with Xephyr server.
314.TP 314.TP
315\fBx11 xorg 315\fBx11 xorg
316Enable X11 sandboxing with X11 security extension. 316Enable X11 sandboxing with X11 security extension.
317.TP 317.TP
318\fBx11 xpra 318\fBx11 xpra
319Enable X11 sandboxing with xpra. 319Enable X11 sandboxing with Xpra server.
320.TP
321\fBx11 xvfb
322Enable X11 sandboxing with Xvfb server.
320 323
321.SH Resource limits, CPU affinity, Control Groups 324.SH Resource limits, CPU affinity, Control Groups
322These profile entries define the limits on system resources (rlimits) for the processes inside the sandbox. 325These profile entries define the limits on system resources (rlimits) for the processes inside the sandbox.
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index f978661dc..2b6069a7a 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -1772,17 +1772,17 @@ $ sudo firejail --writable-var-log
1772 1772
1773.TP 1773.TP
1774\fB\-\-x11 1774\fB\-\-x11
1775Sandbox the application using Xpra, Xephyr or Xorg security extension. 1775Sandbox the application using Xpra, Xephyr, Xvfb or Xorg security extension.
1776The sandbox will prevents screenshot and keylogger applications started inside the sandbox from accessing 1776The sandbox will prevents screenshot and keylogger applications started inside the sandbox from accessing
1777clients running outside the sandbox. 1777clients running outside the sandbox.
1778Firejail will try first Xpra, and if Xpra is not installed on the system, it will try to find Xephyr. 1778Firejail will try first Xpra, and if Xpra is not installed on the system, it will try to find Xephyr.
1779If all fails, Firejail will not attempt to use X11 security extension. 1779If all fails, Firejail will not attempt to use Xvfb or X11 security extension.
1780.br 1780.br
1781 1781
1782.br 1782.br
1783Xpra and Xephyr modes require a network namespace to be instantiated in order to disable 1783Xpra, Xephyr and Xvfb modes require a network namespace to be instantiated in order to disable
1784X11 abstract Unix socket. If this is not possible, the user can disable the abstract socket 1784X11 abstract Unix socket. If this is not possible, the user can disable the abstract socket
1785by adding "-nolisten local" on Xorg command line. 1785by adding "-nolisten local" on Xorg command line at system level.
1786.br 1786.br
1787 1787
1788.br 1788.br
@@ -1859,6 +1859,68 @@ Example:
1859.br 1859.br
1860$ firejail \-\-x11=xpra --net=eth0 firefox 1860$ firejail \-\-x11=xpra --net=eth0 firefox
1861 1861
1862
1863.TP
1864\fB\-\-x11=xvfb
1865Start Xvfb X11 server and attach the sandbox to this server.
1866Xvfb, short for X virtual framebuffer, performs all graphical operations in memory
1867without showing any screen output. Xvfb is mainly used for remote access and software
1868testing on headless servers.
1869.br
1870
1871.br
1872On Debian platforms Xvfb is installed with the command \fBsudo apt-get install xvfb\fR.
1873This feature is not available when running as root.
1874.br
1875
1876.br
1877Example: remote VNC access
1878.br
1879
1880.br
1881On the server we start a sandbox using Xvfb and openbox
1882window manager. The default size of Xvfb screen is 800x600 - it can be changed
1883in /etc/firejail/firejail.config (xvfb-screen). Some sort of networking (--net) is required
1884in order to isolate the abstract sockets used by other X servers.
1885.br
1886
1887.br
1888$ firejail --net=none --x11=xvfb openbox
1889.br
1890
1891.br
1892*** Attaching to Xvfb display 792 ***
1893.br
1894
1895.br
1896Reading profile /etc/firejail/openbox.profile
1897.br
1898Reading profile /etc/firejail/disable-common.inc
1899.br
1900Reading profile /etc/firejail/disable-common.local
1901.br
1902Parent pid 5400, child pid 5401
1903.br
1904
1905.br
1906On the server we also start a VNC server and attach it to the display handled by our
1907Xvfb server (792).
1908.br
1909
1910.br
1911$ x11vnc -display :792
1912.br
1913
1914.br
1915On the client machine we start a VNC viewer and use it to connect to our server:
1916.br
1917
1918.br
1919$ vncviewer
1920.br
1921
1922
1923
1862.TP 1924.TP
1863\fB\-\-zsh 1925\fB\-\-zsh
1864Use /usr/bin/zsh as default user shell. 1926Use /usr/bin/zsh as default user shell.
diff --git a/src/man/firemon.txt b/src/man/firemon.txt
index bd84401af..ecb626fc6 100644
--- a/src/man/firemon.txt
+++ b/src/man/firemon.txt
@@ -37,6 +37,9 @@ Print information only about named sandbox.
37\fB\-\-netstats 37\fB\-\-netstats
38Monitor network statistics for sandboxes creating a new network namespace. 38Monitor network statistics for sandboxes creating a new network namespace.
39.TP 39.TP
40\fB\-\-nowrap
41Enable line wrapping in terminals. By default the lines are trimmed.
42.TP
40\fB\-\-route 43\fB\-\-route
41Print route table for each sandbox. 44Print route table for each sandbox.
42.TP 45.TP
diff --git a/test/apps-x11-xorg/firefox.exp b/test/apps-x11-xorg/firefox.exp
index 4da9e5a16..4fd17caa6 100755
--- a/test/apps-x11-xorg/firefox.exp
+++ b/test/apps-x11-xorg/firefox.exp
@@ -41,7 +41,7 @@ expect {
41sleep 2 41sleep 2
42 42
43spawn $env(SHELL) 43spawn $env(SHELL)
44send -- "firemon --seccomp\r" 44send -- "firemon --seccomp --nowrap\r"
45expect { 45expect {
46 timeout {puts "TESTING ERROR 5\n";exit} 46 timeout {puts "TESTING ERROR 5\n";exit}
47 "need to be root" {puts "/proc mounted as hidepid, exiting...\n"; exit} 47 "need to be root" {puts "/proc mounted as hidepid, exiting...\n"; exit}
@@ -61,7 +61,7 @@ expect {
61 "name=blablabla" 61 "name=blablabla"
62} 62}
63sleep 1 63sleep 1
64send -- "firemon --caps\r" 64send -- "firemon --caps --nowrap\r"
65expect { 65expect {
66 timeout {puts "TESTING ERROR 6\n";exit} 66 timeout {puts "TESTING ERROR 6\n";exit}
67 " firefox" {puts "firefox detected\n";} 67 " firefox" {puts "firefox detected\n";}
diff --git a/test/apps-x11-xorg/icedove.exp b/test/apps-x11-xorg/icedove.exp
index ce1d38222..8f6722cd7 100755
--- a/test/apps-x11-xorg/icedove.exp
+++ b/test/apps-x11-xorg/icedove.exp
@@ -38,7 +38,7 @@ expect {
38sleep 2 38sleep 2
39 39
40spawn $env(SHELL) 40spawn $env(SHELL)
41send -- "firemon --seccomp\r" 41send -- "firemon --seccomp --nowrap\r"
42expect { 42expect {
43 timeout {puts "TESTING ERROR 5\n";exit} 43 timeout {puts "TESTING ERROR 5\n";exit}
44 "need to be root" {puts "/proc mounted as hidepid, exiting...\n"; exit} 44 "need to be root" {puts "/proc mounted as hidepid, exiting...\n"; exit}
@@ -57,7 +57,7 @@ expect {
57 "name=blablabla" 57 "name=blablabla"
58} 58}
59sleep 2 59sleep 2
60send -- "firemon --caps\r" 60send -- "firemon --caps --nowrap\r"
61expect { 61expect {
62 timeout {puts "TESTING ERROR 6\n";exit} 62 timeout {puts "TESTING ERROR 6\n";exit}
63 ":firejail" 63 ":firejail"
diff --git a/test/apps-x11-xorg/transmission-gtk.exp b/test/apps-x11-xorg/transmission-gtk.exp
index c6d9ba13a..3eb537c1b 100755
--- a/test/apps-x11-xorg/transmission-gtk.exp
+++ b/test/apps-x11-xorg/transmission-gtk.exp
@@ -38,7 +38,7 @@ expect {
38sleep 2 38sleep 2
39 39
40spawn $env(SHELL) 40spawn $env(SHELL)
41send -- "firemon --seccomp\r" 41send -- "firemon --seccomp --nowrap\r"
42expect { 42expect {
43 timeout {puts "TESTING ERROR 5\n";exit} 43 timeout {puts "TESTING ERROR 5\n";exit}
44 "need to be root" {puts "/proc mounted as hidepid, exiting...\n"; exit} 44 "need to be root" {puts "/proc mounted as hidepid, exiting...\n"; exit}
@@ -57,7 +57,7 @@ expect {
57 "name=blablabla" 57 "name=blablabla"
58} 58}
59sleep 1 59sleep 1
60send -- "firemon --caps\r" 60send -- "firemon --caps --nowrap\r"
61expect { 61expect {
62 timeout {puts "TESTING ERROR 6\n";exit} 62 timeout {puts "TESTING ERROR 6\n";exit}
63 ":firejail" 63 ":firejail"
diff --git a/test/environment/nice.exp b/test/environment/nice.exp
index 2c00d1485..50e789c9e 100755
--- a/test/environment/nice.exp
+++ b/test/environment/nice.exp
@@ -77,7 +77,48 @@ expect {
77 "top" 77 "top"
78} 78}
79 79
80sleep 1
81send -- "exit\r"
82after 100
83
84
85# negative nice value should result in nice=0
86send -- "firejail --nice=-5\r"
87expect {
88 timeout {puts "TESTING ERROR 17\n";exit}
89 "Child process initialized"
90}
91sleep 1
92
93send -- "top -b -n 1\r"
94expect {
95 timeout {puts "TESTING ERROR 18\n";exit}
96 $env(USER)
97}
98expect {
99 timeout {puts "TESTING ERROR 19\n";exit}
100 "0"
101}
102expect {
103 timeout {puts "TESTING ERROR 20\n";exit}
104 "bash"
105}
106expect {
107 timeout {puts "TESTING ERROR 21\n";exit}
108 $env(USER)
109}
110expect {
111 timeout {puts "TESTING ERROR 22\n";exit}
112 "0"
113}
114expect {
115 timeout {puts "TESTING ERROR 23\n";exit}
116 "top"
117}
80 118
119sleep 1
120send -- "exit\r"
121after 100
81 122
82puts "\nall done\n" 123puts "\nall done\n"
83 124
diff --git a/test/environment/output.exp b/test/environment/output.exp
index 10c325832..d175ddae2 100755
--- a/test/environment/output.exp
+++ b/test/environment/output.exp
@@ -61,5 +61,27 @@ expect {
61} 61}
62after 100 62after 100
63send -- "rm -f logfile*\r" 63send -- "rm -f logfile*\r"
64
65
66send -- "firejail --output=../logfile -- ./output.sh\r"
67expect {
68 timeout {puts "TESTING ERROR 8\n";exit}
69 "invalid output file"
70}
71after 100
72
73send -- "firejail --output=/etc -- ./output.sh\r"
74expect {
75 timeout {puts "TESTING ERROR 9\n";exit}
76 "invalid output file"
77}
78after 100
79
80send -- "firejail --output=/etc/firejail/zoom.profile -- ./output.sh\r"
81expect {
82 timeout {puts "TESTING ERROR 10\n";exit}
83 "the output file needs to be owned by the current user"
84}
85
64after 100 86after 100
65puts "\nall done\n" 87puts "\nall done\n"
diff --git a/test/filters/debug.exp b/test/filters/debug.exp
new file mode 100755
index 000000000..493022c05
--- /dev/null
+++ b/test/filters/debug.exp
@@ -0,0 +1,45 @@
1#!/usr/bin/expect -f
2# This file is part of Firejail project
3# Copyright (C) 2014-2017 Firejail Authors
4# License GPL v2
5
6set timeout 10
7spawn $env(SHELL)
8match_max 100000
9
10send -- "firejail --debug-syscalls\r"
11expect {
12 timeout {puts "TESTING ERROR 0\n";exit}
13 "set_mempolicy"
14}
15after 100
16
17send -- "firejail --debug-syscalls\r"
18expect {
19 timeout {puts "TESTING ERROR 1\n";exit}
20 "setitimer"
21}
22after 100
23
24send -- "firejail --debug-errnos\r"
25expect {
26 timeout {puts "TESTING ERROR 2\n";exit}
27 "EBADMSG"
28}
29after 100
30
31send -- "firejail --debug-errnos\r"
32expect {
33 timeout {puts "TESTING ERROR 3\n";exit}
34 "ELIBMAX"
35}
36after 100
37
38send -- "firejail --debug-protocols\r"
39expect {
40 timeout {puts "TESTING ERROR 4\n";exit}
41 "unix, inet, inet6, netlink, packet"
42}
43after 100
44
45puts "all done\n"
diff --git a/test/filters/filters.sh b/test/filters/filters.sh
index 73e0e4d5c..4996e6d66 100755
--- a/test/filters/filters.sh
+++ b/test/filters/filters.sh
@@ -6,6 +6,9 @@
6export MALLOC_CHECK_=3 6export MALLOC_CHECK_=3
7export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) 7export MALLOC_PERTURB_=$(($RANDOM % 255 + 1))
8 8
9echo "TESTING: debug options (test/filters/debug.exp)"
10./debug.exp
11
9echo "TESTING: noroot (test/filters/noroot.exp)" 12echo "TESTING: noroot (test/filters/noroot.exp)"
10./noroot.exp 13./noroot.exp
11 14
diff --git a/test/root/git.exp b/test/root/git.exp
new file mode 100755
index 000000000..c5ddeee89
--- /dev/null
+++ b/test/root/git.exp
@@ -0,0 +1,51 @@
1#!/usr/bin/expect -f
2
3set timeout 10
4spawn $env(SHELL)
5match_max 100000
6
7
8
9send -- "firejail --version\r"
10expect {
11 timeout {puts "TESTING ERROR 1\n";exit}
12 "git install support is disabled" { puts "TESTING: git support not available in current build\n"; exit}
13 "git install support is enabled" { puts "git support available\n"}
14}
15
16set timeout 120
17send -- "firejail --git-install\r"
18expect {
19 timeout {puts "TESTING ERROR 2\n";exit}
20 "Cloning into"
21}
22expect {
23 timeout {puts "TESTING ERROR 3\n";exit}
24 "Configuration options"
25}
26expect {
27 timeout {puts "TESTING ERROR 4\n";exit}
28 "src/fseccomp/fseccomp default seccomp"
29}
30expect {
31 timeout {puts "TESTING ERROR 5\n";exit}
32 "Mainline git Firejail version was installed in"
33}
34after 100
35
36send -- "firejail --git-uninstall\r"
37expect {
38 timeout {puts "TESTING ERROR 6\n";exit}
39 "Cloning into"
40}
41expect {
42 timeout {puts "TESTING ERROR 7\n";exit}
43 "Configuration options"
44}
45expect {
46 timeout {puts "TESTING ERROR 8\n";exit}
47 "Firejail mainline git version uninstalled from"
48}
49after 100
50
51puts "\nall done\n"
diff --git a/test/root/root.sh b/test/root/root.sh
index 9764b3804..29c618772 100755
--- a/test/root/root.sh
+++ b/test/root/root.sh
@@ -62,6 +62,9 @@ echo "TESTING: fs whitelist mnt, opt, media (test/root/whitelist-mnt.exp)"
62echo "TESTING: join (test/root/join.exp)" 62echo "TESTING: join (test/root/join.exp)"
63./join.exp 63./join.exp
64 64
65echo "TESTING: git-install (test/root/git.exp)"
66./git.exp
67
65#******************************** 68#********************************
66# seccomp 69# seccomp
67#******************************** 70#********************************
diff --git a/test/utils/join.exp b/test/utils/join.exp
index b74b0b17a..d5c421676 100755
--- a/test/utils/join.exp
+++ b/test/utils/join.exp
@@ -16,6 +16,14 @@ expect {
16sleep 2 16sleep 2
17 17
18spawn $env(SHELL) 18spawn $env(SHELL)
19send -- "firejail --shell=none --join=jointesting\r"
20expect {
21 timeout {puts "TESTING ERROR 1\n";exit}
22 "shell=none set, but no command specified"
23}
24after 100
25
26
19send -- "firejail --join=jointesting\r" 27send -- "firejail --join=jointesting\r"
20expect { 28expect {
21 timeout {puts "TESTING ERROR 1\n";exit} 29 timeout {puts "TESTING ERROR 1\n";exit}