aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in3
-rw-r--r--README5
-rw-r--r--README.md35
-rw-r--r--RELNOTES2
-rw-r--r--etc/disable-programs.inc1
-rw-r--r--etc/inox.profile24
-rw-r--r--platform/debian/conffiles1
-rw-r--r--src/faudit/dbus.c2
-rw-r--r--src/firejail/bandwidth.c8
-rw-r--r--src/firejail/checkcfg.c4
-rw-r--r--src/firejail/cmdline.c12
-rw-r--r--src/firejail/env.c11
-rw-r--r--src/firejail/firejail.h5
-rw-r--r--src/firejail/fs.c14
-rw-r--r--src/firejail/fs_home.c5
-rw-r--r--src/firejail/join.c47
-rw-r--r--src/firejail/main.c193
-rw-r--r--src/firejail/network.txt2
-rw-r--r--src/firejail/no_sandbox.c7
-rw-r--r--src/firejail/restricted_shell.c33
-rw-r--r--src/firejail/sandbox.c45
-rw-r--r--src/firejail/x11.c100
-rwxr-xr-xtest/network/net_arp.exp2
-rw-r--r--todo3
24 files changed, 404 insertions, 160 deletions
diff --git a/Makefile.in b/Makefile.in
index 1142059a5..c91db3bc7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -48,7 +48,6 @@ clean:
48 rm -f test/environment/index.html 48 rm -f test/environment/index.html
49 rm -f test/environment/wget-log 49 rm -f test/environment/wget-log
50 rm -f test/sysutils/firejail_t* 50 rm -f test/sysutils/firejail_t*
51 cd test/compile; ./compile.sh --clean; cd ../..
52 cd test/dist-compile; ./compile.sh --clean; cd ../.. 51 cd test/dist-compile; ./compile.sh --clean; cd ../..
53 52
54distclean: clean 53distclean: clean
@@ -138,7 +137,7 @@ uninstall:
138 rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firecfg 137 rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firecfg
139 138
140DISTFILES = "src etc platform configure configure.ac Makefile.in install.sh mkman.sh mketc.sh mkdeb.sh mkuid.sh COPYING README RELNOTES" 139DISTFILES = "src etc platform configure configure.ac Makefile.in install.sh mkman.sh mketc.sh mkdeb.sh mkuid.sh COPYING README RELNOTES"
141DISTFILES_TEST = "test/apps test/apps-x11 test/environment test/profiles test/utils test/compile test/dist-compile test/filters test/network test/fs test/sysutils" 140DISTFILES_TEST = "test/apps test/apps-x11 test/environment test/profiles test/utils test/dist-compile test/filters test/network test/fs test/sysutils"
142 141
143dist: 142dist:
144 make distclean 143 make distclean
diff --git a/README b/README
index 292d9a522..12bb8bf49 100644
--- a/README
+++ b/README
@@ -38,6 +38,11 @@ Aleksey Manevich (https://github.com/manevich)
38 - spliting up cmdline.c 38 - spliting up cmdline.c
39 - Busybox support 39 - Busybox support
40 - X11 support rewrite 40 - X11 support rewrite
41 - gether shell selection code in one place
42Gaman Gabriel (https://github.com/stelariusinfinitek)
43 - inox profile
44Laurent Declercq (https://github.com/nuxwin)
45 - fixed test for shell interpreter in chroots
41Franco (nextime) Lanza (https://github.com/nextime) 46Franco (nextime) Lanza (https://github.com/nextime)
42 - added --private-template 47 - added --private-template
43xee5ch (https://github.com/xee5ch) 48xee5ch (https://github.com/xee5ch)
diff --git a/README.md b/README.md
index 3047bf908..04965a97a 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,39 @@ FAQ: https://firejail.wordpress.com/support/frequently-asked-questions/
38 38
39Version 0.9.41~rc1 was released. 39Version 0.9.41~rc1 was released.
40 40
41# Branch status: unstable
42
43A number of problems are being worked on. This is the output of "make test":
44`````
45[...]
46cd test/sysutils; ./sysutils.sh | grep TESTING
47TESTING: cpio
48netblue@debian:~/work/github/firejail/test/sysutils$ TESTING ERROR 1
49TESTING: gzip
50netblue@debian:~/work/github/firejail/test/sysutils$ TESTING ERROR 1
51TESTING: xzdec
52netblue@debian:~/work/github/firejail/test/sysutils$ TESTING ERROR 1
53TESTING: xz
54netblue@debian:~/work/github/firejail/test/sysutils$ TESTING ERROR 1
55TESTING: less
56TESTING: file
57TESTING: tar
58netblue@debian:~/work/github/firejail/test/sysutils$ TESTING ERROR 3.1
59[...]
60cd test/apps-x11; ./apps-x11.sh | grep TESTING
61TESTING: xterm x11
62netblue@debian:~/work/github/firejail/test/apps-x11$ TESTING ERROR 5.1
63TESTING: firefox x11
64netblue@debian:~/work/github/firejail/test/apps-x11$ TESTING ERROR 5.1
65TESTING: chromium x11
66TESTING: transmission-gtk x11
67netblue@debian:~/work/github/firejail/test/apps-x11$ TESTING ERROR 5.1
68TESTING: icedove x11
69netblue@debian:~/work/github/firejail/test/apps-x11$ TESTING ERROR 5.1
70[...]
71`````
72"firemon --seccomp" and "firemon --caps" are misbehaving at the moment.
73
41## Deprecated --user 74## Deprecated --user
42 75
43--user option was deprecated, please use "sudo -u username firejail application" instead. 76--user option was deprecated, please use "sudo -u username firejail application" instead.
@@ -197,5 +230,5 @@ Browsers: Palemoon
197## New security profiles 230## New security profiles
198 231
199Gitter, gThumb, mpv, Franz messenger, LibreOffice, pix, audacity, xz, xzdec, gzip, cpio, less, Atom Beta, Atom, jitsi, eom, uudeview 232Gitter, gThumb, mpv, Franz messenger, LibreOffice, pix, audacity, xz, xzdec, gzip, cpio, less, Atom Beta, Atom, jitsi, eom, uudeview
200tar (gtar), unzip, unrar, file, skypeforlinux, gnome-chess 233tar (gtar), unzip, unrar, file, skypeforlinux, gnome-chess, inox
201 234
diff --git a/RELNOTES b/RELNOTES
index 79f634dcd..a40808c23 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -23,7 +23,7 @@ firejail (0.9.42~rc2) baseline; urgency=low
23 * new profiles: Gitter, gThumb, mpv, Franz messenger, LibreOffice 23 * new profiles: Gitter, gThumb, mpv, Franz messenger, LibreOffice
24 * new profiles: pix, audacity, xz, xzdec, gzip, cpio, less 24 * new profiles: pix, audacity, xz, xzdec, gzip, cpio, less
25 * new profiles: Atom Beta, Atom, jitsi, eom, uudeview 25 * new profiles: Atom Beta, Atom, jitsi, eom, uudeview
26 * new profiles: tar (gtar), unzip, unrar, file, skypeforlinux 26 * new profiles: tar (gtar), unzip, unrar, file, skypeforlinux, inox
27 -- netblue30 <netblue30@yahoo.com> Thu, 21 Jul 2016 08:00:00 -0500 27 -- netblue30 <netblue30@yahoo.com> Thu, 21 Jul 2016 08:00:00 -0500
28 28
29firejail (0.9.40) baseline; urgency=low 29firejail (0.9.40) baseline; urgency=low
diff --git a/etc/disable-programs.inc b/etc/disable-programs.inc
index 01e68506d..140417b01 100644
--- a/etc/disable-programs.inc
+++ b/etc/disable-programs.inc
@@ -60,6 +60,7 @@ blacklist ${HOME}/.config/slimjet
60blacklist ${HOME}/.config/qutebrowser 60blacklist ${HOME}/.config/qutebrowser
61blacklist ${HOME}/.8pecxstudios 61blacklist ${HOME}/.8pecxstudios
62blacklist ${HOME}/.config/brave 62blacklist ${HOME}/.config/brave
63blacklist ${HOME}/.config/inox
63 64
64# Instant Messaging 65# Instant Messaging
65blacklist ${HOME}/.config/hexchat 66blacklist ${HOME}/.config/hexchat
diff --git a/etc/inox.profile b/etc/inox.profile
new file mode 100644
index 000000000..49d2f2835
--- /dev/null
+++ b/etc/inox.profile
@@ -0,0 +1,24 @@
1# Inox browser profile
2noblacklist ~/.config/inox
3noblacklist ~/.cache/inox
4include /etc/firejail/disable-common.inc
5include /etc/firejail/disable-programs.inc
6
7netfilter
8
9whitelist ${DOWNLOADS}
10mkdir ~/.config/inox
11whitelist ~/.config/inox
12mkdir ~/.cache/inox
13whitelist ~/.cache/inox
14mkdir ~/.pki
15whitelist ~/.pki
16
17# lastpass, keepassx
18whitelist ~/.keepassx
19whitelist ~/.config/keepassx
20whitelist ~/keepassx.kdbx
21whitelist ~/.lastpass
22whitelist ~/.config/lastpass
23
24include /etc/firejail/whitelist-common.inc
diff --git a/platform/debian/conffiles b/platform/debian/conffiles
index 633123e92..59f0b35e7 100644
--- a/platform/debian/conffiles
+++ b/platform/debian/conffiles
@@ -61,6 +61,7 @@
61/etc/firejail/icecat.profile 61/etc/firejail/icecat.profile
62/etc/firejail/icedove.profile 62/etc/firejail/icedove.profile
63/etc/firejail/iceweasel.profile 63/etc/firejail/iceweasel.profile
64/etc/firejail/inox.profile
64/etc/firejail/jitsi.profile 65/etc/firejail/jitsi.profile
65/etc/firejail/kmail.profile 66/etc/firejail/kmail.profile
66/etc/firejail/konversation.profile 67/etc/firejail/konversation.profile
diff --git a/src/faudit/dbus.c b/src/faudit/dbus.c
index 1edce5802..64f5d8ae4 100644
--- a/src/faudit/dbus.c
+++ b/src/faudit/dbus.c
@@ -63,8 +63,6 @@ void dbus_test(void) {
63 if (ptr) 63 if (ptr)
64 *ptr = '\0'; 64 *ptr = '\0';
65 check_session_bus(sockfile); 65 check_session_bus(sockfile);
66
67 sockfile -= 13;
68 } 66 }
69 free(bus); 67 free(bus);
70 } 68 }
diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c
index 34c5ca509..5ff67b644 100644
--- a/src/firejail/bandwidth.c
+++ b/src/firejail/bandwidth.c
@@ -459,13 +459,15 @@ void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, in
459 if (setregid(0, 0)) 459 if (setregid(0, 0))
460 errExit("setregid"); 460 errExit("setregid");
461 461
462 assert(cfg.shell);
463
462 char *arg[4]; 464 char *arg[4];
463 arg[0] = "/bin/bash"; 465 arg[0] = cfg.shell;
464 arg[1] = "-c"; 466 arg[1] = "-c";
465 arg[2] = cmd; 467 arg[2] = cmd;
466 arg[3] = NULL; 468 arg[3] = NULL;
467 execvp("/bin/bash", arg); 469 execvp(arg[0], arg);
468 470
469 // it will never get here 471 // it will never get here
470 exit(0); 472 errExit("execvp");
471} 473}
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c
index 3b60dafb6..019b54773 100644
--- a/src/firejail/checkcfg.c
+++ b/src/firejail/checkcfg.c
@@ -50,7 +50,7 @@ int checkcfg(int val) {
50 FILE *fp = fopen(fname, "r"); 50 FILE *fp = fopen(fname, "r");
51 if (!fp) { 51 if (!fp) {
52#ifdef HAVE_GLOBALCFG 52#ifdef HAVE_GLOBALCFG
53 fprintf(stderr, "Warning: Firejail configuration file %s not found\n", fname); 53 fprintf(stderr, "Error: Firejail configuration file %s not found\n", fname);
54 exit(1); 54 exit(1);
55#else 55#else
56 initialized = 1; 56 initialized = 1;
@@ -317,7 +317,7 @@ void print_compiletime_support(void) {
317#endif 317#endif
318 ); 318 );
319 319
320 printf("\t- X11 snadboxing support is %s\n", 320 printf("\t- X11 sandboxing support is %s\n",
321#ifdef HAVE_X11 321#ifdef HAVE_X11
322 "enabled" 322 "enabled"
323#else 323#else
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c
index 48cbaffb7..cadf4795d 100644
--- a/src/firejail/cmdline.c
+++ b/src/firejail/cmdline.c
@@ -26,7 +26,9 @@
26#include <assert.h> 26#include <assert.h>
27#include <errno.h> 27#include <errno.h>
28 28
29int cmdline_length(int argc, char **argv, int index) { 29static int cmdline_length(int argc, char **argv, int index) {
30 assert(index != -1);
31
30 unsigned i,j; 32 unsigned i,j;
31 int len = 0; 33 int len = 0;
32 unsigned argcnt = argc - index; 34 unsigned argcnt = argc - index;
@@ -62,7 +64,9 @@ int cmdline_length(int argc, char **argv, int index) {
62 return len; 64 return len;
63} 65}
64 66
65void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) { 67static void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) {
68 assert(index != -1);
69
66 unsigned i,j; 70 unsigned i,j;
67 unsigned argcnt = argc - index; 71 unsigned argcnt = argc - index;
68 bool in_quotes = false; 72 bool in_quotes = false;
@@ -131,6 +135,10 @@ void quote_cmdline(char *command_line, char *window_title, int len, int argc, ch
131} 135}
132 136
133void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { 137void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) {
138 // index == -1 could happen if we have --shell=none and no program was specified
139 // the program should exit with an error before entering this function
140 assert(index != -1);
141
134 int len = cmdline_length(argc, argv, index); 142 int len = cmdline_length(argc, argv, index);
135 if (len > ARG_MAX) { 143 if (len > ARG_MAX) {
136 errno = E2BIG; 144 errno = E2BIG;
diff --git a/src/firejail/env.c b/src/firejail/env.c
index 79d6b81e3..c05abadca 100644
--- a/src/firejail/env.c
+++ b/src/firejail/env.c
@@ -121,19 +121,16 @@ void env_defaults(void) {
121 errExit("setenv"); 121 errExit("setenv");
122 if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, 122 if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc,
123 errExit("setenv"); 123 errExit("setenv");
124 if (arg_zsh && setenv("SHELL", "/usr/bin/zsh", 1) < 0)
125 errExit("setenv");
126 if (arg_csh && setenv("SHELL", "/bin/csh", 1) < 0)
127 errExit("setenv");
128 if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0) 124 if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0)
129 errExit("setenv"); 125 errExit("setenv");
130 // set prompt color to green 126 // set prompt color to green
131 //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' 127 //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] '
132 if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) 128// if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0)
133 errExit("setenv"); 129// errExit("setenv");
134 130
135 // set the window title 131 // set the window title
136 printf("\033]0;firejail %s\007", cfg.window_title);fflush(0); 132 printf("\033]0;firejail %s\007", cfg.window_title);
133 fflush(0);
137} 134}
138 135
139// parse and store the environment setting 136// parse and store the environment setting
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index ee70f19f1..1fed3fcdf 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -22,6 +22,8 @@
22#include "../include/common.h" 22#include "../include/common.h"
23#include "../include/euid_common.h" 23#include "../include/euid_common.h"
24 24
25// debug restricted shell
26//#define DEBUG_RESTRICTED_SHELL
25 27
26// filesystem 28// filesystem
27#define RUN_FIREJAIL_BASEDIR "/run" 29#define RUN_FIREJAIL_BASEDIR "/run"
@@ -268,6 +270,7 @@ extern int arg_audit; // audit
268extern char *arg_audit_prog; // audit 270extern char *arg_audit_prog; // audit
269extern int arg_apparmor; // apparmor 271extern int arg_apparmor; // apparmor
270 272
273extern int login_shell;
271extern int parent_to_child_fds[2]; 274extern int parent_to_child_fds[2];
272extern int child_to_parent_fds[2]; 275extern int child_to_parent_fds[2];
273extern pid_t sandbox_pid; 276extern pid_t sandbox_pid;
@@ -278,6 +281,7 @@ extern int fullargc;
278 281
279// main.c 282// main.c
280void check_user_namespace(void); 283void check_user_namespace(void);
284char *guess_shell(void);
281 285
282// sandbox.c 286// sandbox.c
283int sandbox(void* sandbox_arg); 287int sandbox(void* sandbox_arg);
@@ -358,7 +362,6 @@ void shut(pid_t pid);
358void shut_name(const char *name); 362void shut_name(const char *name);
359 363
360// restricted_shell.c 364// restricted_shell.c
361extern char *restricted_user;
362int restricted_shell(const char *user); 365int restricted_shell(const char *user);
363 366
364// arp.c 367// arp.c
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index c152abe0d..484b99537 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -1141,13 +1141,13 @@ int fs_check_chroot_dir(const char *rootdir) {
1141 free(name); 1141 free(name);
1142 1142
1143 // check /bin/bash 1143 // check /bin/bash
1144 if (asprintf(&name, "%s/bin/bash", rootdir) == -1) 1144// if (asprintf(&name, "%s/bin/bash", rootdir) == -1)
1145 errExit("asprintf"); 1145// errExit("asprintf");
1146 if (stat(name, &s) == -1) { 1146// if (stat(name, &s) == -1) {
1147 fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); 1147// fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n");
1148 return 1; 1148// return 1;
1149 } 1149// }
1150 free(name); 1150// free(name);
1151 1151
1152 // check x11 socket directory 1152 // check x11 socket directory
1153 if (getenv("FIREJAIL_X11")) { 1153 if (getenv("FIREJAIL_X11")) {
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index c1e983c16..d328d5f1c 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -32,8 +32,9 @@
32 32
33static void skel(const char *homedir, uid_t u, gid_t g) { 33static void skel(const char *homedir, uid_t u, gid_t g) {
34 char *fname; 34 char *fname;
35
35 // zsh 36 // zsh
36 if (arg_zsh) { 37 if (!arg_shell_none && (strcmp(cfg.shell,"/usr/bin/zsh") == 0 || strcmp(cfg.shell,"/bin/zsh") == 0)) {
37 // copy skel files 38 // copy skel files
38 if (asprintf(&fname, "%s/.zshrc", homedir) == -1) 39 if (asprintf(&fname, "%s/.zshrc", homedir) == -1)
39 errExit("asprintf"); 40 errExit("asprintf");
@@ -63,7 +64,7 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
63 free(fname); 64 free(fname);
64 } 65 }
65 // csh 66 // csh
66 else if (arg_csh) { 67 else if (!arg_shell_none && strcmp(cfg.shell,"/bin/csh") == 0) {
67 // copy skel files 68 // copy skel files
68 if (asprintf(&fname, "%s/.cshrc", homedir) == -1) 69 if (asprintf(&fname, "%s/.cshrc", homedir) == -1)
69 errExit("asprintf"); 70 errExit("asprintf");
diff --git a/src/firejail/join.c b/src/firejail/join.c
index 0b5b6a34a..632715fea 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -330,32 +330,15 @@ void join(pid_t pid, int argc, char **argv, int index) {
330 } 330 }
331 } 331 }
332 332
333 // run cmdline trough /bin/bash 333 // run cmdline trough shell
334 if (cfg.command_line == NULL) { 334 if (cfg.command_line == NULL) {
335 assert(cfg.shell);
335 336
336 // replace the process with a shell 337 // replace the process with a shell
337 if (cfg.shell) 338 execlp(cfg.shell, cfg.shell, NULL);
338 execlp(cfg.shell, cfg.shell, NULL);
339 else if (arg_zsh)
340 execlp("/usr/bin/zsh", "/usr/bin/zsh", NULL);
341 else if (arg_csh)
342 execlp("/bin/csh", "/bin/csh", NULL);
343 else {
344 struct stat s;
345 if (stat("/bin/bash", &s) == 0)
346 execlp("/bin/bash", "/bin/bash", NULL);
347 else if (stat("/usr/bin/zsh", &s) == 0)
348 execlp("/usr/bin/zsh", "/usr/bin/zsh", NULL);
349 else if (stat("/bin/csh", &s) == 0)
350 execlp("/bin/csh", "/bin/csh", NULL);
351 else if (stat("/bin/sh", &s) == 0)
352 execlp("/bin/sh", "/bin/sh", NULL);
353 }
354 339
355 // no shell found, print an error and exit 340 // it should never get here
356 fprintf(stderr, "Error: no POSIX shell found\n"); 341 errExit("execlp");
357 sleep(5);
358 exit(1);
359 } 342 }
360 else { 343 else {
361 // run the command supplied by the user 344 // run the command supplied by the user
@@ -398,19 +381,10 @@ void join(pid_t pid, int argc, char **argv, int index) {
398 execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]); 381 execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index]);
399 exit(1); 382 exit(1);
400 } else { 383 } else {
401 // choose the shell requested by the user, or use bash as default 384 assert(cfg.shell);
402 char *sh; 385
403 if (cfg.shell)
404 sh = cfg.shell;
405 else if (arg_zsh)
406 sh = "/usr/bin/zsh";
407 else if (arg_csh)
408 sh = "/bin/csh";
409 else
410 sh = "/bin/bash";
411
412 char *arg[5]; 386 char *arg[5];
413 arg[0] = sh; 387 arg[0] = cfg.shell;
414 arg[1] = "-c"; 388 arg[1] = "-c";
415 if (arg_debug) 389 if (arg_debug)
416 printf("Starting %s\n", cfg.command_line); 390 printf("Starting %s\n", cfg.command_line);
@@ -423,7 +397,10 @@ void join(pid_t pid, int argc, char **argv, int index) {
423 arg[3] = cfg.command_line; 397 arg[3] = cfg.command_line;
424 arg[4] = NULL; 398 arg[4] = NULL;
425 } 399 }
426 execvp("/bin/bash", arg); 400 execvp(arg[0], arg);
401
402 // it should never get here
403 errExit("execvp");
427 } 404 }
428 } 405 }
429 406
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 120809456..8de5f9a6e 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -105,6 +105,7 @@ int arg_appimage = 0; // appimage
105int arg_audit = 0; // audit 105int arg_audit = 0; // audit
106char *arg_audit_prog; // audit 106char *arg_audit_prog; // audit
107int arg_apparmor; // apparmor 107int arg_apparmor; // apparmor
108int login_shell = 0;
108 109
109int parent_to_child_fds[2]; 110int parent_to_child_fds[2];
110int child_to_parent_fds[2]; 111int child_to_parent_fds[2];
@@ -238,7 +239,8 @@ void check_user_namespace(void) {
238 stat("/proc/self/gid_map", &s3) == 0) 239 stat("/proc/self/gid_map", &s3) == 0)
239 arg_noroot = 1; 240 arg_noroot = 1;
240 else { 241 else {
241 fprintf(stderr, "Warning: user namespaces not available in the current kernel.\n"); 242 if (!arg_quiet || arg_debug)
243 fprintf(stderr, "Warning: user namespaces not available in the current kernel.\n");
242 arg_noroot = 0; 244 arg_noroot = 0;
243 } 245 }
244} 246}
@@ -566,7 +568,18 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
566#endif 568#endif
567 else if (strncmp(argv[i], "--join=", 7) == 0) { 569 else if (strncmp(argv[i], "--join=", 7) == 0) {
568 logargs(argc, argv); 570 logargs(argc, argv);
569 571
572 if (arg_shell_none) {
573 if (argc <= (i+1)) {
574 fprintf(stderr, "Error: --shell=none set, but no command specified\n");
575 exit(1);
576 }
577 cfg.original_program_index = i + 1;
578 }
579
580 if (!cfg.shell && !arg_shell_none)
581 cfg.shell = guess_shell();
582
570 // join sandbox by pid or by name 583 // join sandbox by pid or by name
571 pid_t pid; 584 pid_t pid;
572 if (read_pid(argv[i] + 7, &pid) == 0) 585 if (read_pid(argv[i] + 7, &pid) == 0)
@@ -574,6 +587,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
574 else 587 else
575 join_name(argv[i] + 7, argc, argv, i + 1); 588 join_name(argv[i] + 7, argc, argv, i + 1);
576 exit(0); 589 exit(0);
590
577 } 591 }
578#ifdef HAVE_NETWORK 592#ifdef HAVE_NETWORK
579 else if (strncmp(argv[i], "--join-network=", 15) == 0) { 593 else if (strncmp(argv[i], "--join-network=", 15) == 0) {
@@ -745,6 +759,25 @@ static void detect_quiet(int argc, char **argv) {
745 } 759 }
746} 760}
747 761
762char *guess_shell(void) {
763 char *shell;
764 // shells in order of preference
765 char *shells[] = {"/bin/bash", "/bin/csh", "/usr/bin/zsh", "/bin/sh", "/bin/ash", NULL };
766
767 int i = 0;
768 while (shells[i] != NULL) {
769 struct stat s;
770 // access call checks as real UID/GID, not as effective UID/GID
771 if (stat(shells[i], &s) == 0 && access(shells[i], R_OK) == 0) {
772 shell = shells[i];
773 break;
774 }
775 i++;
776 }
777
778 return shell;
779}
780
748//******************************************* 781//*******************************************
749// Main program 782// Main program
750//******************************************* 783//*******************************************
@@ -883,6 +916,41 @@ int main(int argc, char **argv) {
883 if (strcmp(comm, "sshd") == 0) { 916 if (strcmp(comm, "sshd") == 0) {
884 arg_quiet = 1; 917 arg_quiet = 1;
885 parent_sshd = 1; 918 parent_sshd = 1;
919
920#ifdef DEBUG_RESTRICTED_SHELL
921 {EUID_ROOT();
922 FILE *fp = fopen("/firelog", "w");
923 if (fp) {
924 int i;
925 fprintf(fp, "argc %d: ", argc);
926 for (i = 0; i < argc; i++)
927 fprintf(fp, "#%s# ", argv[i]);
928 fprintf(fp, "\n");
929 fclose(fp);
930 }
931 EUID_USER();}
932#endif
933 // run sftp and scp directly without any sandboxing
934 // regular login has argv[0] == "-firejail"
935 if (*argv[0] != '-') {
936 if (strcmp(argv[1], "-c") == 0 && argc > 2) {
937 if (strcmp(argv[2], "/usr/lib/openssh/sftp-server") == 0 ||
938 strncmp(argv[2], "scp ", 4) == 0) {
939#ifdef DEBUG_RESTRICTED_SHELL
940 {EUID_ROOT();
941 FILE *fp = fopen("/firelog", "a");
942 if (fp) {
943 fprintf(fp, "run without a sandbox\n");
944 fclose(fp);
945 }
946 EUID_USER();}
947#endif
948
949 drop_privs(1);
950 run_no_sandbox(argc, argv);
951 }
952 }
953 }
886 } 954 }
887 free(comm); 955 free(comm);
888 } 956 }
@@ -890,8 +958,25 @@ int main(int argc, char **argv) {
890 958
891 // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users 959 // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users
892 if (*argv[0] == '-' || parent_sshd) { 960 if (*argv[0] == '-' || parent_sshd) {
961 if (argc == 1)
962 login_shell = 1;
893 fullargc = restricted_shell(cfg.username); 963 fullargc = restricted_shell(cfg.username);
894 if (fullargc) { 964 if (fullargc) {
965
966#ifdef DEBUG_RESTRICTED_SHELL
967 {EUID_ROOT();
968 FILE *fp = fopen("/firelog", "a");
969 if (fp) {
970 fprintf(fp, "fullargc %d: ", fullargc);
971 int i;
972 for (i = 0; i < fullargc; i++)
973 fprintf(fp, "#%s# ", fullargv[i]);
974 fprintf(fp, "\n");
975 fclose(fp);
976 }
977 EUID_USER();}
978#endif
979
895 int j; 980 int j;
896 for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++) 981 for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++)
897 fullargv[j] = argv[i]; 982 fullargv[j] = argv[i];
@@ -899,6 +984,20 @@ int main(int argc, char **argv) {
899 // replace argc/argv with fullargc/fullargv 984 // replace argc/argv with fullargc/fullargv
900 argv = fullargv; 985 argv = fullargv;
901 argc = j; 986 argc = j;
987
988#ifdef DEBUG_RESTRICTED_SHELL
989 {EUID_ROOT();
990 FILE *fp = fopen("/firelog", "a");
991 if (fp) {
992 fprintf(fp, "argc %d: ", argc);
993 int i;
994 for (i = 0; i < argc; i++)
995 fprintf(fp, "#%s# ", argv[i]);
996 fprintf(fp, "\n");
997 fclose(fp);
998 }
999 EUID_USER();}
1000#endif
902 } 1001 }
903 } 1002 }
904 else { 1003 else {
@@ -1582,7 +1681,8 @@ int main(int argc, char **argv) {
1582 errExit("strdup"); 1681 errExit("strdup");
1583 1682
1584 if (net_get_if_addr(intf->dev, &intf->ip, &intf->mask, intf->mac, &intf->mtu)) { 1683 if (net_get_if_addr(intf->dev, &intf->ip, &intf->mask, intf->mac, &intf->mtu)) {
1585 fprintf(stderr, "Warning: interface %s is not configured\n", intf->dev); 1684 if (!arg_quiet || arg_debug)
1685 fprintf(stderr, "Warning: interface %s is not configured\n", intf->dev);
1586 } 1686 }
1587 intf->configured = 1; 1687 intf->configured = 1;
1588 } 1688 }
@@ -1913,26 +2013,26 @@ int main(int argc, char **argv) {
1913 fprintf(stderr, "Error: --shell=none was already specified.\n"); 2013 fprintf(stderr, "Error: --shell=none was already specified.\n");
1914 return 1; 2014 return 1;
1915 } 2015 }
1916 if (arg_zsh || cfg.shell ) { 2016 if (cfg.shell) {
1917 fprintf(stderr, "Error: only one default user shell can be specified\n"); 2017 fprintf(stderr, "Error: only one default user shell can be specified\n");
1918 return 1; 2018 return 1;
1919 } 2019 }
1920 arg_csh = 1; 2020 cfg.shell = "/bin/csh";
1921 } 2021 }
1922 else if (strcmp(argv[i], "--zsh") == 0) { 2022 else if (strcmp(argv[i], "--zsh") == 0) {
1923 if (arg_shell_none) { 2023 if (arg_shell_none) {
1924 fprintf(stderr, "Error: --shell=none was already specified.\n"); 2024 fprintf(stderr, "Error: --shell=none was already specified.\n");
1925 return 1; 2025 return 1;
1926 } 2026 }
1927 if (arg_csh || cfg.shell ) { 2027 if (cfg.shell) {
1928 fprintf(stderr, "Error: only one default user shell can be specified\n"); 2028 fprintf(stderr, "Error: only one default user shell can be specified\n");
1929 return 1; 2029 return 1;
1930 } 2030 }
1931 arg_zsh = 1; 2031 cfg.shell = "/bin/zsh";
1932 } 2032 }
1933 else if (strcmp(argv[i], "--shell=none") == 0) { 2033 else if (strcmp(argv[i], "--shell=none") == 0) {
1934 arg_shell_none = 1; 2034 arg_shell_none = 1;
1935 if (arg_csh || arg_zsh || cfg.shell) { 2035 if (cfg.shell) {
1936 fprintf(stderr, "Error: a shell was already specified\n"); 2036 fprintf(stderr, "Error: a shell was already specified\n");
1937 return 1; 2037 return 1;
1938 } 2038 }
@@ -1944,7 +2044,7 @@ int main(int argc, char **argv) {
1944 } 2044 }
1945 invalid_filename(argv[i] + 8); 2045 invalid_filename(argv[i] + 8);
1946 2046
1947 if (arg_csh || arg_zsh || cfg.shell) { 2047 if (cfg.shell) {
1948 fprintf(stderr, "Error: only one user shell can be specified\n"); 2048 fprintf(stderr, "Error: only one user shell can be specified\n");
1949 return 1; 2049 return 1;
1950 } 2050 }
@@ -1954,9 +2054,18 @@ int main(int argc, char **argv) {
1954 fprintf(stderr, "Error: invalid shell\n"); 2054 fprintf(stderr, "Error: invalid shell\n");
1955 exit(1); 2055 exit(1);
1956 } 2056 }
1957 2057
1958 // access call checks as real UID/GID, not as effective UID/GID 2058 // access call checks as real UID/GID, not as effective UID/GID
1959 if (access(cfg.shell, R_OK)) { 2059 if(cfg.chrootdir) {
2060 char *shellpath;
2061 if (asprintf(&shellpath, "%s%s", cfg.chrootdir, cfg.shell) == -1)
2062 errExit("asprintf");
2063 if (access(shellpath, R_OK)) {
2064 fprintf(stderr, "Error: cannot access shell file in chroot\n");
2065 exit(1);
2066 }
2067 free(shellpath);
2068 } else if (access(cfg.shell, R_OK)) {
1960 fprintf(stderr, "Error: cannot access shell file\n"); 2069 fprintf(stderr, "Error: cannot access shell file\n");
1961 exit(1); 2070 exit(1);
1962 } 2071 }
@@ -1999,10 +2108,18 @@ int main(int argc, char **argv) {
1999 break; 2108 break;
2000 } 2109 }
2001 } 2110 }
2111
2112 // prog_index could still be -1 if no program was specified
2113 if (prog_index == -1 && arg_shell_none) {
2114 fprintf(stderr, "shell=none configured, but no program specified\n");
2115 exit(1);
2116 }
2002 2117
2003 // check trace configuration 2118 // check trace configuration
2004 if (arg_trace && arg_tracelog) 2119 if (arg_trace && arg_tracelog) {
2005 fprintf(stderr, "Warning: --trace and --tracelog are mutually exclusive; --tracelog disabled\n"); 2120 if (!arg_quiet || arg_debug)
2121 fprintf(stderr, "Warning: --trace and --tracelog are mutually exclusive; --tracelog disabled\n");
2122 }
2006 2123
2007 // check user namespace (--noroot) options 2124 // check user namespace (--noroot) options
2008 if (arg_noroot) { 2125 if (arg_noroot) {
@@ -2026,27 +2143,23 @@ int main(int argc, char **argv) {
2026 free(msg); 2143 free(msg);
2027 } 2144 }
2028 2145
2029 // build the sandbox command 2146 // guess shell if unspecified
2030 if (prog_index == -1 && arg_zsh) { 2147 if (!arg_shell_none && !cfg.shell) {
2031 cfg.command_line = "/usr/bin/zsh"; 2148 cfg.shell = guess_shell();
2032 cfg.window_title = "/usr/bin/zsh"; 2149 if (!cfg.shell) {
2033 cfg.command_name = "zsh"; 2150 fprintf(stderr, "Error: unable to guess your shell, please set explicitly by using --shell option.\n");
2034 } 2151 exit(1);
2035 else if (prog_index == -1 && arg_csh) { 2152 }
2036 cfg.command_line = "/bin/csh"; 2153 if (arg_debug)
2037 cfg.window_title = "/bin/csh"; 2154 printf("Autoselecting %s as shell\n", cfg.shell);
2038 cfg.command_name = "csh";
2039 } 2155 }
2040 else if (prog_index == -1 && cfg.shell) { 2156
2157 // build the sandbox command
2158 if (prog_index == -1 && cfg.shell) {
2041 cfg.command_line = cfg.shell; 2159 cfg.command_line = cfg.shell;
2042 cfg.window_title = cfg.shell; 2160 cfg.window_title = cfg.shell;
2043 cfg.command_name = cfg.shell; 2161 cfg.command_name = cfg.shell;
2044 } 2162 }
2045 else if (prog_index == -1) {
2046 cfg.command_line = "/bin/bash";
2047 cfg.window_title = "/bin/bash";
2048 cfg.command_name = "bash";
2049 }
2050 else if (arg_appimage) { 2163 else if (arg_appimage) {
2051 if (arg_debug) 2164 if (arg_debug)
2052 printf("Configuring appimage environment\n"); 2165 printf("Configuring appimage environment\n");
@@ -2056,6 +2169,10 @@ int main(int argc, char **argv) {
2056 else { 2169 else {
2057 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); 2170 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index);
2058 } 2171 }
2172/* else {
2173 fprintf(stderr, "Error: command must be specified when --shell=none used.\n");
2174 exit(1);
2175 }*/
2059 2176
2060 assert(cfg.command_name); 2177 assert(cfg.command_name);
2061 if (arg_debug) 2178 if (arg_debug)
@@ -2086,10 +2203,14 @@ int main(int argc, char **argv) {
2086 2203
2087 // use default.profile as the default 2204 // use default.profile as the default
2088 if (!custom_profile && !arg_noprofile) { 2205 if (!custom_profile && !arg_noprofile) {
2089 if (cfg.chrootdir) 2206 if (cfg.chrootdir) {
2090 fprintf(stderr, "Warning: default profile disabled by --chroot option\n"); 2207 if (!arg_quiet || arg_debug)
2091 else if (arg_overlay) 2208 fprintf(stderr, "Warning: default profile disabled by --chroot option\n");
2092 fprintf(stderr, "Warning: default profile disabled by --overlay option\n"); 2209 }
2210 else if (arg_overlay) {
2211 if (!arg_quiet || arg_debug)
2212 fprintf(stderr, "Warning: default profile disabled by --overlay option\n");
2213 }
2093 else { 2214 else {
2094 // try to load a default profile 2215 // try to load a default profile
2095 char *profile_name = DEFAULT_USER_PROFILE; 2216 char *profile_name = DEFAULT_USER_PROFILE;
@@ -2152,11 +2273,13 @@ int main(int argc, char **argv) {
2152 errExit("pipe"); 2273 errExit("pipe");
2153 2274
2154 if (arg_noroot && arg_overlay) { 2275 if (arg_noroot && arg_overlay) {
2155 fprintf(stderr, "Warning: --overlay and --noroot are mutually exclusive, noroot disabled\n"); 2276 if (!arg_quiet || arg_debug)
2277 fprintf(stderr, "Warning: --overlay and --noroot are mutually exclusive, noroot disabled\n");
2156 arg_noroot = 0; 2278 arg_noroot = 0;
2157 } 2279 }
2158 else if (arg_noroot && cfg.chrootdir) { 2280 else if (arg_noroot && cfg.chrootdir) {
2159 fprintf(stderr, "Warning: --chroot and --noroot are mutually exclusive, noroot disabled\n"); 2281 if (!arg_quiet || arg_debug)
2282 fprintf(stderr, "Warning: --chroot and --noroot are mutually exclusive, noroot disabled\n");
2160 arg_noroot = 0; 2283 arg_noroot = 0;
2161 } 2284 }
2162 2285
diff --git a/src/firejail/network.txt b/src/firejail/network.txt
index 673d5b941..f6df0f485 100644
--- a/src/firejail/network.txt
+++ b/src/firejail/network.txt
@@ -13,7 +13,7 @@ net_configure_bridge(br, device) {
13} 13}
14 14
15net_configure_sandbox_ip(br) { 15net_configure_sandbox_ip(br) {
16 if br->ip_snadbox 16 if br->ip_sandbox
17 check br->ipsandbox inside the bridge network 17 check br->ipsandbox inside the bridge network
18 arp_check(br->ipsandbox) // send an arp req to check if anybody else is using this address 18 arp_check(br->ipsandbox) // send an arp req to check if anybody else is using this address
19 else 19 else
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c
index f1fd04aec..80ed72dca 100644
--- a/src/firejail/no_sandbox.c
+++ b/src/firejail/no_sandbox.c
@@ -172,6 +172,8 @@ void run_no_sandbox(int argc, char **argv) {
172 int len = 0; 172 int len = 0;
173 int i; 173 int i;
174 for (i = 1; i < argc; i++) { 174 for (i = 1; i < argc; i++) {
175 if (i == 1 && strcmp(argv[i], "-c") == 0)
176 continue;
175 if (*argv[i] == '-') 177 if (*argv[i] == '-')
176 continue; 178 continue;
177 break; 179 break;
@@ -202,8 +204,9 @@ void run_no_sandbox(int argc, char **argv) {
202 } 204 }
203 205
204 // start the program in /bin/sh 206 // start the program in /bin/sh
205 fprintf(stderr, "Warning: an existing sandbox was detected. " 207 if (!arg_quiet)
206 "%s will run without any additional sandboxing features in a /bin/sh shell\n", command); 208 fprintf(stderr, "Warning: an existing sandbox was detected. "
209 "%s will run without any additional sandboxing features in a /bin/sh shell\n", command);
207 int rv = system(command); 210 int rv = system(command);
208 (void) rv; 211 (void) rv;
209 if (allocated) 212 if (allocated)
diff --git a/src/firejail/restricted_shell.c b/src/firejail/restricted_shell.c
index ee6e94957..24ce27c2e 100644
--- a/src/firejail/restricted_shell.c
+++ b/src/firejail/restricted_shell.c
@@ -40,7 +40,7 @@ int restricted_shell(const char *user) {
40 char buf[MAX_READ]; 40 char buf[MAX_READ];
41 while (fgets(buf, MAX_READ, fp)) { 41 while (fgets(buf, MAX_READ, fp)) {
42 lineno++; 42 lineno++;
43 43
44 // remove empty spaces at the beginning of the line 44 // remove empty spaces at the beginning of the line
45 char *ptr = buf; 45 char *ptr = buf;
46 while (*ptr == ' ' || *ptr == '\t') { 46 while (*ptr == ' ' || *ptr == '\t') {
@@ -48,7 +48,7 @@ int restricted_shell(const char *user) {
48 } 48 }
49 if (*ptr == '\n' || *ptr == '#') 49 if (*ptr == '\n' || *ptr == '#')
50 continue; 50 continue;
51 51
52 // parse line 52 // parse line
53 char *usr = ptr; 53 char *usr = ptr;
54 char *args = strchr(usr, ':'); 54 char *args = strchr(usr, ':');
@@ -56,6 +56,7 @@ int restricted_shell(const char *user) {
56 fprintf(stderr, "Error: users.conf line %d\n", lineno); 56 fprintf(stderr, "Error: users.conf line %d\n", lineno);
57 exit(1); 57 exit(1);
58 } 58 }
59
59 *args = '\0'; 60 *args = '\0';
60 args++; 61 args++;
61 ptr = strchr(args, '\n'); 62 ptr = strchr(args, '\n');
@@ -70,29 +71,41 @@ int restricted_shell(const char *user) {
70 found = 1; 71 found = 1;
71 break; 72 break;
72 } 73 }
74 ptr2++;
73 } 75 }
74 if (!found) 76 if (!found)
75 continue; 77 continue;
76 78
77 // process user 79 // process user
78 if (strcmp(user, usr) == 0) { 80 if (strcmp(user, usr) == 0) {
79 restricted_user = strdup(user);
80 // extract program arguments 81 // extract program arguments
81 82
82 fullargv[0] = "firejail"; 83 fullargv[0] = "firejail";
83 int i; 84 int i;
84 ptr = args; 85 ptr = args;
85 for (i = 1; i < MAX_ARGS; i++) { 86 for (i = 1; i < MAX_ARGS; i++) {
86 fullargv[i] = ptr; 87 // skip blanks
87 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') 88 while (*ptr == ' ' || *ptr == '\t')
88 ptr++; 89 ptr++;
90 fullargv[i] = ptr;
91#ifdef DEBUG_RESTRICTED_SHELL
92 {EUID_ROOT();
93 FILE *fp = fopen("/firelog", "a");
94 if (fp) {
95 fprintf(fp, "i %d ptr #%s#\n", i, fullargv[i]);
96 fclose(fp);
97 }
98 EUID_USER();}
99#endif
100
89 if (*ptr != '\0') { 101 if (*ptr != '\0') {
102 // go to the end of the word
103 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0')
104 ptr++;
90 *ptr ='\0'; 105 *ptr ='\0';
91 fullargv[i] = strdup(fullargv[i]); 106 fullargv[i] = strdup(fullargv[i]);
92 if (fullargv[i] == NULL) { 107 if (fullargv[i] == NULL)
93 fprintf(stderr, "Error: cannot allocate memory\n"); 108 errExit("strdup");
94 exit(1);
95 }
96 ptr++; 109 ptr++;
97 while (*ptr == ' ' || *ptr == '\t') 110 while (*ptr == ' ' || *ptr == '\t')
98 ptr++; 111 ptr++;
@@ -108,7 +121,7 @@ int restricted_shell(const char *user) {
108 } 121 }
109 } 122 }
110 fclose(fp); 123 fclose(fp);
111 124
112 return 0; 125 return 0;
113} 126}
114 127
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index a131d9e91..8178cfc8e 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -325,30 +325,27 @@ static void start_application(void) {
325 // start the program using a shell 325 // start the program using a shell
326 //**************************************** 326 //****************************************
327 else { 327 else {
328 // choose the shell requested by the user, or use bash as default 328 assert(cfg.shell);
329 char *sh; 329 assert(cfg.command_line);
330 if (cfg.shell) 330
331 sh = cfg.shell;
332 else if (arg_zsh)
333 sh = "/usr/bin/zsh";
334 else if (arg_csh)
335 sh = "/bin/csh";
336 else
337 sh = "/bin/bash";
338
339 char *arg[5]; 331 char *arg[5];
340 int index = 0; 332 int index = 0;
341 arg[index++] = sh; 333 arg[index++] = cfg.shell;
342 arg[index++] = "-c"; 334 if (login_shell) {
343 assert(cfg.command_line); 335 arg[index++] = "-l";
344 if (arg_debug) 336 if (arg_debug)
345 printf("Starting %s\n", cfg.command_line); 337 printf("Starting %s login shell\n", cfg.shell);
346 if (arg_doubledash) 338 } else {
347 arg[index++] = "--"; 339 arg[index++] = "-c";
348 arg[index++] = cfg.command_line; 340 if (arg_debug)
341 printf("Running %s command through %s\n", cfg.command_line, cfg.shell);
342 if (arg_doubledash)
343 arg[index++] = "--";
344 arg[index++] = cfg.command_line;
345 }
349 arg[index] = NULL; 346 arg[index] = NULL;
350 assert(index < 5); 347 assert(index < 5);
351 348
352 if (arg_debug) { 349 if (arg_debug) {
353 char *msg; 350 char *msg;
354 if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) 351 if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1)
@@ -356,7 +353,7 @@ static void start_application(void) {
356 logmsg(msg); 353 logmsg(msg);
357 free(msg); 354 free(msg);
358 } 355 }
359 356
360 if (arg_debug) { 357 if (arg_debug) {
361 int i; 358 int i;
362 for (i = 0; i < 5; i++) { 359 for (i = 0; i < 5; i++) {
@@ -365,12 +362,12 @@ static void start_application(void) {
365 printf("execvp argument %d: %s\n", i, arg[i]); 362 printf("execvp argument %d: %s\n", i, arg[i]);
366 } 363 }
367 } 364 }
368 365
369 if (!arg_command && !arg_quiet) 366 if (!arg_command && !arg_quiet)
370 printf("Child process initialized\n"); 367 printf("Child process initialized\n");
371 execvp(sh, arg); 368 execvp(arg[0], arg);
372 } 369 }
373 370
374 perror("execvp"); 371 perror("execvp");
375 exit(1); // it should never get here!!! 372 exit(1); // it should never get here!!!
376} 373}
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 58908e9df..ed6fa3741 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -20,6 +20,7 @@
20#include "firejail.h" 20#include "firejail.h"
21#include <sys/types.h> 21#include <sys/types.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <fcntl.h>
23#include <unistd.h> 24#include <unistd.h>
24#include <signal.h> 25#include <signal.h>
25#include <stdlib.h> 26#include <stdlib.h>
@@ -164,7 +165,7 @@ void x11_start_xephyr(int argc, char **argv) {
164 EUID_ASSERT(); 165 EUID_ASSERT();
165 size_t i; 166 size_t i;
166 struct stat s; 167 struct stat s;
167 pid_t client = 0; 168 pid_t jail = 0;
168 pid_t server = 0; 169 pid_t server = 0;
169 170
170 setenv("FIREJAIL_X11", "yes", 1); 171 setenv("FIREJAIL_X11", "yes", 1);
@@ -255,7 +256,7 @@ void x11_start_xephyr(int argc, char **argv) {
255 } 256 }
256 257
257 // remove --x11 arg 258 // remove --x11 arg
258 char *client_argv[argc+2]; 259 char *jail_argv[argc+2];
259 size_t j = 0; 260 size_t j = 0;
260 for (i = 0; i < argc; i++) { 261 for (i = 0; i < argc; i++) {
261 if (strcmp(argv[i], "--x11") == 0) 262 if (strcmp(argv[i], "--x11") == 0)
@@ -264,18 +265,18 @@ void x11_start_xephyr(int argc, char **argv) {
264 continue; 265 continue;
265 if (strcmp(argv[i], "--x11=xephyr") == 0) 266 if (strcmp(argv[i], "--x11=xephyr") == 0)
266 continue; 267 continue;
267 client_argv[j] = argv[i]; 268 jail_argv[j] = argv[i];
268 j++; 269 j++;
269 } 270 }
270 client_argv[j] = NULL; 271 jail_argv[j] = NULL;
271 272
272 assert(j < argc+2); // no overrun 273 assert(j < argc+2); // no overrun
273 274
274 if (arg_debug) { 275 if (arg_debug) {
275 size_t i = 0; 276 size_t i = 0;
276 printf("xephyr client:"); 277 printf("xephyr client:");
277 while (client_argv[i]!=NULL) { 278 while (jail_argv[i]!=NULL) {
278 printf(" \"%s\"", client_argv[i]); 279 printf(" \"%s\"", jail_argv[i]);
279 i++; 280 i++;
280 } 281 }
281 putchar('\n'); 282 putchar('\n');
@@ -322,13 +323,14 @@ void x11_start_xephyr(int argc, char **argv) {
322 323
323 setenv("DISPLAY", display_str, 1); 324 setenv("DISPLAY", display_str, 1);
324 // run attach command 325 // run attach command
325 client = fork(); 326 jail = fork();
326 if (client < 0) 327 if (jail < 0)
327 errExit("fork"); 328 errExit("fork");
328 if (client == 0) { 329 if (jail == 0) {
329 printf("\n*** Attaching to Xephyr display %d ***\n\n", display); 330 if (!arg_quiet)
331 printf("\n*** Attaching to Xephyr display %d ***\n\n", display);
330 332
331 execvp(client_argv[0], client_argv); 333 execvp(jail_argv[0], jail_argv);
332 perror("execvp"); 334 perror("execvp");
333 exit(1); 335 exit(1);
334 } 336 }
@@ -337,16 +339,21 @@ void x11_start_xephyr(int argc, char **argv) {
337 free(display_str); 339 free(display_str);
338 free(temp); 340 free(temp);
339 341
340 // wait for either server or client termination 342 // wait for either server or jail termination
341 pid_t pid = wait(); 343 pid_t pid = wait(NULL);
342 344
343 // see which process terminated and kill other 345 // see which process terminated and kill other
344 if (pid == server) { 346 if (pid == server) {
345 kill(client, SIGTERM); 347 kill(jail, SIGTERM);
346 } else if (pid == client) { 348 } else if (pid == jail) {
347 kill(server, SIGTERM); 349 kill(server, SIGTERM);
348 } 350 }
349 351
352 // without this closing Xephyr window may mess your terminal:
353 // "monitoring" process will release terminal before
354 // jail process ends and releases terminal
355 wait(NULL); // fulneral
356
350 exit(0); 357 exit(0);
351} 358}
352 359
@@ -381,6 +388,13 @@ void x11_start_xpra(int argc, char **argv) {
381 // build the start command 388 // build the start command
382 char *server_argv[] = { "xpra", "start", display_str, "--no-daemon", NULL }; 389 char *server_argv[] = { "xpra", "start", display_str, "--no-daemon", NULL };
383 390
391 int fd_null = -1;
392 if (arg_quiet) {
393 fd_null = open("/dev/null", O_RDWR);
394 if (fd_null == -1)
395 errExit("open");
396 }
397
384 // start 398 // start
385 server = fork(); 399 server = fork();
386 if (server < 0) 400 if (server < 0)
@@ -388,6 +402,12 @@ void x11_start_xpra(int argc, char **argv) {
388 if (server == 0) { 402 if (server == 0) {
389 if (arg_debug) 403 if (arg_debug)
390 printf("Starting xpra...\n"); 404 printf("Starting xpra...\n");
405
406 if (arg_quiet && fd_null != -1) {
407 dup2(fd_null,0);
408 dup2(fd_null,1);
409 dup2(fd_null,2);
410 }
391 411
392 execvp(server_argv[0], server_argv); 412 execvp(server_argv[0], server_argv);
393 perror("execvp"); 413 perror("execvp");
@@ -404,8 +424,7 @@ void x11_start_xpra(int argc, char **argv) {
404 sleep(1); 424 sleep(1);
405 if (stat(fname, &s) == 0) 425 if (stat(fname, &s) == 0)
406 break; 426 break;
407 }; 427 }
408// sleep(1);
409 428
410 if (n == 10) { 429 if (n == 10) {
411 fprintf(stderr, "Error: failed to start xpra\n"); 430 fprintf(stderr, "Error: failed to start xpra\n");
@@ -427,7 +446,15 @@ void x11_start_xpra(int argc, char **argv) {
427 if (client < 0) 446 if (client < 0)
428 errExit("fork"); 447 errExit("fork");
429 if (client == 0) { 448 if (client == 0) {
430 printf("\n*** Attaching to xpra display %d ***\n\n", display); 449 if (arg_quiet && fd_null != -1) {
450 dup2(fd_null,0);
451 dup2(fd_null,1);
452 dup2(fd_null,2);
453 }
454
455 if (!arg_quiet)
456 printf("\n*** Attaching to xpra display %d ***\n\n", display);
457
431 execvp(attach_argv[0], attach_argv); 458 execvp(attach_argv[0], attach_argv);
432 perror("execvp"); 459 perror("execvp");
433 exit(1); 460 exit(1);
@@ -458,7 +485,8 @@ void x11_start_xpra(int argc, char **argv) {
458 if (jail < 0) 485 if (jail < 0)
459 errExit("fork"); 486 errExit("fork");
460 if (jail == 0) { 487 if (jail == 0) {
461 execvp(firejail_argv[0], firejail_argv); 488 if (firejail_argv[0]) // shut up llvm scan-build
489 execvp(firejail_argv[0], firejail_argv);
462 perror("execvp"); 490 perror("execvp");
463 exit(1); 491 exit(1);
464 } 492 }
@@ -466,26 +494,54 @@ void x11_start_xpra(int argc, char **argv) {
466 if (!arg_quiet) 494 if (!arg_quiet)
467 printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail); 495 printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail);
468 496
497 sleep(1); // let jail start
498
469 // wait for jail or server to end 499 // wait for jail or server to end
470 while (1) { 500 while (1) {
471 pid_t pid = wait(); 501 pid_t pid = wait(NULL);
472 502
473 if (pid == jail) { 503 if (pid == jail) {
474 sleep(3); // FIXME: find better way to wait for xpra
475 char *stop_argv[] = { "xpra", "stop", display_str, NULL }; 504 char *stop_argv[] = { "xpra", "stop", display_str, NULL };
476 pid_t stop = fork(); 505 pid_t stop = fork();
477 if (stop < 0) 506 if (stop < 0)
478 errExit("fork"); 507 errExit("fork");
479 if (stop == 0) { 508 if (stop == 0) {
509 if (arg_quiet && fd_null != -1) {
510 dup2(fd_null,0);
511 dup2(fd_null,1);
512 dup2(fd_null,2);
513 }
480 execvp(stop_argv[0], stop_argv); 514 execvp(stop_argv[0], stop_argv);
481 perror("execvp"); 515 perror("execvp");
482 exit(1); 516 exit(1);
483 } 517 }
484 sleep(3); 518
519 // wait for xpra server to stop, 10 seconds limit
520 while (++n < 10) {
521 sleep(1);
522 pid = waitpid(server, NULL, WNOHANG);
523 if (pid == server)
524 break;
525 }
526
527 if (arg_debug)
528 if (n == 10)
529 printf("failed to stop xpra server gratefully\n");
530 else
531 printf("xpra server successfully stoped in %d secs\n", n);
532
533 // kill xpra server and xpra client
485 kill(client, SIGTERM); 534 kill(client, SIGTERM);
486 kill(server, SIGTERM); 535 kill(server, SIGTERM);
487 exit(0); 536 exit(0);
488 } 537 }
538 else if (pid == server) {
539 // kill firejail process
540 kill(jail, SIGTERM);
541 // kill xpra client (should die with server, but...)
542 kill(client, SIGTERM);
543 exit(0);
544 }
489 } 545 }
490} 546}
491 547
diff --git a/test/network/net_arp.exp b/test/network/net_arp.exp
index f27f85814..fdd30f218 100755
--- a/test/network/net_arp.exp
+++ b/test/network/net_arp.exp
@@ -69,6 +69,6 @@ expect {
69 "sleep 20" 69 "sleep 20"
70} 70}
71 71
72# wait for snadboxes to be shutdown 72# wait for sandboxes to be shutdown
73sleep 30 73sleep 30
74puts "\n" 74puts "\n"
diff --git a/todo b/todo
index 8fe3904da..02eacdda9 100644
--- a/todo
+++ b/todo
@@ -279,3 +279,6 @@ private-dev
279private-tmp 279private-tmp
280nosound 280nosound
281 281
28226. fix firemon and firetools on systems with hidepid=2
283
284sudo mount -o remount,rw,hidepid=2 /proc