aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Fred Barclay <Fred-Barclay@users.noreply.github.com>2017-05-22 01:48:27 -0500
committerLibravatar Fred Barclay <Fred-Barclay@users.noreply.github.com>2017-05-22 01:48:27 -0500
commitcfbcbf2c95455373aa2570827c52b7b87d80cfef (patch)
treea29ac95c58a14c7f69c9b900b10fd1d63ba4ec19
parentFix 1291 - remove nonexistent *.inc from qupzilla profile (diff)
downloadfirejail-cfbcbf2c95455373aa2570827c52b7b87d80cfef.tar.gz
firejail-cfbcbf2c95455373aa2570827c52b7b87d80cfef.tar.zst
firejail-cfbcbf2c95455373aa2570827c52b7b87d80cfef.zip
--novideo option
Still a work in progress. Code needs cleanup and improvement, but it does block /dev/video* in all of my tests so far.
-rw-r--r--src/firejail/firejail.h22
-rw-r--r--src/firejail/fs_dev.c36
-rw-r--r--src/firejail/main.c286
-rw-r--r--src/firejail/profile.c130
-rw-r--r--src/firejail/sandbox.c144
-rw-r--r--src/firejail/usage.c41
-rw-r--r--src/man/firejail-profile.txt13
-rw-r--r--src/man/firejail.txt78
8 files changed, 389 insertions, 361 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index fba4c4fe2..91b9c7be7 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -147,9 +147,9 @@ typedef struct bridge_t {
147 uint32_t mask; // interface device mask 147 uint32_t mask; // interface device mask
148 uint8_t mac[6]; // interface mac address 148 uint8_t mac[6]; // interface mac address
149 int mtu; // interface mtu 149 int mtu; // interface mtu
150 150
151 char *veth_name; // veth name for the device connected to the bridge 151 char *veth_name; // veth name for the device connected to the bridge
152 152
153 // inside the sandbox 153 // inside the sandbox
154 char *devsandbox; // name of the device inside the sandbox 154 char *devsandbox; // name of the device inside the sandbox
155 uint32_t ipsandbox; // ip address inside the sandbox 155 uint32_t ipsandbox; // ip address inside the sandbox
@@ -157,7 +157,7 @@ typedef struct bridge_t {
157 uint8_t macsandbox[6]; // mac address inside the sandbox 157 uint8_t macsandbox[6]; // mac address inside the sandbox
158 uint32_t iprange_start;// iprange arp scan start range 158 uint32_t iprange_start;// iprange arp scan start range
159 uint32_t iprange_end; // iprange arp scan end range 159 uint32_t iprange_end; // iprange arp scan end range
160 160
161 // flags 161 // flags
162 uint8_t arg_ip_none; // --ip=none 162 uint8_t arg_ip_none; // --ip=none
163 uint8_t macvlan; // set by --net=eth0 (or eth1, ...); reset by --net=br0 (or br1, ...) 163 uint8_t macvlan; // set by --net=eth0 (or eth1, ...); reset by --net=br0 (or br1, ...)
@@ -171,14 +171,14 @@ typedef struct interface_t {
171 uint32_t mask; 171 uint32_t mask;
172 uint8_t mac[6]; 172 uint8_t mac[6];
173 int mtu; 173 int mtu;
174 174
175 uint8_t configured; 175 uint8_t configured;
176} Interface; 176} Interface;
177 177
178typedef struct profile_entry_t { 178typedef struct profile_entry_t {
179 struct profile_entry_t *next; 179 struct profile_entry_t *next;
180 char *data; // command 180 char *data; // command
181 181
182 // whitelist command parameters 182 // whitelist command parameters
183 char *link; // link name - set if the file is a link 183 char *link; // link name - set if the file is a link
184 unsigned home_dir:1; // whitelist in /home/user directory 184 unsigned home_dir:1; // whitelist in /home/user directory
@@ -195,10 +195,10 @@ typedef struct config_t {
195 // user data 195 // user data
196 char *username; 196 char *username;
197 char *homedir; 197 char *homedir;
198 198
199 // filesystem 199 // filesystem
200 ProfileEntry *profile; 200 ProfileEntry *profile;
201#define MAX_PROFILE_IGNORE 32 201#define MAX_PROFILE_IGNORE 32
202 char *profile_ignore[MAX_PROFILE_IGNORE]; 202 char *profile_ignore[MAX_PROFILE_IGNORE];
203 char *chrootdir; // chroot directory 203 char *chrootdir; // chroot directory
204 char *home_private; // private home directory 204 char *home_private; // private home directory
@@ -239,12 +239,12 @@ typedef struct config_t {
239 long long unsigned rlimit_nproc; 239 long long unsigned rlimit_nproc;
240 long long unsigned rlimit_fsize; 240 long long unsigned rlimit_fsize;
241 long long unsigned rlimit_sigpending; 241 long long unsigned rlimit_sigpending;
242 242
243 // cpu affinity, nice and control groups 243 // cpu affinity, nice and control groups
244 uint32_t cpus; 244 uint32_t cpus;
245 int nice; 245 int nice;
246 char *cgroup; 246 char *cgroup;
247 247
248 248
249 // command line 249 // command line
250 char *command_line; 250 char *command_line;
@@ -331,6 +331,7 @@ extern int arg_private_tmp; // private tmp directory
331extern int arg_scan; // arp-scan all interfaces 331extern int arg_scan; // arp-scan all interfaces
332extern int arg_whitelist; // whitelist commad 332extern int arg_whitelist; // whitelist commad
333extern int arg_nosound; // disable sound 333extern int arg_nosound; // disable sound
334extern int arg_novideo; //disable video devices in /dev
334extern int arg_no3d; // disable 3d hardware acceleration 335extern int arg_no3d; // disable 3d hardware acceleration
335extern int arg_quiet; // no output for scripting 336extern int arg_quiet; // no output for scripting
336extern int arg_join_network; // join only the network namespace 337extern int arg_join_network; // join only the network namespace
@@ -724,7 +725,7 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc,
724// bitmapped filters for sbox_run 725// bitmapped filters for sbox_run
725#define SBOX_ROOT (1 << 0) // run the sandbox as root 726#define SBOX_ROOT (1 << 0) // run the sandbox as root
726#define SBOX_USER (1 << 1) // run the sandbox as a regular user 727#define SBOX_USER (1 << 1) // run the sandbox as a regular user
727#define SBOX_SECCOMP (1 << 2) // install seccomp 728#define SBOX_SECCOMP (1 << 2) // install seccomp
728#define SBOX_CAPS_NONE (1 << 3) // drop all capabilities 729#define SBOX_CAPS_NONE (1 << 3) // drop all capabilities
729#define SBOX_CAPS_NETWORK (1 << 4) // caps filter for programs running network programs 730#define SBOX_CAPS_NETWORK (1 << 4) // caps filter for programs running network programs
730#define SBOX_ALLOW_STDIN (1 << 5) // don't close stdin 731#define SBOX_ALLOW_STDIN (1 << 5) // don't close stdin
@@ -739,4 +740,3 @@ void git_install();
739void git_uninstall(); 740void git_uninstall();
740 741
741#endif 742#endif
742
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index 9b73ac9fc..159c8e654 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -26,7 +26,7 @@
26#include <fcntl.h> 26#include <fcntl.h>
27#include <pwd.h> 27#include <pwd.h>
28#ifndef _BSD_SOURCE 28#ifndef _BSD_SOURCE
29#define _BSD_SOURCE 29#define _BSD_SOURCE
30#endif 30#endif
31#include <sys/sysmacros.h> 31#include <sys/sysmacros.h>
32#include <sys/types.h> 32#include <sys/types.h>
@@ -35,6 +35,7 @@ typedef struct {
35 const char *dev_fname; 35 const char *dev_fname;
36 const char *run_fname; 36 const char *run_fname;
37 int sound; 37 int sound;
38 int video;
38 int hw3d; 39 int hw3d;
39} DevEntry; 40} DevEntry;
40 41
@@ -93,16 +94,16 @@ static void deventry_mount(void) {
93 fclose(fp); 94 fclose(fp);
94 } 95 }
95 } 96 }
96 97
97 if (mount(dev[i].run_fname, dev[i].dev_fname, NULL, MS_BIND|MS_REC, NULL) < 0) 98 if (mount(dev[i].run_fname, dev[i].dev_fname, NULL, MS_BIND|MS_REC, NULL) < 0)
98 errExit("mounting dev file"); 99 errExit("mounting dev file");
99 fs_logger2("whitelist", dev[i].dev_fname); 100 fs_logger2("whitelist", dev[i].dev_fname);
100 } 101 }
101 102
102 i++; 103 i++;
103 } 104 }
104} 105}
105 106
106static void create_char_dev(const char *path, mode_t mode, int major, int minor) { 107static void create_char_dev(const char *path, mode_t mode, int major, int minor) {
107 dev_t dev = makedev(major, minor); 108 dev_t dev = makedev(major, minor);
108 if (mknod(path, S_IFCHR | mode, dev) == -1) 109 if (mknod(path, S_IFCHR | mode, dev) == -1)
@@ -112,7 +113,7 @@ static void create_char_dev(const char *path, mode_t mode, int major, int minor)
112 ASSERT_PERMS(path, 0, 0, mode); 113 ASSERT_PERMS(path, 0, 0, mode);
113 114
114 return; 115 return;
115 116
116errexit: 117errexit:
117 fprintf(stderr, "Error: cannot create %s device\n", path); 118 fprintf(stderr, "Error: cannot create %s device\n", path);
118 exit(1); 119 exit(1);
@@ -161,7 +162,7 @@ void fs_private_dev(void){
161 if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) 162 if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
162 errExit("mounting /dev"); 163 errExit("mounting /dev");
163 fs_logger("tmpfs /dev"); 164 fs_logger("tmpfs /dev");
164 165
165 deventry_mount(); 166 deventry_mount();
166 167
167 // bring back /dev/log 168 // bring back /dev/log
@@ -174,11 +175,11 @@ void fs_private_dev(void){
174 errExit("mounting /dev/log"); 175 errExit("mounting /dev/log");
175 fs_logger("clone /dev/log"); 176 fs_logger("clone /dev/log");
176 } 177 }
177 } 178 }
178 if (mount(RUN_RO_DIR, RUN_DEV_DIR, "none", MS_BIND, "mode=400,gid=0") < 0) 179 if (mount(RUN_RO_DIR, RUN_DEV_DIR, "none", MS_BIND, "mode=400,gid=0") < 0)
179 errExit("disable /dev/snd"); 180 errExit("disable /dev/snd");
180 181
181 182
182 // create /dev/shm 183 // create /dev/shm
183 if (arg_debug) 184 if (arg_debug)
184 printf("Create /dev/shm directory\n"); 185 printf("Create /dev/shm directory\n");
@@ -267,24 +268,24 @@ void fs_dev_shm(void) {
267 fwarning("/dev/shm not mounted\n"); 268 fwarning("/dev/shm not mounted\n");
268 dbg_test_dir("/dev/shm"); 269 dbg_test_dir("/dev/shm");
269 } 270 }
270 271
271 } 272 }
272} 273}
273#endif 274#endif
274 275
275static void disable_file_or_dir(const char *fname) { 276static void disable_file_or_dir(const char *fname) {
276 if (arg_debug) 277 if (arg_debug)
277 printf("disable %s\n", fname); 278 printf("disable %s\n", fname);
278 struct stat s; 279 struct stat s;
279 if (stat(fname, &s) != -1) { 280 if (stat(fname, &s) != -1) {
280 if (is_dir(fname)) { 281 if (is_dir(fname)) {
281 if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) 282 if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0)
282 errExit("disable directory"); 283 errExit("disable directory");
283 } 284 }
284 else { 285 else {
285 if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) 286 if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0)
286 errExit("disable file"); 287 errExit("disable file");
287 } 288 }
288 } 289 }
289 fs_logger2("blacklist", fname); 290 fs_logger2("blacklist", fname);
290 291
@@ -299,6 +300,15 @@ void fs_dev_disable_sound(void) {
299 } 300 }
300} 301}
301 302
303void fs_dev_disable_video(void) {
304 int i = 0;
305 while (dev[i].dev_fname != NULL) {
306 if (dev[i].video)
307 disable_file_or_dir(dev[i].dev_fname);
308 i++;
309 }
310}
311
302void fs_dev_disable_3d(void) { 312void fs_dev_disable_3d(void) {
303 int i = 0; 313 int i = 0;
304 while (dev[i].dev_fname != NULL) { 314 while (dev[i].dev_fname != NULL) {
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 86ca422ae..012b2f230 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -88,6 +88,7 @@ int arg_private_tmp = 0; // private tmp directory
88int arg_scan = 0; // arp-scan all interfaces 88int arg_scan = 0; // arp-scan all interfaces
89int arg_whitelist = 0; // whitelist commad 89int arg_whitelist = 0; // whitelist commad
90int arg_nosound = 0; // disable sound 90int arg_nosound = 0; // disable sound
91int arg_novideo = 0; //disable video devices in /dev
91int arg_no3d; // disable 3d hardware acceleration 92int arg_no3d; // disable 3d hardware acceleration
92int arg_quiet = 0; // no output for scripting 93int arg_quiet = 0; // no output for scripting
93int arg_join_network = 0; // join only the network namespace 94int arg_join_network = 0; // join only the network namespace
@@ -143,7 +144,7 @@ static void myexit(int rv) {
143 clear_run_files(sandbox_pid); 144 clear_run_files(sandbox_pid);
144 appimage_clear(); 145 appimage_clear();
145 flush_stdin(); 146 flush_stdin();
146 exit(rv); 147 exit(rv);
147} 148}
148 149
149static void my_handler(int s){ 150static void my_handler(int s){
@@ -163,7 +164,7 @@ static pid_t extract_pid(const char *name) {
163 fprintf(stderr, "Error: invalid sandbox name\n"); 164 fprintf(stderr, "Error: invalid sandbox name\n");
164 exit(1); 165 exit(1);
165 } 166 }
166 167
167 pid_t pid; 168 pid_t pid;
168 EUID_ROOT(); 169 EUID_ROOT();
169 if (name2pid(name, &pid)) { 170 if (name2pid(name, &pid)) {
@@ -201,7 +202,7 @@ static void init_cfg(int argc, char **argv) {
201 cfg.bridge1.devsandbox = "eth1"; 202 cfg.bridge1.devsandbox = "eth1";
202 cfg.bridge2.devsandbox = "eth2"; 203 cfg.bridge2.devsandbox = "eth2";
203 cfg.bridge3.devsandbox = "eth3"; 204 cfg.bridge3.devsandbox = "eth3";
204 205
205 // extract user data 206 // extract user data
206 EUID_ROOT(); // rise permissions for grsecurity 207 EUID_ROOT(); // rise permissions for grsecurity
207 struct passwd *pw = getpwuid(getuid()); 208 struct passwd *pw = getpwuid(getuid());
@@ -249,7 +250,7 @@ void check_user_namespace(void) {
249 EUID_ASSERT(); 250 EUID_ASSERT();
250 if (getuid() == 0) 251 if (getuid() == 0)
251 goto errout; 252 goto errout;
252 253
253 // test user namespaces available in the kernel 254 // test user namespaces available in the kernel
254 struct stat s1; 255 struct stat s1;
255 struct stat s2; 256 struct stat s2;
@@ -280,7 +281,7 @@ static void exit_err_feature(const char *feature) {
280// this function handles command line options such as --version and --help 281// this function handles command line options such as --version and --help
281static void run_cmd_and_exit(int i, int argc, char **argv) { 282static void run_cmd_and_exit(int i, int argc, char **argv) {
282 EUID_ASSERT(); 283 EUID_ASSERT();
283 284
284 //************************************* 285 //*************************************
285 // basic arguments 286 // basic arguments
286 //************************************* 287 //*************************************
@@ -303,7 +304,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
303 if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) 304 if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1)
304 errExit("asprintf"); 305 errExit("asprintf");
305 EUID_ROOT(); 306 EUID_ROOT();
306 if (setreuid(0, 0) < 0 || 307 if (setreuid(0, 0) < 0 ||
307 setregid(0, 0) < 0) 308 setregid(0, 0) < 0)
308 errExit("setreuid/setregid"); 309 errExit("setreuid/setregid");
309 errno = 0; 310 errno = 0;
@@ -349,11 +350,11 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
349 exit_err_feature("x11"); 350 exit_err_feature("x11");
350 } 351 }
351#endif 352#endif
352#ifdef HAVE_NETWORK 353#ifdef HAVE_NETWORK
353 else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { 354 else if (strncmp(argv[i], "--bandwidth=", 12) == 0) {
354 if (checkcfg(CFG_NETWORK)) { 355 if (checkcfg(CFG_NETWORK)) {
355 logargs(argc, argv); 356 logargs(argc, argv);
356 357
357 // extract the command 358 // extract the command
358 if ((i + 1) == argc) { 359 if ((i + 1) == argc) {
359 fprintf(stderr, "Error: command expected after --bandwidth option\n"); 360 fprintf(stderr, "Error: command expected after --bandwidth option\n");
@@ -364,7 +365,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
364 fprintf(stderr, "Error: invalid --bandwidth command.\nValid commands: set, clear, status.\n"); 365 fprintf(stderr, "Error: invalid --bandwidth command.\nValid commands: set, clear, status.\n");
365 exit(1); 366 exit(1);
366 } 367 }
367 368
368 // extract network name 369 // extract network name
369 char *dev = NULL; 370 char *dev = NULL;
370 int down = 0; 371 int down = 0;
@@ -376,20 +377,20 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
376 exit(1); 377 exit(1);
377 } 378 }
378 dev = argv[i + 2]; 379 dev = argv[i + 2];
379 380
380 // check device name 381 // check device name
381 if (if_nametoindex(dev) == 0) { 382 if (if_nametoindex(dev) == 0) {
382 fprintf(stderr, "Error: network device %s not found\n", dev); 383 fprintf(stderr, "Error: network device %s not found\n", dev);
383 exit(1); 384 exit(1);
384 } 385 }
385 386
386 // extract bandwidth 387 // extract bandwidth
387 if (strcmp(cmd, "set") == 0) { 388 if (strcmp(cmd, "set") == 0) {
388 if ((i + 4) >= argc) { 389 if ((i + 4) >= argc) {
389 fprintf(stderr, "Error: invalid --bandwidth set command\n"); 390 fprintf(stderr, "Error: invalid --bandwidth set command\n");
390 exit(1); 391 exit(1);
391 } 392 }
392 393
393 down = atoi(argv[i + 3]); 394 down = atoi(argv[i + 3]);
394 if (down < 0) { 395 if (down < 0) {
395 fprintf(stderr, "Error: invalid download speed\n"); 396 fprintf(stderr, "Error: invalid download speed\n");
@@ -401,8 +402,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
401 exit(1); 402 exit(1);
402 } 403 }
403 } 404 }
404 } 405 }
405 406
406 // extract pid or sandbox name 407 // extract pid or sandbox name
407 pid_t pid = read_pid(argv[i] + 12); 408 pid_t pid = read_pid(argv[i] + 12);
408 bandwidth_pid(pid, cmd, dev, down, up); 409 bandwidth_pid(pid, cmd, dev, down, up);
@@ -450,7 +451,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
450 else if (strncmp(argv[i], "--protocol.print=", 17) == 0) { 451 else if (strncmp(argv[i], "--protocol.print=", 17) == 0) {
451 if (checkcfg(CFG_SECCOMP)) { 452 if (checkcfg(CFG_SECCOMP)) {
452 // print seccomp filter for a sandbox specified by pid or by name 453 // print seccomp filter for a sandbox specified by pid or by name
453 pid_t pid = read_pid(argv[i] + 17); 454 pid_t pid = read_pid(argv[i] + 17);
454 protocol_print_filter(pid); 455 protocol_print_filter(pid);
455 } 456 }
456 else 457 else
@@ -509,7 +510,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
509 2, PATH_FIREMON, "--top"); 510 2, PATH_FIREMON, "--top");
510 exit(0); 511 exit(0);
511 } 512 }
512#ifdef HAVE_NETWORK 513#ifdef HAVE_NETWORK
513 else if (strcmp(argv[i], "--netstats") == 0) { 514 else if (strcmp(argv[i], "--netstats") == 0) {
514 if (checkcfg(CFG_NETWORK)) { 515 if (checkcfg(CFG_NETWORK)) {
515 struct stat s; 516 struct stat s;
@@ -524,12 +525,12 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
524 else 525 else
525 exit_err_feature("networking"); 526 exit_err_feature("networking");
526 } 527 }
527#endif 528#endif
528#ifdef HAVE_FILE_TRANSFER 529#ifdef HAVE_FILE_TRANSFER
529 else if (strncmp(argv[i], "--get=", 6) == 0) { 530 else if (strncmp(argv[i], "--get=", 6) == 0) {
530 if (checkcfg(CFG_FILE_TRANSFER)) { 531 if (checkcfg(CFG_FILE_TRANSFER)) {
531 logargs(argc, argv); 532 logargs(argc, argv);
532 533
533 // verify path 534 // verify path
534 if ((i + 2) != argc) { 535 if ((i + 2) != argc) {
535 fprintf(stderr, "Error: invalid --get option, path expected\n"); 536 fprintf(stderr, "Error: invalid --get option, path expected\n");
@@ -541,7 +542,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
541 fprintf(stderr, "Error: invalid file name %s\n", path); 542 fprintf(stderr, "Error: invalid file name %s\n", path);
542 exit(1); 543 exit(1);
543 } 544 }
544 545
545 // get file 546 // get file
546 pid_t pid = read_pid(argv[i] + 6); 547 pid_t pid = read_pid(argv[i] + 6);
547 sandboxfs(SANDBOX_FS_GET, pid, path, NULL); 548 sandboxfs(SANDBOX_FS_GET, pid, path, NULL);
@@ -553,7 +554,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
553 else if (strncmp(argv[i], "--put=", 6) == 0) { 554 else if (strncmp(argv[i], "--put=", 6) == 0) {
554 if (checkcfg(CFG_FILE_TRANSFER)) { 555 if (checkcfg(CFG_FILE_TRANSFER)) {
555 logargs(argc, argv); 556 logargs(argc, argv);
556 557
557 // verify path 558 // verify path
558 if ((i + 3) != argc) { 559 if ((i + 3) != argc) {
559 fprintf(stderr, "Error: invalid --put option, 2 paths expected\n"); 560 fprintf(stderr, "Error: invalid --put option, 2 paths expected\n");
@@ -571,7 +572,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
571 fprintf(stderr, "Error: invalid file name %s\n", path2); 572 fprintf(stderr, "Error: invalid file name %s\n", path2);
572 exit(1); 573 exit(1);
573 } 574 }
574 575
575 // get file 576 // get file
576 pid_t pid = read_pid(argv[i] + 6); 577 pid_t pid = read_pid(argv[i] + 6);
577 sandboxfs(SANDBOX_FS_PUT, pid, path1, path2); 578 sandboxfs(SANDBOX_FS_PUT, pid, path1, path2);
@@ -583,7 +584,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
583 else if (strncmp(argv[i], "--ls=", 5) == 0) { 584 else if (strncmp(argv[i], "--ls=", 5) == 0) {
584 if (checkcfg(CFG_FILE_TRANSFER)) { 585 if (checkcfg(CFG_FILE_TRANSFER)) {
585 logargs(argc, argv); 586 logargs(argc, argv);
586 587
587 // verify path 588 // verify path
588 if ((i + 2) != argc) { 589 if ((i + 2) != argc) {
589 fprintf(stderr, "Error: invalid --ls option, path expected\n"); 590 fprintf(stderr, "Error: invalid --ls option, path expected\n");
@@ -595,7 +596,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
595 fprintf(stderr, "Error: invalid file name %s\n", path); 596 fprintf(stderr, "Error: invalid file name %s\n", path);
596 exit(1); 597 exit(1);
597 } 598 }
598 599
599 // list directory contents 600 // list directory contents
600 pid_t pid = read_pid(argv[i] + 5); 601 pid_t pid = read_pid(argv[i] + 5);
601 sandboxfs(SANDBOX_FS_LS, pid, path, NULL); 602 sandboxfs(SANDBOX_FS_LS, pid, path, NULL);
@@ -608,7 +609,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
608 else if (strncmp(argv[i], "--join=", 7) == 0) { 609 else if (strncmp(argv[i], "--join=", 7) == 0) {
609 if (checkcfg(CFG_JOIN) || getuid() == 0) { 610 if (checkcfg(CFG_JOIN) || getuid() == 0) {
610 logargs(argc, argv); 611 logargs(argc, argv);
611 612
612 if (arg_shell_none) { 613 if (arg_shell_none) {
613 if (argc <= (i+1)) { 614 if (argc <= (i+1)) {
614 fprintf(stderr, "Error: --shell=none set, but no command specified\n"); 615 fprintf(stderr, "Error: --shell=none set, but no command specified\n");
@@ -616,10 +617,10 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
616 } 617 }
617 cfg.original_program_index = i + 1; 618 cfg.original_program_index = i + 1;
618 } 619 }
619 620
620 if (!cfg.shell && !arg_shell_none) 621 if (!cfg.shell && !arg_shell_none)
621 cfg.shell = guess_shell(); 622 cfg.shell = guess_shell();
622 623
623 // join sandbox by pid or by name 624 // join sandbox by pid or by name
624 pid_t pid = read_pid(argv[i] + 7); 625 pid_t pid = read_pid(argv[i] + 7);
625 join(pid, argc, argv, i + 1); 626 join(pid, argc, argv, i + 1);
@@ -652,10 +653,10 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
652 join(pid, argc, argv, i + 1); 653 join(pid, argc, argv, i + 1);
653 exit(0); 654 exit(0);
654 } 655 }
655#endif 656#endif
656 // if there no such sandbox continue argument processing 657 // if there no such sandbox continue argument processing
657 } 658 }
658#ifdef HAVE_NETWORK 659#ifdef HAVE_NETWORK
659 else if (strncmp(argv[i], "--join-network=", 15) == 0) { 660 else if (strncmp(argv[i], "--join-network=", 15) == 0) {
660 if (checkcfg(CFG_NETWORK)) { 661 if (checkcfg(CFG_NETWORK)) {
661 logargs(argc, argv); 662 logargs(argc, argv);
@@ -664,7 +665,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
664 fprintf(stderr, "Error: --join-network is only available to root user\n"); 665 fprintf(stderr, "Error: --join-network is only available to root user\n");
665 exit(1); 666 exit(1);
666 } 667 }
667 668
668 if (!cfg.shell && !arg_shell_none) 669 if (!cfg.shell && !arg_shell_none)
669 cfg.shell = guess_shell(); 670 cfg.shell = guess_shell();
670 671
@@ -684,7 +685,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
684 fprintf(stderr, "Error: --join-filesystem is only available to root user\n"); 685 fprintf(stderr, "Error: --join-filesystem is only available to root user\n");
685 exit(1); 686 exit(1);
686 } 687 }
687 688
688 if (!cfg.shell && !arg_shell_none) 689 if (!cfg.shell && !arg_shell_none)
689 cfg.shell = guess_shell(); 690 cfg.shell = guess_shell();
690 691
@@ -695,7 +696,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
695 } 696 }
696 else if (strncmp(argv[i], "--shutdown=", 11) == 0) { 697 else if (strncmp(argv[i], "--shutdown=", 11) == 0) {
697 logargs(argc, argv); 698 logargs(argc, argv);
698 699
699 // shutdown sandbox by pid or by name 700 // shutdown sandbox by pid or by name
700 pid_t pid = read_pid(argv[i] + 11); 701 pid_t pid = read_pid(argv[i] + 11);
701 shut(pid); 702 shut(pid);
@@ -801,7 +802,7 @@ static int check_arg(int argc, char **argv, const char *argument) {
801 if (strncmp(argv[i], "--", 2) != 0) 802 if (strncmp(argv[i], "--", 2) != 0)
802 break; 803 break;
803 } 804 }
804 805
805 return found; 806 return found;
806} 807}
807 808
@@ -825,7 +826,7 @@ int main(int argc, char **argv) {
825 826
826 // build /run/firejail directory structure 827 // build /run/firejail directory structure
827 preproc_build_firejail_dir(); 828 preproc_build_firejail_dir();
828 829
829 if (check_arg(argc, argv, "--quiet")) 830 if (check_arg(argc, argv, "--quiet"))
830 arg_quiet = 1; 831 arg_quiet = 1;
831 if (check_arg(argc, argv, "--allow-debuggers")) { 832 if (check_arg(argc, argv, "--allow-debuggers")) {
@@ -870,7 +871,7 @@ int main(int argc, char **argv) {
870 // If LXC is detected, start firejail sandbox 871 // If LXC is detected, start firejail sandbox
871 // otherwise try to detect a PID namespace by looking under /proc for specific kernel processes and: 872 // otherwise try to detect a PID namespace by looking under /proc for specific kernel processes and:
872 // - if --force flag is set, start firejail sandbox 873 // - if --force flag is set, start firejail sandbox
873 // -- if --force flag is not set, start the application in a /bin/bash shell 874 // -- if --force flag is not set, start the application in a /bin/bash shell
874 if (check_namespace_virt() == 0) { 875 if (check_namespace_virt() == 0) {
875 EUID_ROOT(); 876 EUID_ROOT();
876 int rv = check_kernel_procs(); 877 int rv = check_kernel_procs();
@@ -884,7 +885,7 @@ int main(int argc, char **argv) {
884 printf("firejail version %s\n", VERSION); 885 printf("firejail version %s\n", VERSION);
885 exit(0); 886 exit(0);
886 } 887 }
887 888
888 // start the program directly without sandboxing 889 // start the program directly without sandboxing
889 run_no_sandbox(argc, argv); 890 run_no_sandbox(argc, argv);
890 // it will never get here! 891 // it will never get here!
@@ -916,9 +917,9 @@ int main(int argc, char **argv) {
916 network_del_run_file(sandbox_pid); 917 network_del_run_file(sandbox_pid);
917 delete_name_file(sandbox_pid); 918 delete_name_file(sandbox_pid);
918 delete_x11_file(sandbox_pid); 919 delete_x11_file(sandbox_pid);
919 920
920 EUID_USER(); 921 EUID_USER();
921 922
922 //check if the parent is sshd daemon 923 //check if the parent is sshd daemon
923 int parent_sshd = 0; 924 int parent_sshd = 0;
924 { 925 {
@@ -959,7 +960,7 @@ int main(int argc, char **argv) {
959 } 960 }
960 EUID_USER();} 961 EUID_USER();}
961#endif 962#endif
962 963
963 drop_privs(1); 964 drop_privs(1);
964 int rv = system(argv[2]); 965 int rv = system(argv[2]);
965 exit(rv); 966 exit(rv);
@@ -970,14 +971,14 @@ int main(int argc, char **argv) {
970 free(comm); 971 free(comm);
971 } 972 }
972 } 973 }
973 974
974 // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users 975 // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users
975 if (*argv[0] == '-' || parent_sshd) { 976 if (*argv[0] == '-' || parent_sshd) {
976 if (argc == 1) 977 if (argc == 1)
977 login_shell = 1; 978 login_shell = 1;
978 fullargc = restricted_shell(cfg.username); 979 fullargc = restricted_shell(cfg.username);
979 if (fullargc) { 980 if (fullargc) {
980 981
981#ifdef DEBUG_RESTRICTED_SHELL 982#ifdef DEBUG_RESTRICTED_SHELL
982 {EUID_ROOT(); 983 {EUID_ROOT();
983 FILE *fp = fopen("/firelog", "a"); 984 FILE *fp = fopen("/firelog", "a");
@@ -991,7 +992,7 @@ int main(int argc, char **argv) {
991 } 992 }
992 EUID_USER();} 993 EUID_USER();}
993#endif 994#endif
994 995
995 int j; 996 int j;
996 for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++) 997 for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++)
997 fullargv[j] = argv[i]; 998 fullargv[j] = argv[i];
@@ -1019,23 +1020,23 @@ int main(int argc, char **argv) {
1019 // check --output option and execute it; 1020 // check --output option and execute it;
1020 check_output(argc, argv); // the function will not return if --output option was found 1021 check_output(argc, argv); // the function will not return if --output option was found
1021 } 1022 }
1022 1023
1023 1024
1024 // check for force-nonewprivs in /etc/firejail/firejail.config file 1025 // check for force-nonewprivs in /etc/firejail/firejail.config file
1025 if (checkcfg(CFG_FORCE_NONEWPRIVS)) 1026 if (checkcfg(CFG_FORCE_NONEWPRIVS))
1026 arg_nonewprivs = 1; 1027 arg_nonewprivs = 1;
1027 1028
1028 if (arg_allow_debuggers) { 1029 if (arg_allow_debuggers) {
1029 char *cmd = strdup("noblacklist ${PATH}/strace"); 1030 char *cmd = strdup("noblacklist ${PATH}/strace");
1030 if (!cmd) 1031 if (!cmd)
1031 errExit("strdup"); 1032 errExit("strdup");
1032 profile_add(cmd); 1033 profile_add(cmd);
1033 } 1034 }
1034 1035
1035 // parse arguments 1036 // parse arguments
1036 for (i = 1; i < argc; i++) { 1037 for (i = 1; i < argc; i++) {
1037 run_cmd_and_exit(i, argc, argv); // will exit if the command is recognized 1038 run_cmd_and_exit(i, argc, argv); // will exit if the command is recognized
1038 1039
1039 if (strcmp(argv[i], "--debug") == 0) { 1040 if (strcmp(argv[i], "--debug") == 0) {
1040 if (!arg_quiet) { 1041 if (!arg_quiet) {
1041 arg_debug = 1; 1042 arg_debug = 1;
@@ -1065,7 +1066,7 @@ int main(int argc, char **argv) {
1065#ifdef HAVE_APPARMOR 1066#ifdef HAVE_APPARMOR
1066 else if (strcmp(argv[i], "--apparmor") == 0) 1067 else if (strcmp(argv[i], "--apparmor") == 0)
1067 arg_apparmor = 1; 1068 arg_apparmor = 1;
1068#endif 1069#endif
1069#ifdef HAVE_SECCOMP 1070#ifdef HAVE_SECCOMP
1070 else if (strncmp(argv[i], "--protocol=", 11) == 0) { 1071 else if (strncmp(argv[i], "--protocol=", 11) == 0) {
1071 if (checkcfg(CFG_SECCOMP)) { 1072 if (checkcfg(CFG_SECCOMP)) {
@@ -1079,7 +1080,7 @@ int main(int argc, char **argv) {
1079 errExit("strdup"); 1080 errExit("strdup");
1080 } 1081 }
1081 } 1082 }
1082 else 1083 else
1083 exit_err_feature("seccomp"); 1084 exit_err_feature("seccomp");
1084 } 1085 }
1085 else if (strcmp(argv[i], "--seccomp") == 0) { 1086 else if (strcmp(argv[i], "--seccomp") == 0) {
@@ -1129,7 +1130,7 @@ int main(int argc, char **argv) {
1129 else 1130 else
1130 exit_err_feature("seccomp"); 1131 exit_err_feature("seccomp");
1131 } 1132 }
1132#endif 1133#endif
1133 else if (strcmp(argv[i], "--caps") == 0) 1134 else if (strcmp(argv[i], "--caps") == 0)
1134 arg_caps_default_filter = 1; 1135 arg_caps_default_filter = 1;
1135 else if (strcmp(argv[i], "--caps.drop=all") == 0) 1136 else if (strcmp(argv[i], "--caps.drop=all") == 0)
@@ -1160,22 +1161,22 @@ int main(int argc, char **argv) {
1160 check_unsigned(argv[i] + 16, "Error: invalid rlimit"); 1161 check_unsigned(argv[i] + 16, "Error: invalid rlimit");
1161 sscanf(argv[i] + 16, "%llu", &cfg.rlimit_nofile); 1162 sscanf(argv[i] + 16, "%llu", &cfg.rlimit_nofile);
1162 arg_rlimit_nofile = 1; 1163 arg_rlimit_nofile = 1;
1163 } 1164 }
1164 else if (strncmp(argv[i], "--rlimit-nproc=", 15) == 0) { 1165 else if (strncmp(argv[i], "--rlimit-nproc=", 15) == 0) {
1165 check_unsigned(argv[i] + 15, "Error: invalid rlimit"); 1166 check_unsigned(argv[i] + 15, "Error: invalid rlimit");
1166 sscanf(argv[i] + 15, "%llu", &cfg.rlimit_nproc); 1167 sscanf(argv[i] + 15, "%llu", &cfg.rlimit_nproc);
1167 arg_rlimit_nproc = 1; 1168 arg_rlimit_nproc = 1;
1168 } 1169 }
1169 else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) { 1170 else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) {
1170 check_unsigned(argv[i] + 15, "Error: invalid rlimit"); 1171 check_unsigned(argv[i] + 15, "Error: invalid rlimit");
1171 sscanf(argv[i] + 15, "%llu", &cfg.rlimit_fsize); 1172 sscanf(argv[i] + 15, "%llu", &cfg.rlimit_fsize);
1172 arg_rlimit_fsize = 1; 1173 arg_rlimit_fsize = 1;
1173 } 1174 }
1174 else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) { 1175 else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) {
1175 check_unsigned(argv[i] + 20, "Error: invalid rlimit"); 1176 check_unsigned(argv[i] + 20, "Error: invalid rlimit");
1176 sscanf(argv[i] + 20, "%llu", &cfg.rlimit_sigpending); 1177 sscanf(argv[i] + 20, "%llu", &cfg.rlimit_sigpending);
1177 arg_rlimit_sigpending = 1; 1178 arg_rlimit_sigpending = 1;
1178 } 1179 }
1179 else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) 1180 else if (strncmp(argv[i], "--ipc-namespace", 15) == 0)
1180 arg_ipc = 1; 1181 arg_ipc = 1;
1181 else if (strncmp(argv[i], "--cpu=", 6) == 0) 1182 else if (strncmp(argv[i], "--cpu=", 6) == 0)
@@ -1191,26 +1192,26 @@ int main(int argc, char **argv) {
1191 fprintf(stderr, "Error: only a cgroup can be defined\n"); 1192 fprintf(stderr, "Error: only a cgroup can be defined\n");
1192 exit(1); 1193 exit(1);
1193 } 1194 }
1194 1195
1195 option_cgroup = 1; 1196 option_cgroup = 1;
1196 cfg.cgroup = strdup(argv[i] + 9); 1197 cfg.cgroup = strdup(argv[i] + 9);
1197 if (!cfg.cgroup) 1198 if (!cfg.cgroup)
1198 errExit("strdup"); 1199 errExit("strdup");
1199 set_cgroup(cfg.cgroup); 1200 set_cgroup(cfg.cgroup);
1200 } 1201 }
1201 1202
1202 //************************************* 1203 //*************************************
1203 // filesystem 1204 // filesystem
1204 //************************************* 1205 //*************************************
1205 else if (strcmp(argv[i], "--allusers") == 0) 1206 else if (strcmp(argv[i], "--allusers") == 0)
1206 arg_allusers = 1; 1207 arg_allusers = 1;
1207#ifdef HAVE_BIND 1208#ifdef HAVE_BIND
1208 else if (strncmp(argv[i], "--bind=", 7) == 0) { 1209 else if (strncmp(argv[i], "--bind=", 7) == 0) {
1209 if (checkcfg(CFG_BIND)) { 1210 if (checkcfg(CFG_BIND)) {
1210 char *line; 1211 char *line;
1211 if (asprintf(&line, "bind %s", argv[i] + 7) == -1) 1212 if (asprintf(&line, "bind %s", argv[i] + 7) == -1)
1212 errExit("asprintf"); 1213 errExit("asprintf");
1213 1214
1214 profile_check_line(line, 0, NULL); // will exit if something wrong 1215 profile_check_line(line, 0, NULL); // will exit if something wrong
1215 profile_add(line); 1216 profile_add(line);
1216 } 1217 }
@@ -1222,7 +1223,7 @@ int main(int argc, char **argv) {
1222 char *line; 1223 char *line;
1223 if (asprintf(&line, "tmpfs %s", argv[i] + 8) == -1) 1224 if (asprintf(&line, "tmpfs %s", argv[i] + 8) == -1)
1224 errExit("asprintf"); 1225 errExit("asprintf");
1225 1226
1226 profile_check_line(line, 0, NULL); // will exit if something wrong 1227 profile_check_line(line, 0, NULL); // will exit if something wrong
1227 profile_add(line); 1228 profile_add(line);
1228 } 1229 }
@@ -1230,7 +1231,7 @@ int main(int argc, char **argv) {
1230 char *line; 1231 char *line;
1231 if (asprintf(&line, "blacklist %s", argv[i] + 12) == -1) 1232 if (asprintf(&line, "blacklist %s", argv[i] + 12) == -1)
1232 errExit("asprintf"); 1233 errExit("asprintf");
1233 1234
1234 profile_check_line(line, 0, NULL); // will exit if something wrong 1235 profile_check_line(line, 0, NULL); // will exit if something wrong
1235 profile_add(line); 1236 profile_add(line);
1236 } 1237 }
@@ -1238,7 +1239,7 @@ int main(int argc, char **argv) {
1238 char *line; 1239 char *line;
1239 if (asprintf(&line, "noblacklist %s", argv[i] + 14) == -1) 1240 if (asprintf(&line, "noblacklist %s", argv[i] + 14) == -1)
1240 errExit("asprintf"); 1241 errExit("asprintf");
1241 1242
1242 profile_check_line(line, 0, NULL); // will exit if something wrong 1243 profile_check_line(line, 0, NULL); // will exit if something wrong
1243 profile_add(line); 1244 profile_add(line);
1244 } 1245 }
@@ -1249,7 +1250,7 @@ int main(int argc, char **argv) {
1249 char *line; 1250 char *line;
1250 if (asprintf(&line, "whitelist %s", argv[i] + 12) == -1) 1251 if (asprintf(&line, "whitelist %s", argv[i] + 12) == -1)
1251 errExit("asprintf"); 1252 errExit("asprintf");
1252 1253
1253 profile_check_line(line, 0, NULL); // will exit if something wrong 1254 profile_check_line(line, 0, NULL); // will exit if something wrong
1254 profile_add(line); 1255 profile_add(line);
1255 } 1256 }
@@ -1260,17 +1261,17 @@ int main(int argc, char **argv) {
1260 char *line; 1261 char *line;
1261 if (asprintf(&line, "nowhitelist %s", argv[i] + 14) == -1) 1262 if (asprintf(&line, "nowhitelist %s", argv[i] + 14) == -1)
1262 errExit("asprintf"); 1263 errExit("asprintf");
1263 1264
1264 profile_check_line(line, 0, NULL); // will exit if something wrong 1265 profile_check_line(line, 0, NULL); // will exit if something wrong
1265 profile_add(line); 1266 profile_add(line);
1266 } 1267 }
1267#endif 1268#endif
1268 1269
1269 else if (strncmp(argv[i], "--read-only=", 12) == 0) { 1270 else if (strncmp(argv[i], "--read-only=", 12) == 0) {
1270 char *line; 1271 char *line;
1271 if (asprintf(&line, "read-only %s", argv[i] + 12) == -1) 1272 if (asprintf(&line, "read-only %s", argv[i] + 12) == -1)
1272 errExit("asprintf"); 1273 errExit("asprintf");
1273 1274
1274 profile_check_line(line, 0, NULL); // will exit if something wrong 1275 profile_check_line(line, 0, NULL); // will exit if something wrong
1275 profile_add(line); 1276 profile_add(line);
1276 } 1277 }
@@ -1278,7 +1279,7 @@ int main(int argc, char **argv) {
1278 char *line; 1279 char *line;
1279 if (asprintf(&line, "noexec %s", argv[i] + 9) == -1) 1280 if (asprintf(&line, "noexec %s", argv[i] + 9) == -1)
1280 errExit("asprintf"); 1281 errExit("asprintf");
1281 1282
1282 profile_check_line(line, 0, NULL); // will exit if something wrong 1283 profile_check_line(line, 0, NULL); // will exit if something wrong
1283 profile_add(line); 1284 profile_add(line);
1284 } 1285 }
@@ -1286,7 +1287,7 @@ int main(int argc, char **argv) {
1286 char *line; 1287 char *line;
1287 if (asprintf(&line, "read-write %s", argv[i] + 13) == -1) 1288 if (asprintf(&line, "read-write %s", argv[i] + 13) == -1)
1288 errExit("asprintf"); 1289 errExit("asprintf");
1289 1290
1290 profile_check_line(line, 0, NULL); // will exit if something wrong 1291 profile_check_line(line, 0, NULL); // will exit if something wrong
1291 profile_add(line); 1292 profile_add(line);
1292 } 1293 }
@@ -1300,16 +1301,16 @@ int main(int argc, char **argv) {
1300 struct stat s; 1301 struct stat s;
1301 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { 1302 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1302 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n"); 1303 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1303 exit(1); 1304 exit(1);
1304 } 1305 }
1305 arg_overlay = 1; 1306 arg_overlay = 1;
1306 arg_overlay_keep = 1; 1307 arg_overlay_keep = 1;
1307 1308
1308 char *subdirname; 1309 char *subdirname;
1309 if (asprintf(&subdirname, "%d", getpid()) == -1) 1310 if (asprintf(&subdirname, "%d", getpid()) == -1)
1310 errExit("asprintf"); 1311 errExit("asprintf");
1311 cfg.overlay_dir = fs_check_overlay_dir(subdirname, arg_overlay_reuse); 1312 cfg.overlay_dir = fs_check_overlay_dir(subdirname, arg_overlay_reuse);
1312 1313
1313 free(subdirname); 1314 free(subdirname);
1314 } 1315 }
1315 else 1316 else
@@ -1329,13 +1330,13 @@ int main(int argc, char **argv) {
1329 arg_overlay = 1; 1330 arg_overlay = 1;
1330 arg_overlay_keep = 1; 1331 arg_overlay_keep = 1;
1331 arg_overlay_reuse = 1; 1332 arg_overlay_reuse = 1;
1332 1333
1333 char *subdirname = argv[i] + 16; 1334 char *subdirname = argv[i] + 16;
1334 if (subdirname == '\0') { 1335 if (subdirname == '\0') {
1335 fprintf(stderr, "Error: invalid overlay option\n"); 1336 fprintf(stderr, "Error: invalid overlay option\n");
1336 exit(1); 1337 exit(1);
1337 } 1338 }
1338 1339
1339 // check name 1340 // check name
1340 invalid_filename(subdirname); 1341 invalid_filename(subdirname);
1341 if (strstr(subdirname, "..") || strstr(subdirname, "/")) { 1342 if (strstr(subdirname, "..") || strstr(subdirname, "/")) {
@@ -1356,7 +1357,7 @@ int main(int argc, char **argv) {
1356 struct stat s; 1357 struct stat s;
1357 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { 1358 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1358 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n"); 1359 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1359 exit(1); 1360 exit(1);
1360 } 1361 }
1361 arg_overlay = 1; 1362 arg_overlay = 1;
1362 } 1363 }
@@ -1371,7 +1372,7 @@ int main(int argc, char **argv) {
1371 fprintf(stderr, "Error: --noprofile and --profile options are mutually exclusive\n"); 1372 fprintf(stderr, "Error: --noprofile and --profile options are mutually exclusive\n");
1372 exit(1); 1373 exit(1);
1373 } 1374 }
1374 1375
1375 char *ppath = expand_home(argv[i] + 10, cfg.homedir); 1376 char *ppath = expand_home(argv[i] + 10, cfg.homedir);
1376 if (!ppath) 1377 if (!ppath)
1377 errExit("strdup"); 1378 errExit("strdup");
@@ -1391,7 +1392,7 @@ int main(int argc, char **argv) {
1391 fprintf(stderr, "Error: invalid profile path\n"); 1392 fprintf(stderr, "Error: invalid profile path\n");
1392 exit(1); 1393 exit(1);
1393 } 1394 }
1394 1395
1395 // access call checks as real UID/GID, not as effective UID/GID 1396 // access call checks as real UID/GID, not as effective UID/GID
1396 if (access(custom_profile_dir, R_OK)) { 1397 if (access(custom_profile_dir, R_OK)) {
1397 fprintf(stderr, "Error: cannot access profile directory\n"); 1398 fprintf(stderr, "Error: cannot access profile directory\n");
@@ -1415,11 +1416,11 @@ int main(int argc, char **argv) {
1415 fprintf(stderr, "Error: invalid ignore option\n"); 1416 fprintf(stderr, "Error: invalid ignore option\n");
1416 exit(1); 1417 exit(1);
1417 } 1418 }
1418 1419
1419 // find an empty entry in profile_ignore array 1420 // find an empty entry in profile_ignore array
1420 int j; 1421 int j;
1421 for (j = 0; j < MAX_PROFILE_IGNORE; j++) { 1422 for (j = 0; j < MAX_PROFILE_IGNORE; j++) {
1422 if (cfg.profile_ignore[j] == NULL) 1423 if (cfg.profile_ignore[j] == NULL)
1423 break; 1424 break;
1424 } 1425 }
1425 if (j >= MAX_PROFILE_IGNORE) { 1426 if (j >= MAX_PROFILE_IGNORE) {
@@ -1430,23 +1431,23 @@ int main(int argc, char **argv) {
1430 else 1431 else
1431 cfg.profile_ignore[j] = argv[i] + 9; 1432 cfg.profile_ignore[j] = argv[i] + 9;
1432 } 1433 }
1433#ifdef HAVE_CHROOT 1434#ifdef HAVE_CHROOT
1434 else if (strncmp(argv[i], "--chroot=", 9) == 0) { 1435 else if (strncmp(argv[i], "--chroot=", 9) == 0) {
1435 if (checkcfg(CFG_CHROOT)) { 1436 if (checkcfg(CFG_CHROOT)) {
1436 if (arg_overlay) { 1437 if (arg_overlay) {
1437 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); 1438 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1438 exit(1); 1439 exit(1);
1439 } 1440 }
1440 1441
1441 struct stat s; 1442 struct stat s;
1442 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { 1443 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1443 fprintf(stderr, "Error: --chroot option is not available on Grsecurity systems\n"); 1444 fprintf(stderr, "Error: --chroot option is not available on Grsecurity systems\n");
1444 exit(1); 1445 exit(1);
1445 } 1446 }
1446 1447
1447 1448
1448 invalid_filename(argv[i] + 9); 1449 invalid_filename(argv[i] + 9);
1449 1450
1450 // extract chroot dirname 1451 // extract chroot dirname
1451 cfg.chrootdir = argv[i] + 9; 1452 cfg.chrootdir = argv[i] + 9;
1452 // if the directory starts with ~, expand the home directory 1453 // if the directory starts with ~, expand the home directory
@@ -1456,13 +1457,13 @@ int main(int argc, char **argv) {
1456 errExit("asprintf"); 1457 errExit("asprintf");
1457 cfg.chrootdir = tmp; 1458 cfg.chrootdir = tmp;
1458 } 1459 }
1459 1460
1460 // check chroot dirname exists 1461 // check chroot dirname exists
1461 if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { 1462 if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) {
1462 fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir); 1463 fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir);
1463 return 1; 1464 return 1;
1464 } 1465 }
1465 1466
1466 // don't allow "--chroot=/" 1467 // don't allow "--chroot=/"
1467 char *rpath = realpath(cfg.chrootdir, NULL); 1468 char *rpath = realpath(cfg.chrootdir, NULL);
1468 if (rpath == NULL || strcmp(rpath, "/") == 0) { 1469 if (rpath == NULL || strcmp(rpath, "/") == 0) {
@@ -1470,7 +1471,7 @@ int main(int argc, char **argv) {
1470 exit(1); 1471 exit(1);
1471 } 1472 }
1472 cfg.chrootdir = rpath; 1473 cfg.chrootdir = rpath;
1473 1474
1474 // check chroot directory structure 1475 // check chroot directory structure
1475 fs_check_chroot_dir(cfg.chrootdir); 1476 fs_check_chroot_dir(cfg.chrootdir);
1476 } 1477 }
@@ -1528,7 +1529,7 @@ int main(int argc, char **argv) {
1528 fprintf(stderr, "Error: a private home directory was already defined with --private option.\n"); 1529 fprintf(stderr, "Error: a private home directory was already defined with --private option.\n");
1529 exit(1); 1530 exit(1);
1530 } 1531 }
1531 1532
1532 // extract private home dirname 1533 // extract private home dirname
1533 if (*(argv[i] + 15) == '\0') { 1534 if (*(argv[i] + 15) == '\0') {
1534 fprintf(stderr, "Error: invalid private-home option\n"); 1535 fprintf(stderr, "Error: invalid private-home option\n");
@@ -1544,7 +1545,7 @@ int main(int argc, char **argv) {
1544 else 1545 else
1545 exit_err_feature("private-home"); 1546 exit_err_feature("private-home");
1546 } 1547 }
1547#endif 1548#endif
1548 else if (strcmp(argv[i], "--private-dev") == 0) { 1549 else if (strcmp(argv[i], "--private-dev") == 0) {
1549 arg_private_dev = 1; 1550 arg_private_dev = 1;
1550 } 1551 }
@@ -1553,7 +1554,7 @@ int main(int argc, char **argv) {
1553 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); 1554 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n");
1554 exit(1); 1555 exit(1);
1555 } 1556 }
1556 1557
1557 // extract private etc list 1558 // extract private etc list
1558 if (*(argv[i] + 14) == '\0') { 1559 if (*(argv[i] + 14) == '\0') {
1559 fprintf(stderr, "Error: invalid private-etc option\n"); 1560 fprintf(stderr, "Error: invalid private-etc option\n");
@@ -1646,14 +1647,17 @@ int main(int argc, char **argv) {
1646 else if (strcmp(argv[i], "--nosound") == 0) { 1647 else if (strcmp(argv[i], "--nosound") == 0) {
1647 arg_nosound = 1; 1648 arg_nosound = 1;
1648 } 1649 }
1650 else if (strcmp(argv[i], "--novideo") == 0) {
1651 arg_novideo = 1;
1652 }
1649 else if (strcmp(argv[i], "--no3d") == 0) { 1653 else if (strcmp(argv[i], "--no3d") == 0) {
1650 arg_no3d = 1; 1654 arg_no3d = 1;
1651 } 1655 }
1652 1656
1653 //************************************* 1657 //*************************************
1654 // network 1658 // network
1655 //************************************* 1659 //*************************************
1656#ifdef HAVE_NETWORK 1660#ifdef HAVE_NETWORK
1657 else if (strncmp(argv[i], "--interface=", 12) == 0) { 1661 else if (strncmp(argv[i], "--interface=", 12) == 0) {
1658 if (checkcfg(CFG_NETWORK)) { 1662 if (checkcfg(CFG_NETWORK)) {
1659#ifdef HAVE_NETWORK_RESTRICTED 1663#ifdef HAVE_NETWORK_RESTRICTED
@@ -1668,7 +1672,7 @@ int main(int argc, char **argv) {
1668 fprintf(stderr, "Error: --interface is allowed only to root user\n"); 1672 fprintf(stderr, "Error: --interface is allowed only to root user\n");
1669 exit(1); 1673 exit(1);
1670 } 1674 }
1671 1675
1672 // checks 1676 // checks
1673 if (arg_nonetwork) { 1677 if (arg_nonetwork) {
1674 fprintf(stderr, "Error: --network=none and --interface are incompatible\n"); 1678 fprintf(stderr, "Error: --network=none and --interface are incompatible\n");
@@ -1683,7 +1687,7 @@ int main(int argc, char **argv) {
1683 fprintf(stderr, "Error: cannot find interface %s\n", argv[i] + 12); 1687 fprintf(stderr, "Error: cannot find interface %s\n", argv[i] + 12);
1684 exit(1); 1688 exit(1);
1685 } 1689 }
1686 1690
1687 Interface *intf; 1691 Interface *intf;
1688 if (cfg.interface0.configured == 0) 1692 if (cfg.interface0.configured == 0)
1689 intf = &cfg.interface0; 1693 intf = &cfg.interface0;
@@ -1697,11 +1701,11 @@ int main(int argc, char **argv) {
1697 fprintf(stderr, "Error: maximum 4 interfaces are allowed\n"); 1701 fprintf(stderr, "Error: maximum 4 interfaces are allowed\n");
1698 return 1; 1702 return 1;
1699 } 1703 }
1700 1704
1701 intf->dev = strdup(argv[i] + 12); 1705 intf->dev = strdup(argv[i] + 12);
1702 if (!intf->dev) 1706 if (!intf->dev)
1703 errExit("strdup"); 1707 errExit("strdup");
1704 1708
1705 if (net_get_if_addr(intf->dev, &intf->ip, &intf->mask, intf->mac, &intf->mtu)) { 1709 if (net_get_if_addr(intf->dev, &intf->ip, &intf->mask, intf->mac, &intf->mtu)) {
1706 fwarning("interface %s is not configured\n", intf->dev); 1710 fwarning("interface %s is not configured\n", intf->dev);
1707 } 1711 }
@@ -1742,7 +1746,7 @@ int main(int argc, char **argv) {
1742 fprintf(stderr, "Error: cannot attach to lo device\n"); 1746 fprintf(stderr, "Error: cannot attach to lo device\n");
1743 exit(1); 1747 exit(1);
1744 } 1748 }
1745 1749
1746 Bridge *br; 1750 Bridge *br;
1747 if (cfg.bridge0.configured == 0) 1751 if (cfg.bridge0.configured == 0)
1748 br = &cfg.bridge0; 1752 br = &cfg.bridge0;
@@ -1799,7 +1803,7 @@ int main(int argc, char **argv) {
1799 fprintf(stderr, "Error: cannot configure the IP range twice for the same interface\n"); 1803 fprintf(stderr, "Error: cannot configure the IP range twice for the same interface\n");
1800 return 1; 1804 return 1;
1801 } 1805 }
1802 1806
1803 // parse option arguments 1807 // parse option arguments
1804 char *firstip = argv[i] + 10; 1808 char *firstip = argv[i] + 10;
1805 char *secondip = firstip; 1809 char *secondip = firstip;
@@ -1814,7 +1818,7 @@ int main(int argc, char **argv) {
1814 } 1818 }
1815 *secondip = '\0'; 1819 *secondip = '\0';
1816 secondip++; 1820 secondip++;
1817 1821
1818 // check addresses 1822 // check addresses
1819 if (atoip(firstip, &br->iprange_start) || atoip(secondip, &br->iprange_end) || 1823 if (atoip(firstip, &br->iprange_start) || atoip(secondip, &br->iprange_end) ||
1820 br->iprange_start >= br->iprange_end) { 1824 br->iprange_start >= br->iprange_end) {
@@ -1841,7 +1845,7 @@ int main(int argc, char **argv) {
1841 fprintf(stderr, "Error: cannot configure the MAC address twice for the same interface\n"); 1845 fprintf(stderr, "Error: cannot configure the MAC address twice for the same interface\n");
1842 exit(1); 1846 exit(1);
1843 } 1847 }
1844 1848
1845 // read the address 1849 // read the address
1846 if (atomac(argv[i] + 6, br->macsandbox)) { 1850 if (atomac(argv[i] + 6, br->macsandbox)) {
1847 fprintf(stderr, "Error: invalid MAC address\n"); 1851 fprintf(stderr, "Error: invalid MAC address\n");
@@ -1859,7 +1863,7 @@ int main(int argc, char **argv) {
1859 fprintf(stderr, "Error: no network device configured\n"); 1863 fprintf(stderr, "Error: no network device configured\n");
1860 exit(1); 1864 exit(1);
1861 } 1865 }
1862 1866
1863 if (sscanf(argv[i] + 6, "%d", &br->mtu) != 1 || br->mtu < 576 || br->mtu > 9198) { 1867 if (sscanf(argv[i] + 6, "%d", &br->mtu) != 1 || br->mtu < 576 || br->mtu > 9198) {
1864 fprintf(stderr, "Error: invalid mtu value\n"); 1868 fprintf(stderr, "Error: invalid mtu value\n");
1865 exit(1); 1869 exit(1);
@@ -1880,7 +1884,7 @@ int main(int argc, char **argv) {
1880 fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); 1884 fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n");
1881 exit(1); 1885 exit(1);
1882 } 1886 }
1883 1887
1884 // configure this IP address for the last bridge defined 1888 // configure this IP address for the last bridge defined
1885 if (strcmp(argv[i] + 5, "none") == 0) 1889 if (strcmp(argv[i] + 5, "none") == 0)
1886 br->arg_ip_none = 1; 1890 br->arg_ip_none = 1;
@@ -1906,7 +1910,7 @@ int main(int argc, char **argv) {
1906 fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); 1910 fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n");
1907 exit(1); 1911 exit(1);
1908 } 1912 }
1909 1913
1910 // configure this IP address for the last bridge defined 1914 // configure this IP address for the last bridge defined
1911 // todo: verify ipv6 syntax 1915 // todo: verify ipv6 syntax
1912 br->ip6sandbox = argv[i] + 6; 1916 br->ip6sandbox = argv[i] + 6;
@@ -1915,7 +1919,7 @@ int main(int argc, char **argv) {
1915// exit(1); 1919// exit(1);
1916// } 1920// }
1917 } 1921 }
1918 else 1922 else
1919 exit_err_feature("networking"); 1923 exit_err_feature("networking");
1920 } 1924 }
1921 1925
@@ -1930,14 +1934,14 @@ int main(int argc, char **argv) {
1930 else 1934 else
1931 exit_err_feature("networking"); 1935 exit_err_feature("networking");
1932 } 1936 }
1933#endif 1937#endif
1934 else if (strncmp(argv[i], "--dns=", 6) == 0) { 1938 else if (strncmp(argv[i], "--dns=", 6) == 0) {
1935 uint32_t dns; 1939 uint32_t dns;
1936 if (atoip(argv[i] + 6, &dns)) { 1940 if (atoip(argv[i] + 6, &dns)) {
1937 fprintf(stderr, "Error: invalid DNS server IP address\n"); 1941 fprintf(stderr, "Error: invalid DNS server IP address\n");
1938 return 1; 1942 return 1;
1939 } 1943 }
1940 1944
1941 if (cfg.dns1 == 0) 1945 if (cfg.dns1 == 0)
1942 cfg.dns1 = dns; 1946 cfg.dns1 = dns;
1943 else if (cfg.dns2 == 0) 1947 else if (cfg.dns2 == 0)
@@ -1949,7 +1953,7 @@ int main(int argc, char **argv) {
1949 return 1; 1953 return 1;
1950 } 1954 }
1951 } 1955 }
1952 1956
1953 else if (strncmp(argv[i], "--hosts-file=", 13) == 0) 1957 else if (strncmp(argv[i], "--hosts-file=", 13) == 0)
1954 cfg.hosts_file = fs_check_hosts_file(argv[i] + 13); 1958 cfg.hosts_file = fs_check_hosts_file(argv[i] + 13);
1955 1959
@@ -2042,7 +2046,7 @@ int main(int argc, char **argv) {
2042 arg_appimage = 1; 2046 arg_appimage = 1;
2043 else if (strcmp(argv[i], "--csh") == 0) { 2047 else if (strcmp(argv[i], "--csh") == 0) {
2044 if (arg_shell_none) { 2048 if (arg_shell_none) {
2045 2049
2046 fprintf(stderr, "Error: --shell=none was already specified.\n"); 2050 fprintf(stderr, "Error: --shell=none was already specified.\n");
2047 return 1; 2051 return 1;
2048 } 2052 }
@@ -2076,7 +2080,7 @@ int main(int argc, char **argv) {
2076 return 1; 2080 return 1;
2077 } 2081 }
2078 invalid_filename(argv[i] + 8); 2082 invalid_filename(argv[i] + 8);
2079 2083
2080 if (cfg.shell) { 2084 if (cfg.shell) {
2081 fprintf(stderr, "Error: only one user shell can be specified\n"); 2085 fprintf(stderr, "Error: only one user shell can be specified\n");
2082 return 1; 2086 return 1;
@@ -2110,7 +2114,7 @@ int main(int argc, char **argv) {
2110 return 1; 2114 return 1;
2111 } 2115 }
2112 } 2116 }
2113 2117
2114 // unlike all other x11 features, this is available always 2118 // unlike all other x11 features, this is available always
2115 else if (strcmp(argv[i], "--x11=none") == 0) { 2119 else if (strcmp(argv[i], "--x11=none") == 0) {
2116 arg_x11_block = 1; 2120 arg_x11_block = 1;
@@ -2119,7 +2123,7 @@ int main(int argc, char **argv) {
2119 else if (strcmp(argv[i], "--x11=xorg") == 0) { 2123 else if (strcmp(argv[i], "--x11=xorg") == 0) {
2120 if (checkcfg(CFG_X11)) 2124 if (checkcfg(CFG_X11))
2121 arg_x11_xorg = 1; 2125 arg_x11_xorg = 1;
2122 else 2126 else
2123 exit_err_feature("x11"); 2127 exit_err_feature("x11");
2124 } 2128 }
2125#endif 2129#endif
@@ -2139,7 +2143,7 @@ int main(int argc, char **argv) {
2139 fprintf(stderr, "This feature is not enabled in the current build\n"); 2143 fprintf(stderr, "This feature is not enabled in the current build\n");
2140 exit(1); 2144 exit(1);
2141 } 2145 }
2142 2146
2143 else if (strcmp(argv[i], "--") == 0) { 2147 else if (strcmp(argv[i], "--") == 0) {
2144 // double dash - positional params to follow 2148 // double dash - positional params to follow
2145 arg_doubledash = 1; 2149 arg_doubledash = 1;
@@ -2158,7 +2162,7 @@ int main(int argc, char **argv) {
2158 fprintf(stderr, "Error: invalid %s command line option\n", argv[i]); 2162 fprintf(stderr, "Error: invalid %s command line option\n", argv[i]);
2159 return 1; 2163 return 1;
2160 } 2164 }
2161 2165
2162 // we have a program name coming 2166 // we have a program name coming
2163 if (arg_appimage) { 2167 if (arg_appimage) {
2164 cfg.command_name = strdup(argv[i]); 2168 cfg.command_name = strdup(argv[i]);
@@ -2171,7 +2175,7 @@ int main(int argc, char **argv) {
2171 break; 2175 break;
2172 } 2176 }
2173 } 2177 }
2174 2178
2175 // prog_index could still be -1 if no program was specified 2179 // prog_index could still be -1 if no program was specified
2176 if (prog_index == -1 && arg_shell_none) { 2180 if (prog_index == -1 && arg_shell_none) {
2177 fprintf(stderr, "Error: shell=none configured, but no program specified\n"); 2181 fprintf(stderr, "Error: shell=none configured, but no program specified\n");
@@ -2182,7 +2186,7 @@ int main(int argc, char **argv) {
2182 if (arg_trace && arg_tracelog) { 2186 if (arg_trace && arg_tracelog) {
2183 fwarning("--trace and --tracelog are mutually exclusive; --tracelog disabled\n"); 2187 fwarning("--trace and --tracelog are mutually exclusive; --tracelog disabled\n");
2184 } 2188 }
2185 2189
2186 // check user namespace (--noroot) options 2190 // check user namespace (--noroot) options
2187 if (arg_noroot) { 2191 if (arg_noroot) {
2188 if (arg_overlay) { 2192 if (arg_overlay) {
@@ -2235,12 +2239,12 @@ int main(int argc, char **argv) {
2235 fprintf(stderr, "Error: command must be specified when --shell=none used.\n"); 2239 fprintf(stderr, "Error: command must be specified when --shell=none used.\n");
2236 exit(1); 2240 exit(1);
2237 }*/ 2241 }*/
2238 2242
2239 assert(cfg.command_name); 2243 assert(cfg.command_name);
2240 if (arg_debug) 2244 if (arg_debug)
2241 printf("Command name #%s#\n", cfg.command_name); 2245 printf("Command name #%s#\n", cfg.command_name);
2242 2246
2243 2247
2244 // load the profile 2248 // load the profile
2245 if (!arg_noprofile) { 2249 if (!arg_noprofile) {
2246 if (!custom_profile) { 2250 if (!custom_profile) {
@@ -2278,14 +2282,14 @@ int main(int argc, char **argv) {
2278 profile_name = DEFAULT_ROOT_PROFILE; 2282 profile_name = DEFAULT_ROOT_PROFILE;
2279 if (arg_debug) 2283 if (arg_debug)
2280 printf("Attempting to find %s.profile...\n", profile_name); 2284 printf("Attempting to find %s.profile...\n", profile_name);
2281 2285
2282 // look for the profile in ~/.config/firejail directory 2286 // look for the profile in ~/.config/firejail directory
2283 char *usercfgdir; 2287 char *usercfgdir;
2284 if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) 2288 if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1)
2285 errExit("asprintf"); 2289 errExit("asprintf");
2286 custom_profile = profile_find(profile_name, usercfgdir); 2290 custom_profile = profile_find(profile_name, usercfgdir);
2287 free(usercfgdir); 2291 free(usercfgdir);
2288 2292
2289 if (!custom_profile) { 2293 if (!custom_profile) {
2290 // look for the profile in /etc/firejail directory 2294 // look for the profile in /etc/firejail directory
2291 if (custom_profile_dir) 2295 if (custom_profile_dir)
@@ -2297,7 +2301,7 @@ int main(int argc, char **argv) {
2297 fprintf(stderr, "Error: no default.profile installed\n"); 2301 fprintf(stderr, "Error: no default.profile installed\n");
2298 exit(1); 2302 exit(1);
2299 } 2303 }
2300 2304
2301 if (custom_profile && !arg_quiet) 2305 if (custom_profile && !arg_quiet)
2302 printf("\n** Note: you can use --noprofile to disable %s.profile **\n\n", profile_name); 2306 printf("\n** Note: you can use --noprofile to disable %s.profile **\n\n", profile_name);
2303 } 2307 }
@@ -2309,7 +2313,7 @@ int main(int argc, char **argv) {
2309 2313
2310 // check network configuration options - it will exit if anything went wrong 2314 // check network configuration options - it will exit if anything went wrong
2311 net_check_cfg(); 2315 net_check_cfg();
2312 2316
2313 // check and assign an IP address - for macvlan it will be done again in the sandbox! 2317 // check and assign an IP address - for macvlan it will be done again in the sandbox!
2314 if (any_bridge_configured()) { 2318 if (any_bridge_configured()) {
2315 EUID_ROOT(); 2319 EUID_ROOT();
@@ -2319,12 +2323,12 @@ int main(int argc, char **argv) {
2319 (void) rv; 2323 (void) rv;
2320 flock(lockfd, LOCK_EX); 2324 flock(lockfd, LOCK_EX);
2321 } 2325 }
2322 2326
2323 check_network(&cfg.bridge0); 2327 check_network(&cfg.bridge0);
2324 check_network(&cfg.bridge1); 2328 check_network(&cfg.bridge1);
2325 check_network(&cfg.bridge2); 2329 check_network(&cfg.bridge2);
2326 check_network(&cfg.bridge3); 2330 check_network(&cfg.bridge3);
2327 2331
2328 // save network mapping in shared memory 2332 // save network mapping in shared memory
2329 network_set_run_file(sandbox_pid); 2333 network_set_run_file(sandbox_pid);
2330 EUID_USER(); 2334 EUID_USER();
@@ -2354,10 +2358,10 @@ int main(int argc, char **argv) {
2354 if (display > 0) 2358 if (display > 0)
2355 set_x11_file(sandbox_pid, display); 2359 set_x11_file(sandbox_pid, display);
2356 EUID_USER(); 2360 EUID_USER();
2357 2361
2358 // clone environment 2362 // clone environment
2359 int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD; 2363 int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD;
2360 2364
2361 // in root mode also enable CLONE_NEWIPC 2365 // in root mode also enable CLONE_NEWIPC
2362 // in user mode CLONE_NEWIPC will break MIT Shared Memory Extension (MIT-SHM) 2366 // in user mode CLONE_NEWIPC will break MIT Shared Memory Extension (MIT-SHM)
2363 if (getuid() == 0 || arg_ipc) { 2367 if (getuid() == 0 || arg_ipc) {
@@ -2365,7 +2369,7 @@ int main(int argc, char **argv) {
2365 if (arg_debug) 2369 if (arg_debug)
2366 printf("Enabling IPC namespace\n"); 2370 printf("Enabling IPC namespace\n");
2367 } 2371 }
2368 2372
2369 if (any_bridge_configured() || any_interface_configured() || arg_nonetwork) { 2373 if (any_bridge_configured() || any_interface_configured() || arg_nonetwork) {
2370 flags |= CLONE_NEWNET; 2374 flags |= CLONE_NEWNET;
2371 } 2375 }
@@ -2387,9 +2391,9 @@ int main(int argc, char **argv) {
2387 if (getuid() == 0) // only for root 2391 if (getuid() == 0) // only for root
2388 printf("The new log directory is /proc/%d/root/var/log\n", child); 2392 printf("The new log directory is /proc/%d/root/var/log\n", child);
2389 } 2393 }
2390 2394
2391 if (!arg_nonetwork) { 2395 if (!arg_nonetwork) {
2392 EUID_ROOT(); 2396 EUID_ROOT();
2393 pid_t net_child = fork(); 2397 pid_t net_child = fork();
2394 if (net_child < 0) 2398 if (net_child < 0)
2395 errExit("fork"); 2399 errExit("fork");
@@ -2401,11 +2405,11 @@ int main(int argc, char **argv) {
2401 errExit("setregid"); 2405 errExit("setregid");
2402 network_main(child); 2406 network_main(child);
2403 if (arg_debug) 2407 if (arg_debug)
2404 printf("Host network configured\n"); 2408 printf("Host network configured\n");
2405#ifdef HAVE_GCOV 2409#ifdef HAVE_GCOV
2406 __gcov_flush(); 2410 __gcov_flush();
2407#endif 2411#endif
2408 _exit(0); 2412 _exit(0);
2409 } 2413 }
2410 2414
2411 // wait for the child to finish 2415 // wait for the child to finish
@@ -2416,10 +2420,10 @@ int main(int argc, char **argv) {
2416 // close each end of the unused pipes 2420 // close each end of the unused pipes
2417 close(parent_to_child_fds[0]); 2421 close(parent_to_child_fds[0]);
2418 close(child_to_parent_fds[1]); 2422 close(child_to_parent_fds[1]);
2419 2423
2420 // notify child that base setup is complete 2424 // notify child that base setup is complete
2421 notify_other(parent_to_child_fds[1]); 2425 notify_other(parent_to_child_fds[1]);
2422 2426
2423 // wait for child to create new user namespace with CLONE_NEWUSER 2427 // wait for child to create new user namespace with CLONE_NEWUSER
2424 wait_for_other(child_to_parent_fds[0]); 2428 wait_for_other(child_to_parent_fds[0]);
2425 close(child_to_parent_fds[0]); 2429 close(child_to_parent_fds[0]);
@@ -2440,7 +2444,7 @@ int main(int argc, char **argv) {
2440 EUID_USER(); 2444 EUID_USER();
2441 free(map); 2445 free(map);
2442 free(map_path); 2446 free(map_path);
2443 2447
2444 // gid file 2448 // gid file
2445 if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1) 2449 if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1)
2446 errExit("asprintf"); 2450 errExit("asprintf");
@@ -2452,7 +2456,7 @@ int main(int argc, char **argv) {
2452 gid_t gid = getgid(); 2456 gid_t gid = getgid();
2453 sprintf(ptr, "%d %d 1\n", gid, gid); 2457 sprintf(ptr, "%d %d 1\n", gid, gid);
2454 ptr += strlen(ptr); 2458 ptr += strlen(ptr);
2455 2459
2456 if (!arg_nogroups) { 2460 if (!arg_nogroups) {
2457 // add tty group 2461 // add tty group
2458 gid_t g = get_group_id("tty"); 2462 gid_t g = get_group_id("tty");
@@ -2460,38 +2464,38 @@ int main(int argc, char **argv) {
2460 sprintf(ptr, "%d %d 1\n", g, g); 2464 sprintf(ptr, "%d %d 1\n", g, g);
2461 ptr += strlen(ptr); 2465 ptr += strlen(ptr);
2462 } 2466 }
2463 2467
2464 // add audio group 2468 // add audio group
2465 g = get_group_id("audio"); 2469 g = get_group_id("audio");
2466 if (g) { 2470 if (g) {
2467 sprintf(ptr, "%d %d 1\n", g, g); 2471 sprintf(ptr, "%d %d 1\n", g, g);
2468 ptr += strlen(ptr); 2472 ptr += strlen(ptr);
2469 } 2473 }
2470 2474
2471 // add video group 2475 // add video group
2472 g = get_group_id("video"); 2476 g = get_group_id("video");
2473 if (g) { 2477 if (g) {
2474 sprintf(ptr, "%d %d 1\n", g, g); 2478 sprintf(ptr, "%d %d 1\n", g, g);
2475 ptr += strlen(ptr); 2479 ptr += strlen(ptr);
2476 } 2480 }
2477 2481
2478 // add games group 2482 // add games group
2479 g = get_group_id("games"); 2483 g = get_group_id("games");
2480 if (g) { 2484 if (g) {
2481 sprintf(ptr, "%d %d 1\n", g, g); 2485 sprintf(ptr, "%d %d 1\n", g, g);
2482 } 2486 }
2483 } 2487 }
2484 2488
2485 EUID_ROOT(); 2489 EUID_ROOT();
2486 update_map(gidmap, map_path); 2490 update_map(gidmap, map_path);
2487 EUID_USER(); 2491 EUID_USER();
2488 free(map_path); 2492 free(map_path);
2489 } 2493 }
2490 2494
2491 // notify child that UID/GID mapping is complete 2495 // notify child that UID/GID mapping is complete
2492 notify_other(parent_to_child_fds[1]); 2496 notify_other(parent_to_child_fds[1]);
2493 close(parent_to_child_fds[1]); 2497 close(parent_to_child_fds[1]);
2494 2498
2495 EUID_ROOT(); 2499 EUID_ROOT();
2496 if (lockfd != -1) { 2500 if (lockfd != -1) {
2497 flock(lockfd, LOCK_UN); 2501 flock(lockfd, LOCK_UN);
@@ -2499,13 +2503,13 @@ int main(int argc, char **argv) {
2499 } 2503 }
2500 2504
2501 // create name file under /run/firejail 2505 // create name file under /run/firejail
2502 2506
2503 2507
2504 // handle CTRL-C in parent 2508 // handle CTRL-C in parent
2505 signal (SIGINT, my_handler); 2509 signal (SIGINT, my_handler);
2506 signal (SIGTERM, my_handler); 2510 signal (SIGTERM, my_handler);
2507 2511
2508 2512
2509 // wait for the child to finish 2513 // wait for the child to finish
2510 EUID_USER(); 2514 EUID_USER();
2511 int status = 0; 2515 int status = 0;
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 9ae2aa5b4..11258892e 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -28,8 +28,8 @@ int profile_find(const char *name, const char *dir) {
28 EUID_ASSERT(); 28 EUID_ASSERT();
29 assert(name); 29 assert(name);
30 assert(dir); 30 assert(dir);
31 31
32 int rv = 0; 32 int rv = 0;
33 DIR *dp; 33 DIR *dp;
34 char *pname; 34 char *pname;
35 if (asprintf(&pname, "%s.profile", name) == -1) 35 if (asprintf(&pname, "%s.profile", name) == -1)
@@ -74,17 +74,17 @@ static void warning_feature_disabled(const char *feature) {
74// return 0 if the command was already executed inside the function 74// return 0 if the command was already executed inside the function
75int profile_check_line(char *ptr, int lineno, const char *fname) { 75int profile_check_line(char *ptr, int lineno, const char *fname) {
76 EUID_ASSERT(); 76 EUID_ASSERT();
77 77
78 // check ignore list 78 // check ignore list
79 int i; 79 int i;
80 for (i = 0; i < MAX_PROFILE_IGNORE; i++) { 80 for (i = 0; i < MAX_PROFILE_IGNORE; i++) {
81 if (cfg.profile_ignore[i] == NULL) 81 if (cfg.profile_ignore[i] == NULL)
82 break; 82 break;
83 83
84 if (strncmp(ptr, cfg.profile_ignore[i], strlen(cfg.profile_ignore[i])) == 0) 84 if (strncmp(ptr, cfg.profile_ignore[i], strlen(cfg.profile_ignore[i])) == 0)
85 return 0; // ignore line 85 return 0; // ignore line
86 } 86 }
87 87
88 if (strncmp(ptr, "ignore ", 7) == 0) { 88 if (strncmp(ptr, "ignore ", 7) == 0) {
89 char *str = strdup(ptr + 7); 89 char *str = strdup(ptr + 7);
90 if (*str == '\0') { 90 if (*str == '\0') {
@@ -94,7 +94,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
94 // find an empty entry in profile_ignore array 94 // find an empty entry in profile_ignore array
95 int j; 95 int j;
96 for (j = 0; j < MAX_PROFILE_IGNORE; j++) { 96 for (j = 0; j < MAX_PROFILE_IGNORE; j++) {
97 if (cfg.profile_ignore[j] == NULL) 97 if (cfg.profile_ignore[j] == NULL)
98 break; 98 break;
99 } 99 }
100 if (j >= MAX_PROFILE_IGNORE) { 100 if (j >= MAX_PROFILE_IGNORE) {
@@ -102,18 +102,18 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
102 exit(1); 102 exit(1);
103 } 103 }
104 // ... and configure it 104 // ... and configure it
105 else 105 else
106 cfg.profile_ignore[j] = str; 106 cfg.profile_ignore[j] = str;
107 107
108 return 0; 108 return 0;
109 } 109 }
110 110
111 // mkdir 111 // mkdir
112 if (strncmp(ptr, "mkdir ", 6) == 0) { 112 if (strncmp(ptr, "mkdir ", 6) == 0) {
113 fs_mkdir(ptr + 6); 113 fs_mkdir(ptr + 6);
114 return 1; // process mkdir again while applying blacklists 114 return 1; // process mkdir again while applying blacklists
115 } 115 }
116 // mkfile 116 // mkfile
117 if (strncmp(ptr, "mkfile ", 7) == 0) { 117 if (strncmp(ptr, "mkfile ", 7) == 0) {
118 fs_mkfile(ptr + 7); 118 fs_mkfile(ptr + 7);
119 return 1; // process mkfile again while applying blacklists 119 return 1; // process mkfile again while applying blacklists
@@ -166,7 +166,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
166 else if (strcmp(ptr, "shell none") == 0) { 166 else if (strcmp(ptr, "shell none") == 0) {
167 arg_shell_none = 1; 167 arg_shell_none = 1;
168 return 0; 168 return 0;
169 } 169 }
170 else if (strcmp(ptr, "tracelog") == 0) { 170 else if (strcmp(ptr, "tracelog") == 0) {
171 arg_tracelog = 1; 171 arg_tracelog = 1;
172 return 0; 172 return 0;
@@ -210,6 +210,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
210 arg_nosound = 1; 210 arg_nosound = 1;
211 return 0; 211 return 0;
212 } 212 }
213 else if (strcmp(ptr, "novideo") == 0) {
214 arg_novideo = 1;
215 return 0;
216 }
213 else if (strcmp(ptr, "no3d") == 0) { 217 else if (strcmp(ptr, "no3d") == 0) {
214 arg_no3d = 1; 218 arg_no3d = 1;
215 return 0; 219 return 0;
@@ -217,7 +221,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
217 else if (strcmp(ptr, "allow-private-blacklist") == 0) { 221 else if (strcmp(ptr, "allow-private-blacklist") == 0) {
218 arg_allow_private_blacklist = 1; 222 arg_allow_private_blacklist = 1;
219 return 0; 223 return 0;
220 } 224 }
221 else if (strcmp(ptr, "netfilter") == 0) { 225 else if (strcmp(ptr, "netfilter") == 0) {
222#ifdef HAVE_NETWORK 226#ifdef HAVE_NETWORK
223 if (checkcfg(CFG_NETWORK)) 227 if (checkcfg(CFG_NETWORK))
@@ -288,7 +292,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
288 fprintf(stderr, "Error: only \"net none\" is allowed to non-root users\n"); 292 fprintf(stderr, "Error: only \"net none\" is allowed to non-root users\n");
289 exit(1); 293 exit(1);
290 } 294 }
291 295
292 if (strcmp(ptr + 4, "lo") == 0) { 296 if (strcmp(ptr + 4, "lo") == 0) {
293 fprintf(stderr, "Error: cannot attach to lo device\n"); 297 fprintf(stderr, "Error: cannot attach to lo device\n");
294 exit(1); 298 exit(1);
@@ -314,7 +318,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
314#endif 318#endif
315 return 0; 319 return 0;
316 } 320 }
317 321
318 else if (strncmp(ptr, "veth-name ", 10) == 0) { 322 else if (strncmp(ptr, "veth-name ", 10) == 0) {
319#ifdef HAVE_NETWORK 323#ifdef HAVE_NETWORK
320 if (checkcfg(CFG_NETWORK)) { 324 if (checkcfg(CFG_NETWORK)) {
@@ -365,7 +369,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
365 } 369 }
366 *secondip = '\0'; 370 *secondip = '\0';
367 secondip++; 371 secondip++;
368 372
369 // check addresses 373 // check addresses
370 if (atoip(firstip, &br->iprange_start) || atoip(secondip, &br->iprange_end) || 374 if (atoip(firstip, &br->iprange_start) || atoip(secondip, &br->iprange_end) ||
371 br->iprange_start >= br->iprange_end) { 375 br->iprange_start >= br->iprange_end) {
@@ -392,7 +396,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
392 fprintf(stderr, "Error: no network device configured\n"); 396 fprintf(stderr, "Error: no network device configured\n");
393 exit(1); 397 exit(1);
394 } 398 }
395 399
396 if (mac_not_zero(br->macsandbox)) { 400 if (mac_not_zero(br->macsandbox)) {
397 fprintf(stderr, "Error: cannot configure the MAC address twice for the same interface\n"); 401 fprintf(stderr, "Error: cannot configure the MAC address twice for the same interface\n");
398 exit(1); 402 exit(1);
@@ -418,7 +422,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
418 fprintf(stderr, "Error: no network device configured\n"); 422 fprintf(stderr, "Error: no network device configured\n");
419 exit(1); 423 exit(1);
420 } 424 }
421 425
422 if (sscanf(ptr + 4, "%d", &br->mtu) != 1 || br->mtu < 576 || br->mtu > 9198) { 426 if (sscanf(ptr + 4, "%d", &br->mtu) != 1 || br->mtu < 576 || br->mtu > 9198) {
423 fprintf(stderr, "Error: invalid mtu value\n"); 427 fprintf(stderr, "Error: invalid mtu value\n");
424 exit(1); 428 exit(1);
@@ -479,7 +483,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
479// fprintf(stderr, "Error: invalid IP address\n"); 483// fprintf(stderr, "Error: invalid IP address\n");
480// exit(1); 484// exit(1);
481// } 485// }
482 486
483 } 487 }
484 else 488 else
485 warning_feature_disabled("networking"); 489 warning_feature_disabled("networking");
@@ -502,7 +506,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
502 } 506 }
503 507
504 if (strcmp(ptr, "apparmor") == 0) { 508 if (strcmp(ptr, "apparmor") == 0) {
505#ifdef HAVE_APPARMOR 509#ifdef HAVE_APPARMOR
506 arg_apparmor = 1; 510 arg_apparmor = 1;
507#endif 511#endif
508 return 0; 512 return 0;
@@ -515,7 +519,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
515 fwarning("a protocol list is present, the new list \"%s\" will not be installed\n", ptr + 9); 519 fwarning("a protocol list is present, the new list \"%s\" will not be installed\n", ptr + 9);
516 return 0; 520 return 0;
517 } 521 }
518 522
519 // store list 523 // store list
520 cfg.protocol = strdup(ptr + 9); 524 cfg.protocol = strdup(ptr + 9);
521 if (!cfg.protocol) 525 if (!cfg.protocol)
@@ -526,7 +530,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
526#endif 530#endif
527 return 0; 531 return 0;
528 } 532 }
529 533
530 if (strncmp(ptr, "env ", 4) == 0) { 534 if (strncmp(ptr, "env ", 4) == 0) {
531 env_store(ptr + 4, SETENV); 535 env_store(ptr + 4, SETENV);
532 return 0; 536 return 0;
@@ -535,7 +539,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
535 env_store(ptr + 6, RMENV); 539 env_store(ptr + 6, RMENV);
536 return 0; 540 return 0;
537 } 541 }
538 542
539 // seccomp drop list on top of default list 543 // seccomp drop list on top of default list
540 if (strncmp(ptr, "seccomp ", 8) == 0) { 544 if (strncmp(ptr, "seccomp ", 8) == 0) {
541#ifdef HAVE_SECCOMP 545#ifdef HAVE_SECCOMP
@@ -549,7 +553,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
549 553
550 return 0; 554 return 0;
551 } 555 }
552 556
553 // seccomp drop list without default list 557 // seccomp drop list without default list
554 if (strncmp(ptr, "seccomp.drop ", 13) == 0) { 558 if (strncmp(ptr, "seccomp.drop ", 13) == 0) {
555#ifdef HAVE_SECCOMP 559#ifdef HAVE_SECCOMP
@@ -559,7 +563,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
559 } 563 }
560 else 564 else
561 warning_feature_disabled("seccomp"); 565 warning_feature_disabled("seccomp");
562#endif 566#endif
563 return 0; 567 return 0;
564 } 568 }
565 569
@@ -572,10 +576,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
572 } 576 }
573 else 577 else
574 warning_feature_disabled("seccomp"); 578 warning_feature_disabled("seccomp");
575#endif 579#endif
576 return 0; 580 return 0;
577 } 581 }
578 582
579 // caps drop list 583 // caps drop list
580 if (strncmp(ptr, "caps.drop ", 10) == 0) { 584 if (strncmp(ptr, "caps.drop ", 10) == 0) {
581 arg_caps_drop = 1; 585 arg_caps_drop = 1;
@@ -586,7 +590,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
586 caps_check_list(arg_caps_list, NULL); 590 caps_check_list(arg_caps_list, NULL);
587 return 0; 591 return 0;
588 } 592 }
589 593
590 // caps keep list 594 // caps keep list
591 if (strncmp(ptr, "caps.keep ", 10) == 0) { 595 if (strncmp(ptr, "caps.keep ", 10) == 0) {
592 arg_caps_keep = 1; 596 arg_caps_keep = 1;
@@ -603,13 +607,13 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
603 cfg.hostname = ptr + 9; 607 cfg.hostname = ptr + 9;
604 return 0; 608 return 0;
605 } 609 }
606 610
607 // hosts-file 611 // hosts-file
608 if (strncmp(ptr, "hosts-file ", 11) == 0) { 612 if (strncmp(ptr, "hosts-file ", 11) == 0) {
609 cfg.hosts_file = fs_check_hosts_file(ptr + 11); 613 cfg.hosts_file = fs_check_hosts_file(ptr + 11);
610 return 0; 614 return 0;
611 } 615 }
612 616
613 // dns 617 // dns
614 if (strncmp(ptr, "dns ", 4) == 0) { 618 if (strncmp(ptr, "dns ", 4) == 0) {
615 uint32_t dns; 619 uint32_t dns;
@@ -617,7 +621,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
617 fprintf(stderr, "Error: invalid DNS server IP address\n"); 621 fprintf(stderr, "Error: invalid DNS server IP address\n");
618 return 1; 622 return 1;
619 } 623 }
620 624
621 if (cfg.dns1 == 0) 625 if (cfg.dns1 == 0)
622 cfg.dns1 = dns; 626 cfg.dns1 = dns;
623 else if (cfg.dns2 == 0) 627 else if (cfg.dns2 == 0)
@@ -630,13 +634,13 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
630 } 634 }
631 return 0; 635 return 0;
632 } 636 }
633 637
634 // cpu affinity 638 // cpu affinity
635 if (strncmp(ptr, "cpu ", 4) == 0) { 639 if (strncmp(ptr, "cpu ", 4) == 0) {
636 read_cpu_list(ptr + 4); 640 read_cpu_list(ptr + 4);
637 return 0; 641 return 0;
638 } 642 }
639 643
640 // nice value 644 // nice value
641 if (strncmp(ptr, "nice ", 4) == 0) { 645 if (strncmp(ptr, "nice ", 4) == 0) {
642 cfg.nice = atoi(ptr + 5); 646 cfg.nice = atoi(ptr + 5);
@@ -651,7 +655,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
651 set_cgroup(ptr + 7); 655 set_cgroup(ptr + 7);
652 return 0; 656 return 0;
653 } 657 }
654 658
655 // writable-etc 659 // writable-etc
656 if (strcmp(ptr, "writable-etc") == 0) { 660 if (strcmp(ptr, "writable-etc") == 0) {
657 if (cfg.etc_private_keep) { 661 if (cfg.etc_private_keep) {
@@ -661,7 +665,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
661 arg_writable_etc = 1; 665 arg_writable_etc = 1;
662 return 0; 666 return 0;
663 } 667 }
664 668
665 if (strcmp(ptr, "machine-id") == 0) { 669 if (strcmp(ptr, "machine-id") == 0) {
666 arg_machineid = 1; 670 arg_machineid = 1;
667 return 0; 671 return 0;
@@ -675,7 +679,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
675 arg_writable_var_log = 1; 679 arg_writable_var_log = 1;
676 return 0; 680 return 0;
677 } 681 }
678 682
679 // private directory 683 // private directory
680 if (strncmp(ptr, "private ", 8) == 0) { 684 if (strncmp(ptr, "private ", 8) == 0) {
681 cfg.home_private = ptr + 8; 685 cfg.home_private = ptr + 8;
@@ -717,7 +721,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
717#endif 721#endif
718 return 0; 722 return 0;
719 } 723 }
720 724
721 if (strcmp(ptr, "x11 xpra") == 0) { 725 if (strcmp(ptr, "x11 xpra") == 0) {
722#ifdef HAVE_X11 726#ifdef HAVE_X11
723 if (checkcfg(CFG_X11)) { 727 if (checkcfg(CFG_X11)) {
@@ -736,7 +740,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
736#endif 740#endif
737 return 0; 741 return 0;
738 } 742 }
739 743
740 if (strcmp(ptr, "x11 xvfb") == 0) { 744 if (strcmp(ptr, "x11 xvfb") == 0) {
741#ifdef HAVE_X11 745#ifdef HAVE_X11
742 if (checkcfg(CFG_X11)) { 746 if (checkcfg(CFG_X11)) {
@@ -766,15 +770,15 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
766 else { 770 else {
767 // start x11 771 // start x11
768 x11_start(cfg.original_argc, cfg.original_argv); 772 x11_start(cfg.original_argc, cfg.original_argv);
769 exit(0); 773 exit(0);
770 } 774 }
771 } 775 }
772 else 776 else
773 warning_feature_disabled("x11"); 777 warning_feature_disabled("x11");
774#endif 778#endif
775 return 0; 779 return 0;
776 } 780 }
777 781
778 // private /etc list of files and directories 782 // private /etc list of files and directories
779 if (strncmp(ptr, "private-etc ", 12) == 0) { 783 if (strncmp(ptr, "private-etc ", 12) == 0) {
780 if (arg_writable_etc) { 784 if (arg_writable_etc) {
@@ -788,7 +792,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
788 cfg.etc_private_keep = ptr + 12; 792 cfg.etc_private_keep = ptr + 12;
789 } 793 }
790 arg_private_etc = 1; 794 arg_private_etc = 1;
791 795
792 return 0; 796 return 0;
793 } 797 }
794 798
@@ -801,7 +805,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
801 cfg.opt_private_keep = ptr + 12; 805 cfg.opt_private_keep = ptr + 12;
802 } 806 }
803 arg_private_opt = 1; 807 arg_private_opt = 1;
804 808
805 return 0; 809 return 0;
806 } 810 }
807 811
@@ -814,7 +818,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
814 cfg.srv_private_keep = ptr + 12; 818 cfg.srv_private_keep = ptr + 12;
815 } 819 }
816 arg_private_srv = 1; 820 arg_private_srv = 1;
817 821
818 return 0; 822 return 0;
819 } 823 }
820 824
@@ -906,13 +910,13 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
906 910
907 // filesystem bind 911 // filesystem bind
908 if (strncmp(ptr, "bind ", 5) == 0) { 912 if (strncmp(ptr, "bind ", 5) == 0) {
909#ifdef HAVE_BIND 913#ifdef HAVE_BIND
910 if (checkcfg(CFG_BIND)) { 914 if (checkcfg(CFG_BIND)) {
911 if (getuid() != 0) { 915 if (getuid() != 0) {
912 fprintf(stderr, "Error: --bind option is available only if running as root\n"); 916 fprintf(stderr, "Error: --bind option is available only if running as root\n");
913 exit(1); 917 exit(1);
914 } 918 }
915 919
916 // extract two directories 920 // extract two directories
917 char *dname1 = ptr + 5; 921 char *dname1 = ptr + 5;
918 char *dname2 = split_comma(dname1); // this inserts a '0 to separate the two dierctories 922 char *dname2 = split_comma(dname1); // this inserts a '0 to separate the two dierctories
@@ -920,7 +924,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
920 fprintf(stderr, "Error: missing second directory for bind\n"); 924 fprintf(stderr, "Error: missing second directory for bind\n");
921 exit(1); 925 exit(1);
922 } 926 }
923 927
924 // check directories 928 // check directories
925 invalid_filename(dname1); 929 invalid_filename(dname1);
926 invalid_filename(dname2); 930 invalid_filename(dname2);
@@ -932,14 +936,14 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
932 fprintf(stderr, "Symbolic links are not allowed for bind command\n"); 936 fprintf(stderr, "Symbolic links are not allowed for bind command\n");
933 exit(1); 937 exit(1);
934 } 938 }
935 939
936 // insert comma back 940 // insert comma back
937 *(dname2 - 1) = ','; 941 *(dname2 - 1) = ',';
938 return 1; 942 return 1;
939 } 943 }
940 else 944 else
941 warning_feature_disabled("bind"); 945 warning_feature_disabled("bind");
942#endif 946#endif
943 return 0; 947 return 0;
944 } 948 }
945 949
@@ -969,8 +973,8 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
969 fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); 973 fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
970 exit(1); 974 exit(1);
971 } 975 }
972 976
973 return 0; 977 return 0;
974 } 978 }
975 979
976 if (strncmp(ptr, "join-or-start ", 14) == 0) { 980 if (strncmp(ptr, "join-or-start ", 14) == 0) {
@@ -1005,14 +1009,14 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1005 else if (strncmp(ptr, "noblacklist ", 12) == 0) 1009 else if (strncmp(ptr, "noblacklist ", 12) == 0)
1006 ptr += 12; 1010 ptr += 12;
1007 else if (strncmp(ptr, "whitelist ", 10) == 0) { 1011 else if (strncmp(ptr, "whitelist ", 10) == 0) {
1008#ifdef HAVE_WHITELIST 1012#ifdef HAVE_WHITELIST
1009 if (checkcfg(CFG_WHITELIST)) { 1013 if (checkcfg(CFG_WHITELIST)) {
1010 arg_whitelist = 1; 1014 arg_whitelist = 1;
1011 ptr += 10; 1015 ptr += 10;
1012 } 1016 }
1013 else 1017 else
1014 return 0; 1018 return 0;
1015#else 1019#else
1016 return 0; 1020 return 0;
1017#endif 1021#endif
1018 } 1022 }
@@ -1058,13 +1062,13 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1058// add a profile entry in cfg.profile list; use str to populate the list 1062// add a profile entry in cfg.profile list; use str to populate the list
1059void profile_add(char *str) { 1063void profile_add(char *str) {
1060 EUID_ASSERT(); 1064 EUID_ASSERT();
1061 1065
1062 ProfileEntry *prf = malloc(sizeof(ProfileEntry)); 1066 ProfileEntry *prf = malloc(sizeof(ProfileEntry));
1063 if (!prf) 1067 if (!prf)
1064 errExit("malloc"); 1068 errExit("malloc");
1065 memset(prf, 0, sizeof(ProfileEntry)); 1069 memset(prf, 0, sizeof(ProfileEntry));
1066 prf->next = NULL; 1070 prf->next = NULL;
1067 prf->data = str; 1071 prf->data = str;
1068 1072
1069 // add prf to the list 1073 // add prf to the list
1070 if (cfg.profile == NULL) { 1074 if (cfg.profile == NULL) {
@@ -1081,11 +1085,11 @@ void profile_add(char *str) {
1081static int include_level = 0; 1085static int include_level = 0;
1082void profile_read(const char *fname) { 1086void profile_read(const char *fname) {
1083 EUID_ASSERT(); 1087 EUID_ASSERT();
1084 1088
1085 // exit program if maximum include level was reached 1089 // exit program if maximum include level was reached
1086 if (include_level > MAX_INCLUDE_LEVEL) { 1090 if (include_level > MAX_INCLUDE_LEVEL) {
1087 fprintf(stderr, "Error: maximum profile include level was reached\n"); 1091 fprintf(stderr, "Error: maximum profile include level was reached\n");
1088 exit(1); 1092 exit(1);
1089 } 1093 }
1090 1094
1091 // check file 1095 // check file
@@ -1100,7 +1104,7 @@ void profile_read(const char *fname) {
1100 char *ptr = strstr(base, ".local"); 1104 char *ptr = strstr(base, ".local");
1101 if (ptr && strlen(ptr) == 6) 1105 if (ptr && strlen(ptr) == 6)
1102 return; 1106 return;
1103 1107
1104 fprintf(stderr, "Error: cannot access profile file\n"); 1108 fprintf(stderr, "Error: cannot access profile file\n");
1105 exit(1); 1109 exit(1);
1106 } 1110 }
@@ -1114,7 +1118,7 @@ void profile_read(const char *fname) {
1114 return; 1118 return;
1115 } 1119 }
1116 } 1120 }
1117 1121
1118 // open profile file: 1122 // open profile file:
1119 FILE *fp = fopen(fname, "r"); 1123 FILE *fp = fopen(fname, "r");
1120 if (fp == NULL) { 1124 if (fp == NULL) {
@@ -1133,13 +1137,13 @@ void profile_read(const char *fname) {
1133 char *ptr = line_remove_spaces(buf); 1137 char *ptr = line_remove_spaces(buf);
1134 if (ptr == NULL) 1138 if (ptr == NULL)
1135 continue; 1139 continue;
1136 1140
1137 // comments 1141 // comments
1138 if (*ptr == '#' || *ptr == '\0') { 1142 if (*ptr == '#' || *ptr == '\0') {
1139 free(ptr); 1143 free(ptr);
1140 continue; 1144 continue;
1141 } 1145 }
1142 1146
1143 // process quiet 1147 // process quiet
1144 if (strcmp(ptr, "quiet") == 0) { 1148 if (strcmp(ptr, "quiet") == 0) {
1145 arg_quiet = 1; 1149 arg_quiet = 1;
@@ -1155,13 +1159,13 @@ void profile_read(const char *fname) {
1155 // process include 1159 // process include
1156 if (strncmp(ptr, "include ", 8) == 0) { 1160 if (strncmp(ptr, "include ", 8) == 0) {
1157 include_level++; 1161 include_level++;
1158 1162
1159 // extract profile filename and new skip params 1163 // extract profile filename and new skip params
1160 char *newprofile = ptr + 8; // profile name 1164 char *newprofile = ptr + 8; // profile name
1161 1165
1162 // expand ${HOME}/ in front of the new profile file 1166 // expand ${HOME}/ in front of the new profile file
1163 char *newprofile2 = expand_home(newprofile, cfg.homedir); 1167 char *newprofile2 = expand_home(newprofile, cfg.homedir);
1164 1168
1165 // recursivity 1169 // recursivity
1166 profile_read((newprofile2)? newprofile2:newprofile); 1170 profile_read((newprofile2)? newprofile2:newprofile);
1167 include_level--; 1171 include_level--;
@@ -1170,7 +1174,7 @@ void profile_read(const char *fname) {
1170 free(ptr); 1174 free(ptr);
1171 continue; 1175 continue;
1172 } 1176 }
1173 1177
1174 // verify syntax, exit in case of error 1178 // verify syntax, exit in case of error
1175 if (profile_check_line(ptr, lineno, fname)) 1179 if (profile_check_line(ptr, lineno, fname))
1176 profile_add(ptr); 1180 profile_add(ptr);
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 3ff104d26..0b4d63c1b 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -17,7 +17,7 @@
17 * with this program; if not, write to the Free Software Foundation, Inc., 17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/ 19*/
20 20
21#include "firejail.h" 21#include "firejail.h"
22#include <sys/mount.h> 22#include <sys/mount.h>
23#include <sys/wait.h> 23#include <sys/wait.h>
@@ -65,7 +65,7 @@ static void sandbox_handler(int sig){
65 FILE *fp = fopen(monfile, "r"); 65 FILE *fp = fopen(monfile, "r");
66 if (!fp) 66 if (!fp)
67 break; 67 break;
68 68
69 char c; 69 char c;
70 size_t count = fread(&c, 1, 1, fp); 70 size_t count = fread(&c, 1, 1, fp);
71 fclose(fp); 71 fclose(fp);
@@ -78,7 +78,7 @@ static void sandbox_handler(int sig){
78 monsec--; 78 monsec--;
79 } 79 }
80 free(monfile); 80 free(monfile);
81 81
82 } 82 }
83 83
84 84
@@ -115,7 +115,7 @@ void save_nogroups(void) {
115 fprintf(stderr, "Error: cannot save nogroups state\n"); 115 fprintf(stderr, "Error: cannot save nogroups state\n");
116 exit(1); 116 exit(1);
117 } 117 }
118 118
119} 119}
120 120
121static void sandbox_if_up(Bridge *br) { 121static void sandbox_if_up(Bridge *br) {
@@ -132,7 +132,7 @@ static void sandbox_if_up(Bridge *br) {
132 fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); 132 fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev);
133 exit(1); 133 exit(1);
134 } 134 }
135 135
136 // just assign the address 136 // just assign the address
137 assert(br->ipsandbox); 137 assert(br->ipsandbox);
138 if (arg_debug) 138 if (arg_debug)
@@ -149,19 +149,19 @@ static void sandbox_if_up(Bridge *br) {
149 fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); 149 fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev);
150 exit(1); 150 exit(1);
151 } 151 }
152 152
153 uint32_t rv = arp_check(dev, br->ipsandbox, br->ip); 153 uint32_t rv = arp_check(dev, br->ipsandbox, br->ip);
154 if (rv) { 154 if (rv) {
155 fprintf(stderr, "Error: the address %d.%d.%d.%d is already in use.\n", PRINT_IP(br->ipsandbox)); 155 fprintf(stderr, "Error: the address %d.%d.%d.%d is already in use.\n", PRINT_IP(br->ipsandbox));
156 exit(1); 156 exit(1);
157 } 157 }
158 } 158 }
159 159
160 if (arg_debug) 160 if (arg_debug)
161 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); 161 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
162 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); 162 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu);
163 } 163 }
164 164
165 if (br->ip6sandbox) 165 if (br->ip6sandbox)
166 net_if_ip6(dev, br->ip6sandbox); 166 net_if_ip6(dev, br->ip6sandbox);
167} 167}
@@ -171,14 +171,14 @@ static void chk_chroot(void) {
171 char *mycont = getenv("container"); 171 char *mycont = getenv("container");
172 if (mycont) 172 if (mycont)
173 return; 173 return;
174 174
175 // check if this is a regular chroot 175 // check if this is a regular chroot
176 struct stat s; 176 struct stat s;
177 if (stat("/", &s) == 0) { 177 if (stat("/", &s) == 0) {
178 if (s.st_ino != 2) 178 if (s.st_ino != 2)
179 return; 179 return;
180 } 180 }
181 181
182 fprintf(stderr, "Error: cannot mount filesystem as slave\n"); 182 fprintf(stderr, "Error: cannot mount filesystem as slave\n");
183 exit(1); 183 exit(1);
184} 184}
@@ -238,7 +238,7 @@ static int monitor_application(pid_t app_pid) {
238 continue; 238 continue;
239 if (pid == 1) 239 if (pid == 1)
240 continue; 240 continue;
241 241
242 // todo: make this generic 242 // todo: make this generic
243 // Dillo browser leaves a dpid process running, we need to shut it down 243 // Dillo browser leaves a dpid process running, we need to shut it down
244 int found = 0; 244 int found = 0;
@@ -268,7 +268,7 @@ void start_audit(void) {
268 char *audit_prog; 268 char *audit_prog;
269 if (asprintf(&audit_prog, "%s/firejail/faudit", LIBDIR) == -1) 269 if (asprintf(&audit_prog, "%s/firejail/faudit", LIBDIR) == -1)
270 errExit("asprintf"); 270 errExit("asprintf");
271 assert(getenv("LD_PRELOAD") == NULL); 271 assert(getenv("LD_PRELOAD") == NULL);
272 execl(audit_prog, audit_prog, NULL); 272 execl(audit_prog, audit_prog, NULL);
273 perror("execl"); 273 perror("execl");
274 exit(1); 274 exit(1);
@@ -281,7 +281,7 @@ static void print_time(void) {
281 usleep(1000); 281 usleep(1000);
282 unsigned long long onems = getticks() - end_timestamp; 282 unsigned long long onems = getticks() - end_timestamp;
283 if (onems) { 283 if (onems) {
284 printf("Child process initialized in %.02f ms\n", 284 printf("Child process initialized in %.02f ms\n",
285 (float) (end_timestamp - start_timestamp) / (float) onems); 285 (float) (end_timestamp - start_timestamp) / (float) onems);
286 return; 286 return;
287 } 287 }
@@ -301,7 +301,7 @@ void start_application(void) {
301 printf("starting application\n"); 301 printf("starting application\n");
302 printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); 302 printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD"));
303 } 303 }
304 304
305 //**************************************** 305 //****************************************
306 // audit 306 // audit
307 //**************************************** 307 //****************************************
@@ -405,12 +405,12 @@ static void enforce_filters(void) {
405 free(cfg.seccomp_list_keep); 405 free(cfg.seccomp_list_keep);
406 cfg.seccomp_list_keep = NULL; 406 cfg.seccomp_list_keep = NULL;
407 } 407 }
408 408
409 // disable all capabilities 409 // disable all capabilities
410 if (arg_caps_default_filter || arg_caps_list) 410 if (arg_caps_default_filter || arg_caps_list)
411 fwarning("all capabilities disabled for a regular user in chroot\n"); 411 fwarning("all capabilities disabled for a regular user in chroot\n");
412 arg_caps_drop_all = 1; 412 arg_caps_drop_all = 1;
413 413
414 // drop all supplementary groups; /etc/group file inside chroot 414 // drop all supplementary groups; /etc/group file inside chroot
415 // is controlled by a regular usr 415 // is controlled by a regular usr
416 arg_nogroups = 1; 416 arg_nogroups = 1;
@@ -424,12 +424,12 @@ int sandbox(void* sandbox_arg) {
424 424
425 pid_t child_pid = getpid(); 425 pid_t child_pid = getpid();
426 if (arg_debug) 426 if (arg_debug)
427 printf("Initializing child process\n"); 427 printf("Initializing child process\n");
428 428
429 // close each end of the unused pipes 429 // close each end of the unused pipes
430 close(parent_to_child_fds[1]); 430 close(parent_to_child_fds[1]);
431 close(child_to_parent_fds[0]); 431 close(child_to_parent_fds[0]);
432 432
433 // wait for parent to do base setup 433 // wait for parent to do base setup
434 wait_for_other(parent_to_child_fds[0]); 434 wait_for_other(parent_to_child_fds[0]);
435 435
@@ -454,7 +454,7 @@ int sandbox(void* sandbox_arg) {
454 } 454 }
455 // ... and mount a tmpfs on top of /run/firejail/mnt directory 455 // ... and mount a tmpfs on top of /run/firejail/mnt directory
456 preproc_mount_mnt_dir(); 456 preproc_mount_mnt_dir();
457 457
458 //**************************** 458 //****************************
459 // log sandbox data 459 // log sandbox data
460 //**************************** 460 //****************************
@@ -463,12 +463,12 @@ int sandbox(void* sandbox_arg) {
463 fs_logger2int("sandbox pid:", (int) sandbox_pid); 463 fs_logger2int("sandbox pid:", (int) sandbox_pid);
464 if (cfg.chrootdir) 464 if (cfg.chrootdir)
465 fs_logger("sandbox filesystem: chroot"); 465 fs_logger("sandbox filesystem: chroot");
466 else if (arg_overlay) 466 else if (arg_overlay)
467 fs_logger("sandbox filesystem: overlay"); 467 fs_logger("sandbox filesystem: overlay");
468 else 468 else
469 fs_logger("sandbox filesystem: local"); 469 fs_logger("sandbox filesystem: local");
470 fs_logger("install mount namespace"); 470 fs_logger("install mount namespace");
471 471
472 //**************************** 472 //****************************
473 // netfilter 473 // netfilter
474 //**************************** 474 //****************************
@@ -496,23 +496,23 @@ int sandbox(void* sandbox_arg) {
496 else if (any_bridge_configured() || any_interface_configured()) { 496 else if (any_bridge_configured() || any_interface_configured()) {
497 // configure lo and eth0...eth3 497 // configure lo and eth0...eth3
498 net_if_up("lo"); 498 net_if_up("lo");
499 499
500 if (mac_not_zero(cfg.bridge0.macsandbox)) 500 if (mac_not_zero(cfg.bridge0.macsandbox))
501 net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox); 501 net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox);
502 sandbox_if_up(&cfg.bridge0); 502 sandbox_if_up(&cfg.bridge0);
503 503
504 if (mac_not_zero(cfg.bridge1.macsandbox)) 504 if (mac_not_zero(cfg.bridge1.macsandbox))
505 net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox); 505 net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox);
506 sandbox_if_up(&cfg.bridge1); 506 sandbox_if_up(&cfg.bridge1);
507 507
508 if (mac_not_zero(cfg.bridge2.macsandbox)) 508 if (mac_not_zero(cfg.bridge2.macsandbox))
509 net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox); 509 net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox);
510 sandbox_if_up(&cfg.bridge2); 510 sandbox_if_up(&cfg.bridge2);
511 511
512 if (mac_not_zero(cfg.bridge3.macsandbox)) 512 if (mac_not_zero(cfg.bridge3.macsandbox))
513 net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox); 513 net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox);
514 sandbox_if_up(&cfg.bridge3); 514 sandbox_if_up(&cfg.bridge3);
515 515
516 516
517 // moving an interface in a namespace using --interface will reset the interface configuration; 517 // moving an interface in a namespace using --interface will reset the interface configuration;
518 // we need to put the configuration back 518 // we need to put the configuration back
@@ -520,23 +520,23 @@ int sandbox(void* sandbox_arg) {
520 if (arg_debug) 520 if (arg_debug)
521 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev); 521 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev);
522 net_config_interface(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu); 522 net_config_interface(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu);
523 } 523 }
524 if (cfg.interface1.configured && cfg.interface1.ip) { 524 if (cfg.interface1.configured && cfg.interface1.ip) {
525 if (arg_debug) 525 if (arg_debug)
526 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev); 526 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev);
527 net_config_interface(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu); 527 net_config_interface(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu);
528 } 528 }
529 if (cfg.interface2.configured && cfg.interface2.ip) { 529 if (cfg.interface2.configured && cfg.interface2.ip) {
530 if (arg_debug) 530 if (arg_debug)
531 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev); 531 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev);
532 net_config_interface(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu); 532 net_config_interface(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu);
533 } 533 }
534 if (cfg.interface3.configured && cfg.interface3.ip) { 534 if (cfg.interface3.configured && cfg.interface3.ip) {
535 if (arg_debug) 535 if (arg_debug)
536 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev); 536 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev);
537 net_config_interface(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu); 537 net_config_interface(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu);
538 } 538 }
539 539
540 // add a default route 540 // add a default route
541 if (cfg.defaultgw) { 541 if (cfg.defaultgw) {
542 // set the default route 542 // set the default route
@@ -549,7 +549,7 @@ int sandbox(void* sandbox_arg) {
549 if (arg_debug) 549 if (arg_debug)
550 printf("Network namespace enabled\n"); 550 printf("Network namespace enabled\n");
551 } 551 }
552 552
553 553
554 // print network configuration 554 // print network configuration
555 if (!arg_quiet) { 555 if (!arg_quiet) {
@@ -561,7 +561,7 @@ int sandbox(void* sandbox_arg) {
561 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "printif", "scan"); 561 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "printif", "scan");
562 else 562 else
563 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, PATH_FNET, "printif", "scan"); 563 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, PATH_FNET, "printif", "scan");
564 564
565 } 565 }
566 if (cfg.defaultgw != 0) { 566 if (cfg.defaultgw != 0) {
567 if (gw_cfg_failed) 567 if (gw_cfg_failed)
@@ -585,7 +585,7 @@ int sandbox(void* sandbox_arg) {
585 } 585 }
586 else 586 else
587 env_ibus_load(); 587 env_ibus_load();
588 588
589 //**************************** 589 //****************************
590 // fs pre-processing: 590 // fs pre-processing:
591 // - build seccomp filters 591 // - build seccomp filters
@@ -602,7 +602,7 @@ int sandbox(void* sandbox_arg) {
602 if (rv) 602 if (rv)
603 exit(rv); 603 exit(rv);
604 } 604 }
605#endif 605#endif
606 606
607 // trace pre-install 607 // trace pre-install
608 if (arg_trace || arg_tracelog) 608 if (arg_trace || arg_tracelog)
@@ -622,13 +622,13 @@ int sandbox(void* sandbox_arg) {
622 enforce_filters(); 622 enforce_filters();
623#ifdef HAVE_SECCOMP 623#ifdef HAVE_SECCOMP
624 enforce_seccomp = 1; 624 enforce_seccomp = 1;
625#endif 625#endif
626 } 626 }
627 627
628#ifdef HAVE_CHROOT 628#ifdef HAVE_CHROOT
629 if (cfg.chrootdir) { 629 if (cfg.chrootdir) {
630 fs_chroot(cfg.chrootdir); 630 fs_chroot(cfg.chrootdir);
631 631
632 // force caps and seccomp if not started as root 632 // force caps and seccomp if not started as root
633 if (getuid() != 0) { 633 if (getuid() != 0) {
634 enforce_filters(); 634 enforce_filters();
@@ -638,14 +638,14 @@ int sandbox(void* sandbox_arg) {
638 } 638 }
639 else 639 else
640 arg_seccomp = 1; 640 arg_seccomp = 1;
641 641
642 //**************************** 642 //****************************
643 // trace pre-install, this time inside chroot 643 // trace pre-install, this time inside chroot
644 //**************************** 644 //****************************
645 if (arg_trace || arg_tracelog) 645 if (arg_trace || arg_tracelog)
646 fs_trace_preload(); 646 fs_trace_preload();
647 } 647 }
648 else 648 else
649#endif 649#endif
650#ifdef HAVE_OVERLAYFS 650#ifdef HAVE_OVERLAYFS
651 if (arg_overlay) { 651 if (arg_overlay) {
@@ -663,7 +663,7 @@ int sandbox(void* sandbox_arg) {
663 else 663 else
664#endif 664#endif
665 fs_basic_fs(); 665 fs_basic_fs();
666 666
667 //**************************** 667 //****************************
668 // private mode 668 // private mode
669 //**************************** 669 //****************************
@@ -696,7 +696,7 @@ int sandbox(void* sandbox_arg) {
696 else 696 else
697 fs_private_dev(); 697 fs_private_dev();
698 } 698 }
699 699
700 if (arg_private_etc) { 700 if (arg_private_etc) {
701 if (cfg.chrootdir) 701 if (cfg.chrootdir)
702 fwarning("private-etc feature is disabled in chroot\n"); 702 fwarning("private-etc feature is disabled in chroot\n");
@@ -709,7 +709,7 @@ int sandbox(void* sandbox_arg) {
709 fs_trace_preload(); 709 fs_trace_preload();
710 } 710 }
711 } 711 }
712 712
713 if (arg_private_opt) { 713 if (arg_private_opt) {
714 if (cfg.chrootdir) 714 if (cfg.chrootdir)
715 fwarning("private-opt feature is disabled in chroot\n"); 715 fwarning("private-opt feature is disabled in chroot\n");
@@ -719,7 +719,7 @@ int sandbox(void* sandbox_arg) {
719 fs_private_dir_list("/opt", RUN_OPT_DIR, cfg.opt_private_keep); 719 fs_private_dir_list("/opt", RUN_OPT_DIR, cfg.opt_private_keep);
720 } 720 }
721 } 721 }
722 722
723 if (arg_private_srv) { 723 if (arg_private_srv) {
724 if (cfg.chrootdir) 724 if (cfg.chrootdir)
725 fwarning("private-srv feature is disabled in chroot\n"); 725 fwarning("private-srv feature is disabled in chroot\n");
@@ -729,7 +729,7 @@ int sandbox(void* sandbox_arg) {
729 fs_private_dir_list("/srv", RUN_SRV_DIR, cfg.srv_private_keep); 729 fs_private_dir_list("/srv", RUN_SRV_DIR, cfg.srv_private_keep);
730 } 730 }
731 } 731 }
732 732
733 if (arg_private_bin) { 733 if (arg_private_bin) {
734 if (cfg.chrootdir) 734 if (cfg.chrootdir)
735 fwarning("private-bin feature is disabled in chroot\n"); 735 fwarning("private-bin feature is disabled in chroot\n");
@@ -748,7 +748,7 @@ int sandbox(void* sandbox_arg) {
748 fs_private_bin_list(); 748 fs_private_bin_list();
749 } 749 }
750 } 750 }
751 751
752 if (arg_private_tmp) { 752 if (arg_private_tmp) {
753 if (cfg.chrootdir) 753 if (cfg.chrootdir)
754 fwarning("private-tmp feature is disabled in chroot\n"); 754 fwarning("private-tmp feature is disabled in chroot\n");
@@ -762,7 +762,7 @@ int sandbox(void* sandbox_arg) {
762 } 762 }
763 } 763 }
764 764
765 765
766 //**************************** 766 //****************************
767 // hosts and hostname 767 // hosts and hostname
768 //**************************** 768 //****************************
@@ -777,19 +777,19 @@ int sandbox(void* sandbox_arg) {
777 //**************************** 777 //****************************
778 if (arg_netns) 778 if (arg_netns)
779 netns_mounts(arg_netns); 779 netns_mounts(arg_netns);
780 780
781 //**************************** 781 //****************************
782 // update /proc, /sys, /dev, /boot directory 782 // update /proc, /sys, /dev, /boot directory
783 //**************************** 783 //****************************
784 if (checkcfg(CFG_REMOUNT_PROC_SYS)) 784 if (checkcfg(CFG_REMOUNT_PROC_SYS))
785 fs_proc_sys_dev_boot(); 785 fs_proc_sys_dev_boot();
786 786
787 //**************************** 787 //****************************
788 // handle /mnt and /media 788 // handle /mnt and /media
789 //**************************** 789 //****************************
790 if (checkcfg(CFG_DISABLE_MNT)) 790 if (checkcfg(CFG_DISABLE_MNT))
791 fs_mnt(); 791 fs_mnt();
792 792
793 //**************************** 793 //****************************
794 // nosound/no3d and fix for pulseaudio 7.0 794 // nosound/no3d and fix for pulseaudio 7.0
795 //**************************** 795 //****************************
@@ -802,35 +802,43 @@ int sandbox(void* sandbox_arg) {
802 } 802 }
803 else 803 else
804 pulseaudio_init(); 804 pulseaudio_init();
805 805
806 if (arg_no3d) 806 if (arg_no3d)
807 fs_dev_disable_3d(); 807 fs_dev_disable_3d();
808 808
809 //****************************
810 // novideo
811 //****************************
812 if (arg_novideo) {
813 // disable /dev/video*
814 fs_dev_disable_video();
815 }
816
809 //**************************** 817 //****************************
810 // apply the profile file 818 // apply the profile file
811 //**************************** 819 //****************************
812 // apply all whitelist commands ... 820 // apply all whitelist commands ...
813 if (cfg.chrootdir) 821 if (cfg.chrootdir)
814 fwarning("whitelist feature is disabled in chroot\n"); 822 fwarning("whitelist feature is disabled in chroot\n");
815 else if (arg_overlay) 823 else if (arg_overlay)
816 fwarning("whitelist feature is disabled in overlay\n"); 824 fwarning("whitelist feature is disabled in overlay\n");
817 else 825 else
818 fs_whitelist(); 826 fs_whitelist();
819 827
820 // ... followed by blacklist commands 828 // ... followed by blacklist commands
821 fs_blacklist(); // mkdir and mkfile are processed all over again 829 fs_blacklist(); // mkdir and mkfile are processed all over again
822 830
823 //**************************** 831 //****************************
824 // install trace 832 // install trace
825 //**************************** 833 //****************************
826 if (arg_trace || arg_tracelog) 834 if (arg_trace || arg_tracelog)
827 fs_trace(); 835 fs_trace();
828 836
829 //**************************** 837 //****************************
830 // set dns 838 // set dns
831 //**************************** 839 //****************************
832 fs_resolvconf(); 840 fs_resolvconf();
833 841
834 //**************************** 842 //****************************
835 // fs post-processing 843 // fs post-processing
836 //**************************** 844 //****************************
@@ -846,7 +854,7 @@ int sandbox(void* sandbox_arg) {
846 if (chdir(cfg.cwd) == 0) 854 if (chdir(cfg.cwd) == 0)
847 cwd = 1; 855 cwd = 1;
848 } 856 }
849 857
850 if (!cwd) { 858 if (!cwd) {
851 if (chdir("/") < 0) 859 if (chdir("/") < 0)
852 errExit("chdir"); 860 errExit("chdir");
@@ -866,8 +874,8 @@ int sandbox(void* sandbox_arg) {
866 free(cpath); 874 free(cpath);
867 } 875 }
868 } 876 }
869 877
870 878
871 // set nice 879 // set nice
872 if (arg_nice) { 880 if (arg_nice) {
873 errno = 0; 881 errno = 0;
@@ -878,12 +886,12 @@ int sandbox(void* sandbox_arg) {
878 errno = 0; 886 errno = 0;
879 } 887 }
880 } 888 }
881 889
882 // clean /tmp/.X11-unix sockets 890 // clean /tmp/.X11-unix sockets
883 fs_x11(); 891 fs_x11();
884 if (arg_x11_xorg) 892 if (arg_x11_xorg)
885 x11_xorg(); 893 x11_xorg();
886 894
887 //**************************** 895 //****************************
888 // set security filters 896 // set security filters
889 //**************************** 897 //****************************
@@ -899,7 +907,7 @@ int sandbox(void* sandbox_arg) {
899 save_cpu(); // save cpu affinity mask to CPU_CFG file 907 save_cpu(); // save cpu affinity mask to CPU_CFG file
900 set_cpu_affinity(); 908 set_cpu_affinity();
901 } 909 }
902 910
903 // save cgroup in CGROUP_CFG file 911 // save cgroup in CGROUP_CFG file
904 if (cfg.cgroup) 912 if (cfg.cgroup)
905 save_cgroup(); 913 save_cgroup();
@@ -911,7 +919,7 @@ int sandbox(void* sandbox_arg) {
911 if (cfg.protocol) { 919 if (cfg.protocol) {
912 if (arg_debug) 920 if (arg_debug)
913 printf("Install protocol filter: %s\n", cfg.protocol); 921 printf("Install protocol filter: %s\n", cfg.protocol);
914 seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter 922 seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter
915 protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG 923 protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG
916 } 924 }
917#endif 925#endif
@@ -939,12 +947,12 @@ int sandbox(void* sandbox_arg) {
939 } 947 }
940 else 948 else
941 drop_privs(arg_nogroups); 949 drop_privs(arg_nogroups);
942 950
943 // notify parent that new user namespace has been created so a proper 951 // notify parent that new user namespace has been created so a proper
944 // UID/GID map can be setup 952 // UID/GID map can be setup
945 notify_other(child_to_parent_fds[1]); 953 notify_other(child_to_parent_fds[1]);
946 close(child_to_parent_fds[1]); 954 close(child_to_parent_fds[1]);
947 955
948 // wait for parent to finish setting up a proper UID/GID map 956 // wait for parent to finish setting up a proper UID/GID map
949 wait_for_other(parent_to_child_fds[0]); 957 wait_for_other(parent_to_child_fds[0]);
950 close(parent_to_child_fds[0]); 958 close(parent_to_child_fds[0]);
@@ -956,7 +964,7 @@ int sandbox(void* sandbox_arg) {
956 printf("noroot user namespace installed\n"); 964 printf("noroot user namespace installed\n");
957 set_caps(); 965 set_caps();
958 } 966 }
959 967
960 //**************************************** 968 //****************************************
961 // Set NO_NEW_PRIVS if desired 969 // Set NO_NEW_PRIVS if desired
962 //**************************************** 970 //****************************************
@@ -989,7 +997,7 @@ int sandbox(void* sandbox_arg) {
989 else if (arg_debug) 997 else if (arg_debug)
990 printf("AppArmor enabled\n"); 998 printf("AppArmor enabled\n");
991 } 999 }
992#endif 1000#endif
993 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died 1001 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died
994 start_application(); // start app 1002 start_application(); // start app
995 } 1003 }
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index a21633349..76930e1de 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -36,10 +36,10 @@ void usage(void) {
36 printf(" --apparmor - enable AppArmor confinement.\n"); 36 printf(" --apparmor - enable AppArmor confinement.\n");
37 printf(" --appimage - sandbox an AppImage application.\n"); 37 printf(" --appimage - sandbox an AppImage application.\n");
38 printf(" --audit[=test-program] - audit the sandbox.\n"); 38 printf(" --audit[=test-program] - audit the sandbox.\n");
39#ifdef HAVE_NETWORK 39#ifdef HAVE_NETWORK
40 printf(" --bandwidth=name|pid - set bandwidth limits.\n"); 40 printf(" --bandwidth=name|pid - set bandwidth limits.\n");
41#endif 41#endif
42#ifdef HAVE_BIND 42#ifdef HAVE_BIND
43 printf(" --bind=dirname1,dirname2 - mount-bind dirname1 on top of dirname2.\n"); 43 printf(" --bind=dirname1,dirname2 - mount-bind dirname1 on top of dirname2.\n");
44 printf(" --bind=filename1,filename2 - mount-bind filename1 on top of filename2.\n"); 44 printf(" --bind=filename1,filename2 - mount-bind filename1 on top of filename2.\n");
45#endif 45#endif
@@ -51,7 +51,7 @@ void usage(void) {
51 printf(" --caps.keep=capability,capability - whitelist capabilities filter.\n"); 51 printf(" --caps.keep=capability,capability - whitelist capabilities filter.\n");
52 printf(" --caps.print=name|pid - print the caps filter.\n"); 52 printf(" --caps.print=name|pid - print the caps filter.\n");
53 printf(" --cgroup=tasks-file - place the sandbox in the specified control group.\n"); 53 printf(" --cgroup=tasks-file - place the sandbox in the specified control group.\n");
54#ifdef HAVE_CHROOT 54#ifdef HAVE_CHROOT
55 printf(" --chroot=dirname - chroot into directory.\n"); 55 printf(" --chroot=dirname - chroot into directory.\n");
56#endif 56#endif
57 printf(" --cpu=cpu-number,cpu-number - set cpu affinity.\n"); 57 printf(" --cpu=cpu-number,cpu-number - set cpu affinity.\n");
@@ -64,15 +64,15 @@ void usage(void) {
64 printf(" --debug-errnos - print all recognized error numbers.\n"); 64 printf(" --debug-errnos - print all recognized error numbers.\n");
65 printf(" --debug-protocols - print all recognized protocols.\n"); 65 printf(" --debug-protocols - print all recognized protocols.\n");
66 printf(" --debug-syscalls - print all recognized system calls.\n"); 66 printf(" --debug-syscalls - print all recognized system calls.\n");
67#ifdef HAVE_WHITELIST 67#ifdef HAVE_WHITELIST
68 printf(" --debug-whitelists - debug whitelisting.\n"); 68 printf(" --debug-whitelists - debug whitelisting.\n");
69#endif 69#endif
70#ifdef HAVE_NETWORK 70#ifdef HAVE_NETWORK
71 printf(" --defaultgw=address - configure default gateway.\n"); 71 printf(" --defaultgw=address - configure default gateway.\n");
72#endif 72#endif
73 printf(" --dns=address - set DNS server.\n"); 73 printf(" --dns=address - set DNS server.\n");
74 printf(" --dns.print=name|pid - print DNS configuration.\n"); 74 printf(" --dns.print=name|pid - print DNS configuration.\n");
75 75
76 printf(" --env=name=value - set environment variable.\n"); 76 printf(" --env=name=value - set environment variable.\n");
77 printf(" --force - attempt to start a new sandbox inside the existing sandbox.\n"); 77 printf(" --force - attempt to start a new sandbox inside the existing sandbox.\n");
78 printf(" --fs.print=name|pid - print the filesystem log.\n"); 78 printf(" --fs.print=name|pid - print the filesystem log.\n");
@@ -86,7 +86,7 @@ void usage(void) {
86 printf(" --hostname=name - set sandbox hostname.\n"); 86 printf(" --hostname=name - set sandbox hostname.\n");
87 printf(" --hosts-file=file - use file as /etc/hosts.\n"); 87 printf(" --hosts-file=file - use file as /etc/hosts.\n");
88 printf(" --ignore=command - ignore command in profile files.\n"); 88 printf(" --ignore=command - ignore command in profile files.\n");
89#ifdef HAVE_NETWORK 89#ifdef HAVE_NETWORK
90 printf(" --interface=name - move interface in sandbox.\n"); 90 printf(" --interface=name - move interface in sandbox.\n");
91 printf(" --ip=address - set interface IP address.\n"); 91 printf(" --ip=address - set interface IP address.\n");
92 printf(" --ip=none - no IP address and no default gateway are configured.\n"); 92 printf(" --ip=none - no IP address and no default gateway are configured.\n");
@@ -96,21 +96,21 @@ void usage(void) {
96 printf(" --ipc-namespace - enable a new IPC namespace.\n"); 96 printf(" --ipc-namespace - enable a new IPC namespace.\n");
97 printf(" --join=name|pid - join the sandbox.\n"); 97 printf(" --join=name|pid - join the sandbox.\n");
98 printf(" --join-filesystem=name|pid - join the mount namespace.\n"); 98 printf(" --join-filesystem=name|pid - join the mount namespace.\n");
99#ifdef HAVE_NETWORK 99#ifdef HAVE_NETWORK
100 printf(" --join-network=name|pid - join the network namespace.\n"); 100 printf(" --join-network=name|pid - join the network namespace.\n");
101#endif 101#endif
102 printf(" --join-or-start=name|pid - join the sandbox or start a new one.\n"); 102 printf(" --join-or-start=name|pid - join the sandbox or start a new one.\n");
103 printf(" --list - list all sandboxes.\n"); 103 printf(" --list - list all sandboxes.\n");
104 printf(" --ls=name|pid dir_or_filename - list files in sandbox container.\n"); 104 printf(" --ls=name|pid dir_or_filename - list files in sandbox container.\n");
105#ifdef HAVE_NETWORK 105#ifdef HAVE_NETWORK
106 printf(" --mac=xx:xx:xx:xx:xx:xx - set interface MAC address.\n"); 106 printf(" --mac=xx:xx:xx:xx:xx:xx - set interface MAC address.\n");
107#endif 107#endif
108 printf(" --machine-id - preserve /etc/machine-id\n"); 108 printf(" --machine-id - preserve /etc/machine-id\n");
109#ifdef HAVE_NETWORK 109#ifdef HAVE_NETWORK
110 printf(" --mtu=number - set interface MTU.\n"); 110 printf(" --mtu=number - set interface MTU.\n");
111#endif 111#endif
112 printf(" --name=name - set sandbox name.\n"); 112 printf(" --name=name - set sandbox name.\n");
113#ifdef HAVE_NETWORK 113#ifdef HAVE_NETWORK
114 printf(" --net=bridgename - enable network namespaces and connect to this bridge.\n"); 114 printf(" --net=bridgename - enable network namespaces and connect to this bridge.\n");
115 printf(" --net=ethernet_interface - enable network namespaces and connect to this\n"); 115 printf(" --net=ethernet_interface - enable network namespaces and connect to this\n");
116 printf("\tEthernet interface.\n"); 116 printf("\tEthernet interface.\n");
@@ -127,17 +127,18 @@ void usage(void) {
127 printf(" --nogroups - disable supplementary groups.\n"); 127 printf(" --nogroups - disable supplementary groups.\n");
128 printf(" --nonewprivs - sets the NO_NEW_PRIVS prctl.\n"); 128 printf(" --nonewprivs - sets the NO_NEW_PRIVS prctl.\n");
129 printf(" --noprofile - do not use a security profile.\n"); 129 printf(" --noprofile - do not use a security profile.\n");
130#ifdef HAVE_USERNS 130#ifdef HAVE_USERNS
131 printf(" --noroot - install a user namespace with only the current user.\n"); 131 printf(" --noroot - install a user namespace with only the current user.\n");
132#endif 132#endif
133 printf(" --nosound - disable sound system.\n"); 133 printf(" --nosound - disable sound system.\n");
134 printf(" --novideo - disable video devices.\n");
134 printf(" --nowhitelist=filename - disable whitelist for file or directory .\n"); 135 printf(" --nowhitelist=filename - disable whitelist for file or directory .\n");
135 printf(" --output=logfile - stdout logging and log rotation.\n"); 136 printf(" --output=logfile - stdout logging and log rotation.\n");
136 printf(" --overlay - mount a filesystem overlay on top of the current filesystem.\n"); 137 printf(" --overlay - mount a filesystem overlay on top of the current filesystem.\n");
137 printf(" --overlay-named=name - mount a filesystem overlay on top of the current\n"); 138 printf(" --overlay-named=name - mount a filesystem overlay on top of the current\n");
138 printf("\tfilesystem, and store it in name directory.\n"); 139 printf("\tfilesystem, and store it in name directory.\n");
139 printf(" --overlay-tmpfs - mount a temporary filesystem overlay on top of the current\n"); 140 printf(" --overlay-tmpfs - mount a temporary filesystem overlay on top of the current\n");
140 printf("\tfilesystem.\n"); 141 printf("\tfilesystem.\n");
141 printf(" --overlay-clean - clean all overlays stored in $HOME/.firejail directory.\n"); 142 printf(" --overlay-clean - clean all overlays stored in $HOME/.firejail directory.\n");
142 printf(" --private - temporary home directory.\n"); 143 printf(" --private - temporary home directory.\n");
143 printf(" --private=directory - use directory as user home.\n"); 144 printf(" --private=directory - use directory as user home.\n");
@@ -169,9 +170,9 @@ void usage(void) {
169 printf(" --rlimit-sigpending=number - set the maximum number of pending signals\n"); 170 printf(" --rlimit-sigpending=number - set the maximum number of pending signals\n");
170 printf("\tfor a process.\n"); 171 printf("\tfor a process.\n");
171 printf(" --rmenv=name - remove environment variable in the new sandbox.\n"); 172 printf(" --rmenv=name - remove environment variable in the new sandbox.\n");
172#ifdef HAVE_NETWORK 173#ifdef HAVE_NETWORK
173 printf(" --scan - ARP-scan all the networks from inside a network namespace.\n"); 174 printf(" --scan - ARP-scan all the networks from inside a network namespace.\n");
174#endif 175#endif
175#ifdef HAVE_SECCOMP 176#ifdef HAVE_SECCOMP
176 printf(" --seccomp - enable seccomp filter and apply the default blacklist.\n"); 177 printf(" --seccomp - enable seccomp filter and apply the default blacklist.\n");
177 printf(" --seccomp=syscall,syscall,syscall - enable seccomp filter, blacklist the\n"); 178 printf(" --seccomp=syscall,syscall,syscall - enable seccomp filter, blacklist the\n");
@@ -195,12 +196,12 @@ void usage(void) {
195 printf("\tdirectoires blacklisted by the security profile.\n"); 196 printf("\tdirectoires blacklisted by the security profile.\n");
196 printf(" --tree - print a tree of all sandboxed processes.\n"); 197 printf(" --tree - print a tree of all sandboxed processes.\n");
197 printf(" --version - print program version and exit.\n"); 198 printf(" --version - print program version and exit.\n");
198#ifdef HAVE_NETWORK 199#ifdef HAVE_NETWORK
199 printf(" --veth-name=name - use this name for the interface connected to the bridge.\n"); 200 printf(" --veth-name=name - use this name for the interface connected to the bridge.\n");
200#endif 201#endif
201#ifdef HAVE_WHITELIST 202#ifdef HAVE_WHITELIST
202 printf(" --whitelist=filename - whitelist directory or file.\n"); 203 printf(" --whitelist=filename - whitelist directory or file.\n");
203#endif 204#endif
204 printf(" --writable-etc - /etc directory is mounted read-write.\n"); 205 printf(" --writable-etc - /etc directory is mounted read-write.\n");
205 printf(" --writable-var - /var directory is mounted read-write.\n"); 206 printf(" --writable-var - /var directory is mounted read-write.\n");
206 printf(" --writable-var-log - use the real /var/log directory, not a clone.\n"); 207 printf(" --writable-var-log - use the real /var/log directory, not a clone.\n");
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index bb1bd86b9..cbffa9ce4 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -50,7 +50,7 @@ Parent pid 8553, child pid 8554
50.br 50.br
51Child process initialized 51Child process initialized
52.br 52.br
53[...] 53[...]
54.br 54.br
55 55
56.br 56.br
@@ -92,7 +92,7 @@ Example: "include ${CFG}/firefox.profile" will load "/etc/firejail/firefox.profi
92 92
93System configuration files in ${CFG} are overwritten during software installation. 93System configuration files in ${CFG} are overwritten during software installation.
94Persistent configuration at system level is handled in ".local" files. For every 94Persistent configuration at system level is handled in ".local" files. For every
95profile file in ${CFG} directory, the user can create a corresponding .local file 95profile file in ${CFG} directory, the user can create a corresponding .local file
96storing modifications to the persistent configuration. Persistent .local files 96storing modifications to the persistent configuration. Persistent .local files
97are included at the start of regular profile files. 97are included at the start of regular profile files.
98 98
@@ -255,7 +255,7 @@ Blacklist violations logged to syslog.
255\fBwhitelist file_or_directory 255\fBwhitelist file_or_directory
256Whitelist directory or file. A temporary file system is mounted on the top directory, and the 256Whitelist directory or file. A temporary file system is mounted on the top directory, and the
257whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, 257whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent,
258everything else is discarded when the sandbox is closed. The top directory could be 258everything else is discarded when the sandbox is closed. The top directory could be
259user home, /dev, /media, /mnt, /opt, /srv, /var, and /tmp. 259user home, /dev, /media, /mnt, /opt, /srv, /var, and /tmp.
260.br 260.br
261 261
@@ -405,6 +405,8 @@ Enable IPC namespace.
405\fBnosound 405\fBnosound
406Disable sound system. 406Disable sound system.
407.TP 407.TP
408\fBnovideo
409Disable video devices.
408\fBno3d 410\fBno3d
409Disable 3D hardware acceleration. 411Disable 3D hardware acceleration.
410 412
@@ -533,7 +535,7 @@ really need network access.
533 535
534.TP 536.TP
535\fBveth-name name 537\fBveth-name name
536Use this name for the interface connected to the bridge for --net=bridge_interface commands, 538Use this name for the interface connected to the bridge for --net=bridge_interface commands,
537instead of the default one. 539instead of the default one.
538 540
539.SH Other 541.SH Other
@@ -585,6 +587,3 @@ Homepage: http://firejail.wordpress.com
585\&\flfiremon\fR\|(1), 587\&\flfiremon\fR\|(1),
586\&\flfirecfg\fR\|(1), 588\&\flfirecfg\fR\|(1),
587\&\flfirejail-login\fR\|(5) 589\&\flfirejail-login\fR\|(5)
588
589
590
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 38bb6a19e..de300d47b 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -42,7 +42,7 @@ and it is integrated with Linux Control Groups.
42.PP 42.PP
43Written in C with virtually no dependencies, the software runs on any Linux computer with a 3.x kernel version 43Written in C with virtually no dependencies, the software runs on any Linux computer with a 3.x kernel version
44or newer. 44or newer.
45It can sandbox any type of processes: servers, graphical applications, and even user login sessions. 45It can sandbox any type of processes: servers, graphical applications, and even user login sessions.
46.PP 46.PP
47Firejail allows the user to manage application security using security profiles. 47Firejail allows the user to manage application security using security profiles.
48Each profile defines a set of permissions for a specific application or group 48Each profile defines a set of permissions for a specific application or group
@@ -52,13 +52,13 @@ Linux programs, such as Mozilla Firefox, Chromium, VLC, Transmission etc.
52.SH USAGE 52.SH USAGE
53Without any options, the sandbox consists of a filesystem build in a new mount namespace, 53Without any options, the sandbox consists of a filesystem build in a new mount namespace,
54and new PID and UTS namespaces. IPC, network and user namespaces can be added using the 54and new PID and UTS namespaces. IPC, network and user namespaces can be added using the
55command line options. The default Firejail filesystem is based on the host filesystem with the main 55command line options. The default Firejail filesystem is based on the host filesystem with the main
56system directories mounted read-only. These directories are /etc, /var, /usr, /bin, /sbin, /lib, /lib32, 56system directories mounted read-only. These directories are /etc, /var, /usr, /bin, /sbin, /lib, /lib32,
57/libx32 and /lib64. Only /home and /tmp are writable. 57/libx32 and /lib64. Only /home and /tmp are writable.
58.PP 58.PP
59As it starts up, Firejail tries to find a security profile based on the name of the application. 59As it starts up, Firejail tries to find a security profile based on the name of the application.
60If an appropriate profile is not found, Firejail will use a default profile. 60If an appropriate profile is not found, Firejail will use a default profile.
61The default profile is quite restrictive. In case the application doesn't work, use --noprofile option 61The default profile is quite restrictive. In case the application doesn't work, use --noprofile option
62to disable it. For more information, please see \fBSECURITY PROFILES\fR section below. 62to disable it. For more information, please see \fBSECURITY PROFILES\fR section below.
63.PP 63.PP
64If a program argument is not specified, Firejail starts /bin/bash shell. 64If a program argument is not specified, Firejail starts /bin/bash shell.
@@ -657,7 +657,7 @@ $ sudo firejail --join-network=browser ip addr
657.br 657.br
658Switching to pid 1932, the first child process inside the sandbox 658Switching to pid 1932, the first child process inside the sandbox
659.br 659.br
6601: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 6601: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
661.br 661.br
662 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 662 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
663.br 663.br
@@ -665,11 +665,11 @@ Switching to pid 1932, the first child process inside the sandbox
665.br 665.br
666 valid_lft forever preferred_lft forever 666 valid_lft forever preferred_lft forever
667.br 667.br
668 inet6 ::1/128 scope host 668 inet6 ::1/128 scope host
669.br 669.br
670 valid_lft forever preferred_lft forever 670 valid_lft forever preferred_lft forever
671.br 671.br
6722: eth0-1931: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 6722: eth0-1931: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
673.br 673.br
674 link/ether 76:58:14:42:78:e4 brd ff:ff:ff:ff:ff:ff 674 link/ether 76:58:14:42:78:e4 brd ff:ff:ff:ff:ff:ff
675.br 675.br
@@ -677,7 +677,7 @@ Switching to pid 1932, the first child process inside the sandbox
677.br 677.br
678 valid_lft forever preferred_lft forever 678 valid_lft forever preferred_lft forever
679.br 679.br
680 inet6 fe80::7458:14ff:fe42:78e4/64 scope link 680 inet6 fe80::7458:14ff:fe42:78e4/64 scope link
681.br 681.br
682 valid_lft forever preferred_lft forever 682 valid_lft forever preferred_lft forever
683 683
@@ -702,13 +702,13 @@ Example:
702.br 702.br
703$ firejail \-\-list 703$ firejail \-\-list
704.br 704.br
7057015:netblue:firejail firefox 7057015:netblue:firejail firefox
706.br 706.br
7077056:netblue:firejail \-\-net=eth0 transmission-gtk 7077056:netblue:firejail \-\-net=eth0 transmission-gtk
708.br 708.br
7097064:netblue:firejail \-\-noroot xterm 7097064:netblue:firejail \-\-noroot xterm
710.br 710.br
711$ 711$
712.TP 712.TP
713\fB\-\-mac=address 713\fB\-\-mac=address
714Assign MAC addresses to the last network interface defined by a \-\-net option. 714Assign MAC addresses to the last network interface defined by a \-\-net option.
@@ -998,7 +998,7 @@ $
998 998
999.TP 999.TP
1000\fB\-\-noprofile 1000\fB\-\-noprofile
1001Do not use a security profile. 1001Do not use a security profile.
1002.br 1002.br
1003 1003
1004.br 1004.br
@@ -1012,7 +1012,7 @@ Parent pid 8553, child pid 8554
1012.br 1012.br
1013Child process initialized 1013Child process initialized
1014.br 1014.br
1015[...] 1015[...]
1016.br 1016.br
1017 1017
1018.br 1018.br
@@ -1067,6 +1067,11 @@ Example:
1067$ firejail \-\-nosound firefox 1067$ firejail \-\-nosound firefox
1068 1068
1069.TP 1069.TP
1070\fB\-\-novideo
1071Disable video devices.
1072.br
1073
1074.TP
1070\fB\-\-nowhitelist=dirname_or_filename 1075\fB\-\-nowhitelist=dirname_or_filename
1071Disable whitelist for this directory or file. 1076Disable whitelist for this directory or file.
1072 1077
@@ -1200,7 +1205,7 @@ $ firejail \-\-private-home=.mozilla firefox
1200Build a new /bin in a temporary filesystem, and copy the programs in the list. 1205Build a new /bin in a temporary filesystem, and copy the programs in the list.
1201If no listed file is found, /bin directory will be empty. 1206If no listed file is found, /bin directory will be empty.
1202The same directory is also bind-mounted over /sbin, /usr/bin, /usr/sbin and /usr/local/bin. 1207The same directory is also bind-mounted over /sbin, /usr/bin, /usr/sbin and /usr/local/bin.
1203All modifications are discarded when the sandbox is closed. 1208All modifications are discarded when the sandbox is closed.
1204.br 1209.br
1205 1210
1206.br 1211.br
@@ -1240,7 +1245,7 @@ $
1240Build a new /etc in a temporary 1245Build a new /etc in a temporary
1241filesystem, and copy the files and directories in the list. 1246filesystem, and copy the files and directories in the list.
1242If no listed file is found, /etc directory will be empty. 1247If no listed file is found, /etc directory will be empty.
1243All modifications are discarded when the sandbox is closed. 1248All modifications are discarded when the sandbox is closed.
1244.br 1249.br
1245 1250
1246.br 1251.br
@@ -1255,7 +1260,7 @@ nsswitch.conf,passwd,resolv.conf
1255Build a new /opt in a temporary 1260Build a new /opt in a temporary
1256filesystem, and copy the files and directories in the list. 1261filesystem, and copy the files and directories in the list.
1257If no listed file is found, /opt directory will be empty. 1262If no listed file is found, /opt directory will be empty.
1258All modifications are discarded when the sandbox is closed. 1263All modifications are discarded when the sandbox is closed.
1259.br 1264.br
1260 1265
1261.br 1266.br
@@ -1268,7 +1273,7 @@ $ firejail --private-opt=firefox /opt/firefox/firefox
1268Build a new /srv in a temporary 1273Build a new /srv in a temporary
1269filesystem, and copy the files and directories in the list. 1274filesystem, and copy the files and directories in the list.
1270If no listed file is found, /srv directory will be empty. 1275If no listed file is found, /srv directory will be empty.
1271All modifications are discarded when the sandbox is closed. 1276All modifications are discarded when the sandbox is closed.
1272.br 1277.br
1273 1278
1274.br 1279.br
@@ -1573,7 +1578,7 @@ SECCOMP Filter:
1573.br 1578.br
1574 RETURN_ALLOW 1579 RETURN_ALLOW
1575.br 1580.br
1576$ 1581$
1577.TP 1582.TP
1578\fB\-\-shell=none 1583\fB\-\-shell=none
1579Run the program directly, without a user shell. 1584Run the program directly, without a user shell.
@@ -1665,7 +1670,7 @@ parent is shutting down, bye...
1665.TP 1670.TP
1666\fB\-\-tracelog 1671\fB\-\-tracelog
1667This option enables auditing blacklisted files and directories. A message 1672This option enables auditing blacklisted files and directories. A message
1668is sent to syslog in case the file or the directory is accessed. 1673is sent to syslog in case the file or the directory is accessed.
1669.br 1674.br
1670 1675
1671.br 1676.br
@@ -1698,13 +1703,13 @@ $ firejail \-\-tree
1698.br 1703.br
169911903:netblue:firejail iceweasel 170411903:netblue:firejail iceweasel
1700.br 1705.br
1701 11904:netblue:iceweasel 1706 11904:netblue:iceweasel
1702.br 1707.br
1703 11957:netblue:/usr/lib/iceweasel/plugin-container 1708 11957:netblue:/usr/lib/iceweasel/plugin-container
1704.br 1709.br
170511969:netblue:firejail \-\-net=eth0 transmission-gtk 171011969:netblue:firejail \-\-net=eth0 transmission-gtk
1706.br 1711.br
1707 11970:netblue:transmission-gtk 1712 11970:netblue:transmission-gtk
1708 1713
1709.TP 1714.TP
1710\fB\-\-version 1715\fB\-\-version
@@ -1720,7 +1725,7 @@ firejail version 0.9.27
1720 1725
1721.TP 1726.TP
1722\fB\-\-veth-name=name 1727\fB\-\-veth-name=name
1723Use this name for the interface connected to the bridge for --net=bridge_interface commands, 1728Use this name for the interface connected to the bridge for --net=bridge_interface commands,
1724instead of the default one. 1729instead of the default one.
1725.br 1730.br
1726 1731
@@ -1733,7 +1738,7 @@ $ firejail \-\-net=br0 --veth-name=if0
1733\fB\-\-whitelist=dirname_or_filename 1738\fB\-\-whitelist=dirname_or_filename
1734Whitelist directory or file. A temporary file system is mounted on the top directory, and the 1739Whitelist directory or file. A temporary file system is mounted on the top directory, and the
1735whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, 1740whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent,
1736everything else is discarded when the sandbox is closed. The top directory could be 1741everything else is discarded when the sandbox is closed. The top directory could be
1737user home, /dev, /media, /mnt, /opt, /srv, /var, and /tmp. 1742user home, /dev, /media, /mnt, /opt, /srv, /var, and /tmp.
1738.br 1743.br
1739 1744
@@ -1789,7 +1794,7 @@ Sandbox the application using Xpra, Xephyr, Xvfb or Xorg security extension.
1789The sandbox will prevents screenshot and keylogger applications started inside the sandbox from accessing 1794The sandbox will prevents screenshot and keylogger applications started inside the sandbox from accessing
1790clients running outside the sandbox. 1795clients running outside the sandbox.
1791Firejail will try first Xpra, and if Xpra is not installed on the system, it will try to find Xephyr. 1796Firejail will try first Xpra, and if Xpra is not installed on the system, it will try to find Xephyr.
1792If all fails, Firejail will not attempt to use Xvfb or X11 security extension. 1797If all fails, Firejail will not attempt to use Xvfb or X11 security extension.
1793.br 1798.br
1794 1799
1795.br 1800.br
@@ -1828,7 +1833,7 @@ A security profile for OpenBox is provided.
1828 1833
1829.br 1834.br
1830Xephyr is developed by Xorg project. On Debian platforms it is installed with the command \fBsudo apt-get install xserver-xephyr\fR. 1835Xephyr is developed by Xorg project. On Debian platforms it is installed with the command \fBsudo apt-get install xserver-xephyr\fR.
1831This feature is not available when running as root. 1836This feature is not available when running as root.
1832.br 1837.br
1833 1838
1834.br 1839.br
@@ -1838,9 +1843,9 @@ $ firejail \-\-x11=xephyr --net=eth0 openbox
1838 1843
1839.TP 1844.TP
1840\fB\-\-x11=xorg 1845\fB\-\-x11=xorg
1841Sandbox the application using the untrusted mode implemented by X11 security extension. 1846Sandbox the application using the untrusted mode implemented by X11 security extension.
1842The extension is available in Xorg package 1847The extension is available in Xorg package
1843and it is installed by default on most Linux distributions. It provides support for a simple trusted/untrusted 1848and it is installed by default on most Linux distributions. It provides support for a simple trusted/untrusted
1844connection model. Untrusted clients are restricted in certain ways to prevent them from reading window 1849connection model. Untrusted clients are restricted in certain ways to prevent them from reading window
1845contents of other clients, stealing input events, etc. 1850contents of other clients, stealing input events, etc.
1846 1851
@@ -1875,9 +1880,9 @@ $ firejail \-\-x11=xpra --net=eth0 firefox
1875 1880
1876.TP 1881.TP
1877\fB\-\-x11=xvfb 1882\fB\-\-x11=xvfb
1878Start Xvfb X11 server and attach the sandbox to this server. 1883Start Xvfb X11 server and attach the sandbox to this server.
1879Xvfb, short for X virtual framebuffer, performs all graphical operations in memory 1884Xvfb, short for X virtual framebuffer, performs all graphical operations in memory
1880without showing any screen output. Xvfb is mainly used for remote access and software 1885without showing any screen output. Xvfb is mainly used for remote access and software
1881testing on headless servers. 1886testing on headless servers.
1882.br 1887.br
1883 1888
@@ -1992,7 +1997,7 @@ $ firejail --tree
1992.br 1997.br
1993 1190:netblue:firejail firefox 1998 1190:netblue:firejail firefox
1994.br 1999.br
1995 1220:netblue:/bin/sh -c "/usr/lib/firefox/firefox" 2000 1220:netblue:/bin/sh -c "/usr/lib/firefox/firefox"
1996.br 2001.br
1997 1221:netblue:/usr/lib/firefox/firefox 2002 1221:netblue:/usr/lib/firefox/firefox
1998.RE 2003.RE
@@ -2246,7 +2251,7 @@ Parent pid 8553, child pid 8554
2246.br 2251.br
2247Child process initialized 2252Child process initialized
2248.br 2253.br
2249[...] 2254[...]
2250.br 2255.br
2251 2256
2252.br 2257.br
@@ -2260,7 +2265,7 @@ Child process initialized
2260.RE 2265.RE
2261 2266
2262See man 5 firejail-profile for profile file syntax information. 2267See man 5 firejail-profile for profile file syntax information.
2263 2268
2264.SH RESTRICTED SHELL 2269.SH RESTRICTED SHELL
2265To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in 2270To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in
2266/etc/passwd file for each user that needs to be restricted. Alternatively, 2271/etc/passwd file for each user that needs to be restricted. Alternatively,
@@ -2307,6 +2312,3 @@ Homepage: http://firejail.wordpress.com
2307\&\flfirecfg\fR\|(1), 2312\&\flfirecfg\fR\|(1),
2308\&\flfirejail-profile\fR\|(5), 2313\&\flfirejail-profile\fR\|(5),
2309\&\flfirejail-login\fR\|(5) 2314\&\flfirejail-login\fR\|(5)
2310
2311
2312