aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bash_completion/firejail.bash_completion.in8
-rw-r--r--src/fcopy/main.c3
-rw-r--r--src/fids/fids.h2
-rw-r--r--src/firecfg/firecfg.config1
-rw-r--r--src/firejail/env.c6
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/fs.c52
-rw-r--r--src/firejail/fs_dev.c2
-rw-r--r--src/firejail/fs_home.c11
-rw-r--r--src/firejail/fs_hostname.c7
-rw-r--r--src/firejail/fs_lib.c5
-rw-r--r--src/firejail/fs_lib2.c6
-rw-r--r--src/firejail/fs_whitelist.c59
-rw-r--r--src/firejail/ids.c2
-rw-r--r--src/firejail/join.c20
-rw-r--r--src/firejail/main.c17
-rw-r--r--src/firejail/mountinfo.c71
-rw-r--r--src/firejail/profile.c12
-rw-r--r--src/firejail/sandbox.c19
-rw-r--r--src/firejail/selinux.c21
-rw-r--r--src/firejail/usage.c32
-rw-r--r--src/firejail/util.c14
-rw-r--r--src/jailcheck/jailcheck.h2
-rw-r--r--src/jailcheck/noexec.c2
-rw-r--r--src/man/firejail-profile.txt122
-rw-r--r--src/man/firejail.txt156
-rw-r--r--src/man/firemon.txt2
-rw-r--r--src/tools/profcleaner.c2
-rw-r--r--src/zsh_completion/_firejail.in2
29 files changed, 341 insertions, 319 deletions
diff --git a/src/bash_completion/firejail.bash_completion.in b/src/bash_completion/firejail.bash_completion.in
index f68edf380..ff411c807 100644
--- a/src/bash_completion/firejail.bash_completion.in
+++ b/src/bash_completion/firejail.bash_completion.in
@@ -5,7 +5,7 @@
5# http://bash-completion.alioth.debian.org 5# http://bash-completion.alioth.debian.org
6#******************************************************************* 6#*******************************************************************
7 7
8__interfaces(){ 8__interfaces() {
9 cut -f 1 -d ':' /proc/net/dev | tail -n +3 | grep -v lo | xargs 9 cut -f 1 -d ':' /proc/net/dev | tail -n +3 | grep -v lo | xargs
10} 10}
11 11
@@ -90,11 +90,11 @@ _firejail()
90 _filedir 90 _filedir
91 return 0 91 return 0
92 ;; 92 ;;
93 --net) 93 --net)
94 comps=$(__interfaces) 94 comps=$(__interfaces)
95 COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) 95 COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
96 return 0 96 return 0
97 ;; 97 ;;
98 esac 98 esac
99 99
100 $split && return 0 100 $split && return 0
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
index 31810de9a..f279af89f 100644
--- a/src/fcopy/main.c
+++ b/src/fcopy/main.c
@@ -88,7 +88,8 @@ static void selinux_relabel_path(const char *path, const char *inside_path) {
88 if (arg_debug) 88 if (arg_debug)
89 printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); 89 printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon);
90 90
91 setfilecon_raw(procfs_path, fcon); 91 if (setfilecon_raw(procfs_path, fcon) != 0 && arg_debug)
92 printf("Cannot relabel %s: %s\n", path, strerror(errno));
92 } 93 }
93 freecon(fcon); 94 freecon(fcon);
94 close: 95 close:
diff --git a/src/fids/fids.h b/src/fids/fids.h
index a2e2886fe..eaf2bbd29 100644
--- a/src/fids/fids.h
+++ b/src/fids/fids.h
@@ -48,4 +48,4 @@ int db_exclude_check(const char *fname);
48//#define KEY_SIZE 512 48//#define KEY_SIZE 512
49int blake2b(void *out, size_t outlen, const void *in, size_t inlen); 49int blake2b(void *out, size_t outlen, const void *in, size_t inlen);
50 50
51#endif \ No newline at end of file 51#endif
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index 698630180..a544e25f2 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -348,6 +348,7 @@ gnome-weather
348gnote 348gnote
349gnubik 349gnubik
350godot 350godot
351goldendict
351goobox 352goobox
352google-chrome 353google-chrome
353google-chrome-beta 354google-chrome-beta
diff --git a/src/firejail/env.c b/src/firejail/env.c
index f5e9dd980..ad16de037 100644
--- a/src/firejail/env.c
+++ b/src/firejail/env.c
@@ -262,7 +262,7 @@ static const char * const env_whitelist[] = {
262 "LANG", 262 "LANG",
263 "LANGUAGE", 263 "LANGUAGE",
264 "LC_MESSAGES", 264 "LC_MESSAGES",
265 "PATH", 265 // "PATH",
266 "DISPLAY" // required by X11 266 "DISPLAY" // required by X11
267}; 267};
268 268
@@ -311,6 +311,10 @@ void env_apply_whitelist(void) {
311 errExit("clearenv"); 311 errExit("clearenv");
312 312
313 env_apply_list(env_whitelist, ARRAY_SIZE(env_whitelist)); 313 env_apply_list(env_whitelist, ARRAY_SIZE(env_whitelist));
314
315 // hardcoding PATH
316 if (setenv("PATH", "/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin", 1) < 0)
317 errExit("setenv");
314} 318}
315 319
316// Filter env variables for a sbox app 320// Filter env variables for a sbox app
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 46985d89e..90cb2952b 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -563,7 +563,7 @@ typedef struct {
563 563
564// mountinfo.c 564// mountinfo.c
565MountData *get_last_mount(void); 565MountData *get_last_mount(void);
566int get_mount_id(const char *path); 566int get_mount_id(int fd);
567char **build_mount_array(const int mount_id, const char *path); 567char **build_mount_array(const int mount_id, const char *path);
568 568
569// fs_var.c 569// fs_var.c
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 5ac2da164..3144156a3 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -108,7 +108,7 @@ static void disable_file(OPERATION op, const char *filename) {
108 } 108 }
109 109
110 // check for firejail executable 110 // check for firejail executable
111 // we migth have a file found in ${PATH} pointing to /usr/bin/firejail 111 // we might have a file found in ${PATH} pointing to /usr/bin/firejail
112 // blacklisting it here will end up breaking situations like user clicks on a link in Thunderbird 112 // blacklisting it here will end up breaking situations like user clicks on a link in Thunderbird
113 // and expects Firefox to open in the same sandbox 113 // and expects Firefox to open in the same sandbox
114 if (strcmp(BINDIR "/firejail", fname) == 0) { 114 if (strcmp(BINDIR "/firejail", fname) == 0) {
@@ -200,8 +200,6 @@ static void disable_file(OPERATION op, const char *filename) {
200 } 200 }
201 201
202 fs_tmpfs(fname, uid); 202 fs_tmpfs(fname, uid);
203 EUID_USER(); // fs_tmpfs returns with EUID 0
204
205 selinux_relabel_path(fname, fname); 203 selinux_relabel_path(fname, fname);
206 } 204 }
207 else 205 else
@@ -282,6 +280,8 @@ static void globbing(OPERATION op, const char *pattern, const char *noblacklist[
282 280
283// blacklist files or directories by mounting empty files on top of them 281// blacklist files or directories by mounting empty files on top of them
284void fs_blacklist(void) { 282void fs_blacklist(void) {
283 EUID_ASSERT();
284
285 ProfileEntry *entry = cfg.profile; 285 ProfileEntry *entry = cfg.profile;
286 if (!entry) 286 if (!entry)
287 return; 287 return;
@@ -293,7 +293,6 @@ void fs_blacklist(void) {
293 if (noblacklist == NULL) 293 if (noblacklist == NULL)
294 errExit("failed allocating memory for noblacklist entries"); 294 errExit("failed allocating memory for noblacklist entries");
295 295
296 EUID_USER();
297 while (entry) { 296 while (entry) {
298 OPERATION op = OPERATION_MAX; 297 OPERATION op = OPERATION_MAX;
299 char *ptr; 298 char *ptr;
@@ -469,8 +468,6 @@ void fs_blacklist(void) {
469 for (i = 0; i < noblacklist_c; i++) 468 for (i = 0; i < noblacklist_c; i++)
470 free(noblacklist[i]); 469 free(noblacklist[i]);
471 free(noblacklist); 470 free(noblacklist);
472
473 EUID_ROOT();
474} 471}
475 472
476//*********************************************** 473//***********************************************
@@ -479,7 +476,7 @@ void fs_blacklist(void) {
479 476
480// mount a writable tmpfs on directory; requires a resolved path 477// mount a writable tmpfs on directory; requires a resolved path
481void fs_tmpfs(const char *dir, unsigned check_owner) { 478void fs_tmpfs(const char *dir, unsigned check_owner) {
482 EUID_USER(); 479 EUID_ASSERT();
483 assert(dir); 480 assert(dir);
484 if (arg_debug) 481 if (arg_debug)
485 printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no"); 482 printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no");
@@ -504,12 +501,13 @@ void fs_tmpfs(const char *dir, unsigned check_owner) {
504 errExit("fstatvfs"); 501 errExit("fstatvfs");
505 unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND|MS_REMOUNT); 502 unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND|MS_REMOUNT);
506 // mount via the symbolic link in /proc/self/fd 503 // mount via the symbolic link in /proc/self/fd
507 EUID_ROOT();
508 char *proc; 504 char *proc;
509 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 505 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
510 errExit("asprintf"); 506 errExit("asprintf");
507 EUID_ROOT();
511 if (mount("tmpfs", proc, "tmpfs", flags|MS_NOSUID|MS_NODEV, options) < 0) 508 if (mount("tmpfs", proc, "tmpfs", flags|MS_NOSUID|MS_NODEV, options) < 0)
512 errExit("mounting tmpfs"); 509 errExit("mounting tmpfs");
510 EUID_USER();
513 // check the last mount operation 511 // check the last mount operation
514 MountData *mdata = get_last_mount(); 512 MountData *mdata = get_last_mount();
515 if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, dir) != 0) 513 if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, dir) != 0)
@@ -635,34 +633,30 @@ out:
635} 633}
636 634
637// remount recursively; requires a resolved path 635// remount recursively; requires a resolved path
638static void fs_remount_rec(const char *dir, OPERATION op) { 636static void fs_remount_rec(const char *path, OPERATION op) {
639 EUID_ASSERT(); 637 EUID_ASSERT();
640 assert(dir); 638 assert(op < OPERATION_MAX);
639 assert(path);
641 640
642 struct stat s; 641 // no need to search /proc/self/mountinfo for submounts if not a directory
643 if (stat(dir, &s) != 0) 642 int fd = open(path, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
644 return; 643 if (fd < 0) {
645 if (!S_ISDIR(s.st_mode)) { 644 fs_remount_simple(path, op);
646 // no need to search in /proc/self/mountinfo for submounts if not a directory
647 fs_remount_simple(dir, op);
648 return; 645 return;
649 } 646 }
650 // get mount point of the directory 647
651 int mountid = get_mount_id(dir); 648 // get mount id of the directory
652 if (mountid == -1) 649 int mountid = get_mount_id(fd);
653 return; 650 close(fd);
654 if (mountid == -2) { 651 if (mountid < 0) {
655 // falling back to a simple remount on old kernels 652 // falling back to a simple remount
656 static int mount_warning = 0; 653 fwarning("%s %s not applied recursively\n", opstr[op], path);
657 if (!mount_warning) { 654 fs_remount_simple(path, op);
658 fwarning("read-only, read-write and noexec options are not applied recursively\n");
659 mount_warning = 1;
660 }
661 fs_remount_simple(dir, op);
662 return; 655 return;
663 } 656 }
657
664 // build array with all mount points that need to get remounted 658 // build array with all mount points that need to get remounted
665 char **arr = build_mount_array(mountid, dir); 659 char **arr = build_mount_array(mountid, path);
666 assert(arr); 660 assert(arr);
667 // remount 661 // remount
668 char **tmp = arr; 662 char **tmp = arr;
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index 8cc3ecc62..a43b18344 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -330,8 +330,10 @@ void fs_dev_disable_sound(void) {
330 } 330 }
331 331
332 // disable all jack sockets in /dev/shm 332 // disable all jack sockets in /dev/shm
333 EUID_USER();
333 glob_t globbuf; 334 glob_t globbuf;
334 int globerr = glob("/dev/shm/jack*", GLOB_NOSORT, NULL, &globbuf); 335 int globerr = glob("/dev/shm/jack*", GLOB_NOSORT, NULL, &globbuf);
336 EUID_ROOT();
335 if (globerr) 337 if (globerr)
336 return; 338 return;
337 339
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 0ed476063..590337da1 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -395,14 +395,16 @@ void fs_private(void) {
395 } 395 }
396 if (chown(homedir, u, g) < 0) 396 if (chown(homedir, u, g) < 0)
397 errExit("chown"); 397 errExit("chown");
398
399 fs_logger2("mkdir", homedir); 398 fs_logger2("mkdir", homedir);
400 fs_logger2("tmpfs", homedir); 399 fs_logger2("tmpfs", homedir);
401 } 400 }
402 else 401 else {
403 // mask user home directory 402 // mask user home directory
404 // the directory should be owned by the current user 403 // the directory should be owned by the current user
404 EUID_USER();
405 fs_tmpfs(homedir, 1); 405 fs_tmpfs(homedir, 1);
406 EUID_ROOT();
407 }
406 408
407 selinux_relabel_path(homedir, homedir); 409 selinux_relabel_path(homedir, homedir);
408 } 410 }
@@ -564,12 +566,13 @@ void fs_private_home_list(void) {
564 int xflag = store_xauthority(); 566 int xflag = store_xauthority();
565 int aflag = store_asoundrc(); 567 int aflag = store_asoundrc();
566 568
567 // create /run/firejail/mnt/home directory
568 EUID_ROOT(); 569 EUID_ROOT();
570 // create /run/firejail/mnt/home directory
569 mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); 571 mkdir_attr(RUN_HOME_DIR, 0755, uid, gid);
570 selinux_relabel_path(RUN_HOME_DIR, homedir); 572 selinux_relabel_path(RUN_HOME_DIR, homedir);
571 573
572 fs_logger_print(); // save the current log 574 // save the current log
575 fs_logger_print();
573 EUID_USER(); 576 EUID_USER();
574 577
575 // copy the list of files in the new home directory 578 // copy the list of files in the new home directory
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c
index 1a9a78ceb..7d320e90b 100644
--- a/src/firejail/fs_hostname.c
+++ b/src/firejail/fs_hostname.c
@@ -93,10 +93,6 @@ char *fs_check_hosts_file(const char *fname) {
93 invalid_filename(fname, 0); // no globbing 93 invalid_filename(fname, 0); // no globbing
94 char *rv = expand_macros(fname); 94 char *rv = expand_macros(fname);
95 95
96 // no a link
97 if (is_link(rv))
98 goto errexit;
99
100 // the user has read access to the file 96 // the user has read access to the file
101 if (access(rv, R_OK)) 97 if (access(rv, R_OK))
102 goto errexit; 98 goto errexit;
@@ -119,9 +115,6 @@ void fs_mount_hosts_file(void) {
119 struct stat s; 115 struct stat s;
120 if (stat("/etc/hosts", &s) == -1) 116 if (stat("/etc/hosts", &s) == -1)
121 goto errexit; 117 goto errexit;
122 // not a link
123 if (is_link("/etc/hosts"))
124 goto errexit;
125 // owned by root 118 // owned by root
126 if (s.st_uid != 0) 119 if (s.st_uid != 0)
127 goto errexit; 120 goto errexit;
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c
index 9d7a17cf3..848c186fa 100644
--- a/src/firejail/fs_lib.c
+++ b/src/firejail/fs_lib.c
@@ -195,6 +195,11 @@ void fslib_mount_libs(const char *full_path, unsigned user) {
195 assert(full_path); 195 assert(full_path);
196 // if library/executable does not exist or the user does not have read access to it 196 // if library/executable does not exist or the user does not have read access to it
197 // print a warning and exit the function. 197 // print a warning and exit the function.
198 if (access(full_path, F_OK)) {
199 if (arg_debug || arg_debug_private_lib)
200 printf("Cannot find %s, skipping...\n", full_path);
201 return;
202 }
198 if (user && access(full_path, R_OK)) { 203 if (user && access(full_path, R_OK)) {
199 if (arg_debug || arg_debug_private_lib) 204 if (arg_debug || arg_debug_private_lib)
200 printf("Cannot read %s, skipping...\n", full_path); 205 printf("Cannot read %s, skipping...\n", full_path);
diff --git a/src/firejail/fs_lib2.c b/src/firejail/fs_lib2.c
index c69bf7c98..a347b380c 100644
--- a/src/firejail/fs_lib2.c
+++ b/src/firejail/fs_lib2.c
@@ -143,7 +143,7 @@ static void fdir(void) {
143 NULL, 143 NULL,
144 }; 144 };
145 145
146 // need to parse as root user, unprivileged users have no read permission on executables 146 // need to parse as root user, unprivileged users have no read permission on some of these binaries
147 int i; 147 int i;
148 for (i = 0; fbin[i]; i++) 148 for (i = 0; fbin[i]; i++)
149 fslib_mount_libs(fbin[i], 0); 149 fslib_mount_libs(fbin[i], 0);
@@ -153,7 +153,9 @@ void fslib_install_firejail(void) {
153 timetrace_start(); 153 timetrace_start();
154 // bring in firejail executable libraries, in case we are redirected here 154 // bring in firejail executable libraries, in case we are redirected here
155 // by a firejail symlink from /usr/local/bin/firejail 155 // by a firejail symlink from /usr/local/bin/firejail
156 fslib_mount_libs(PATH_FIREJAIL, 1); // parse as user 156 // fldd might have no read permission on the firejail executable
157 // parse as root in order to support these setups
158 fslib_mount_libs(PATH_FIREJAIL, 0);
157 159
158 // bring in firejail directory 160 // bring in firejail directory
159 fdir(); 161 fdir();
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index 943f275de..7afebed1f 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -105,6 +105,7 @@ static int whitelist_mkpath(const char* path, mode_t mode) {
105} 105}
106 106
107static void whitelist_file(int dirfd, const char *relpath, const char *path) { 107static void whitelist_file(int dirfd, const char *relpath, const char *path) {
108 EUID_ASSERT();
108 assert(relpath && path); 109 assert(relpath && path);
109 110
110 // open mount source, using a file descriptor that refers to the 111 // open mount source, using a file descriptor that refers to the
@@ -130,12 +131,9 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) {
130 } 131 }
131 132
132 // create mount target as root, except if inside home or run/user/$UID directory 133 // create mount target as root, except if inside home or run/user/$UID directory
133 int userprivs = 0; 134 if ((strncmp(path, cfg.homedir, homedir_len) != 0 || path[homedir_len] != '/') &&
134 if ((strncmp(path, cfg.homedir, homedir_len) == 0 && path[homedir_len] == '/') || 135 (strncmp(path, runuser, runuser_len) != 0 || path[runuser_len] != '/'))
135 (strncmp(path, runuser, runuser_len) == 0 && path[runuser_len] == '/')) { 136 EUID_ROOT();
136 EUID_USER();
137 userprivs = 1;
138 }
139 137
140 // create path of the mount target 138 // create path of the mount target
141 int fd2 = whitelist_mkpath(path, 0755); 139 int fd2 = whitelist_mkpath(path, 0755);
@@ -146,8 +144,7 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) {
146 if (arg_debug || arg_debug_whitelists) 144 if (arg_debug || arg_debug_whitelists)
147 printf("Debug %d: skip whitelist %s\n", __LINE__, path); 145 printf("Debug %d: skip whitelist %s\n", __LINE__, path);
148 close(fd); 146 close(fd);
149 if (userprivs) 147 EUID_USER();
150 EUID_ROOT();
151 return; 148 return;
152 } 149 }
153 150
@@ -166,8 +163,7 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) {
166 } 163 }
167 close(fd); 164 close(fd);
168 close(fd2); 165 close(fd2);
169 if (userprivs) 166 EUID_USER();
170 EUID_ROOT();
171 return; 167 return;
172 } 168 }
173 fd3 = openat(fd2, file, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 169 fd3 = openat(fd2, file, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
@@ -184,19 +180,17 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) {
184 } 180 }
185 close(fd); 181 close(fd);
186 close(fd2); 182 close(fd2);
187 if (userprivs) 183 EUID_USER();
188 EUID_ROOT();
189 return; 184 return;
190 } 185 }
191
192 close(fd2); 186 close(fd2);
193 if (userprivs)
194 EUID_ROOT();
195 187
196 if (arg_debug || arg_debug_whitelists) 188 if (arg_debug || arg_debug_whitelists)
197 printf("Whitelisting %s\n", path); 189 printf("Whitelisting %s\n", path);
190 EUID_ROOT();
198 if (bind_mount_by_fd(fd, fd3)) 191 if (bind_mount_by_fd(fd, fd3))
199 errExit("mount bind"); 192 errExit("mount bind");
193 EUID_USER();
200 // check the last mount operation 194 // check the last mount operation
201 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found 195 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found
202#ifdef TEST_MOUNTINFO 196#ifdef TEST_MOUNTINFO
@@ -219,22 +213,19 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) {
219} 213}
220 214
221static void whitelist_symlink(const char *link, const char *target) { 215static void whitelist_symlink(const char *link, const char *target) {
216 EUID_ASSERT();
222 assert(link && target); 217 assert(link && target);
223 218
224 // create files as root, except if inside home or run/user/$UID directory 219 // create files as root, except if inside home or run/user/$UID directory
225 int userprivs = 0; 220 if ((strncmp(link, cfg.homedir, homedir_len) != 0 || link[homedir_len] != '/') &&
226 if ((strncmp(link, cfg.homedir, homedir_len) == 0 && link[homedir_len] == '/') || 221 (strncmp(link, runuser, runuser_len) != 0 || link[runuser_len] != '/'))
227 (strncmp(link, runuser, runuser_len) == 0 && link[runuser_len] == '/')) { 222 EUID_ROOT();
228 EUID_USER();
229 userprivs = 1;
230 }
231 223
232 int fd = whitelist_mkpath(link, 0755); 224 int fd = whitelist_mkpath(link, 0755);
233 if (fd == -1) { 225 if (fd == -1) {
234 if (arg_debug || arg_debug_whitelists) 226 if (arg_debug || arg_debug_whitelists)
235 printf("Debug %d: cannot create symbolic link %s\n", __LINE__, link); 227 printf("Debug %d: cannot create symbolic link %s\n", __LINE__, link);
236 if (userprivs) 228 EUID_USER();
237 EUID_ROOT();
238 return; 229 return;
239 } 230 }
240 231
@@ -252,8 +243,7 @@ static void whitelist_symlink(const char *link, const char *target) {
252 printf("Created symbolic link %s -> %s\n", link, target); 243 printf("Created symbolic link %s -> %s\n", link, target);
253 244
254 close(fd); 245 close(fd);
255 if (userprivs) 246 EUID_USER();
256 EUID_ROOT();
257} 247}
258 248
259static void globbing(const char *pattern) { 249static void globbing(const char *pattern) {
@@ -330,10 +320,11 @@ static void tmpfs_topdirs(const TopDir *topdirs) {
330 // init tmpfs 320 // init tmpfs
331 if (strcmp(topdirs[i].path, "/run") == 0) { 321 if (strcmp(topdirs[i].path, "/run") == 0) {
332 // restore /run/firejail directory 322 // restore /run/firejail directory
333 if (mkdir(RUN_FIREJAIL_DIR, 0755) == -1) 323 EUID_ROOT();
334 errExit("mkdir"); 324 mkdir_attr(RUN_FIREJAIL_DIR, 0755, 0, 0);
335 if (bind_mount_fd_to_path(fd, RUN_FIREJAIL_DIR)) 325 if (bind_mount_fd_to_path(fd, RUN_FIREJAIL_DIR))
336 errExit("mount bind"); 326 errExit("mount bind");
327 EUID_USER();
337 close(fd); 328 close(fd);
338 fs_logger2("whitelist", RUN_FIREJAIL_DIR); 329 fs_logger2("whitelist", RUN_FIREJAIL_DIR);
339 330
@@ -351,12 +342,14 @@ static void tmpfs_topdirs(const TopDir *topdirs) {
351 errExit("asprintf"); 342 errExit("asprintf");
352 if (strcmp(env, pamtmpdir) == 0) { 343 if (strcmp(env, pamtmpdir) == 0) {
353 // create empty user-owned /tmp/user/$UID directory 344 // create empty user-owned /tmp/user/$UID directory
345 EUID_ROOT();
354 mkdir_attr("/tmp/user", 0711, 0, 0); 346 mkdir_attr("/tmp/user", 0711, 0, 0);
355 selinux_relabel_path("/tmp/user", "/tmp/user"); 347 selinux_relabel_path("/tmp/user", "/tmp/user");
356 fs_logger("mkdir /tmp/user"); 348 fs_logger("mkdir /tmp/user");
357 mkdir_attr(pamtmpdir, 0700, getuid(), 0); 349 mkdir_attr(pamtmpdir, 0700, getuid(), 0);
358 selinux_relabel_path(pamtmpdir, pamtmpdir); 350 selinux_relabel_path(pamtmpdir, pamtmpdir);
359 fs_logger2("mkdir", pamtmpdir); 351 fs_logger2("mkdir", pamtmpdir);
352 EUID_USER();
360 } 353 }
361 free(pamtmpdir); 354 free(pamtmpdir);
362 } 355 }
@@ -374,11 +367,8 @@ static void tmpfs_topdirs(const TopDir *topdirs) {
374 } 367 }
375 368
376 // user home directory 369 // user home directory
377 if (tmpfs_home) { 370 if (tmpfs_home)
378 EUID_USER();
379 fs_private(); // checks owner if outside /home 371 fs_private(); // checks owner if outside /home
380 EUID_ROOT();
381 }
382 372
383 // /run/user/$UID directory 373 // /run/user/$UID directory
384 if (tmpfs_runuser) { 374 if (tmpfs_runuser) {
@@ -402,6 +392,7 @@ static int reject_topdir(const char *dir) {
402// keep track of whitelist top level directories by adding them to an array 392// keep track of whitelist top level directories by adding them to an array
403// open each directory 393// open each directory
404static TopDir *add_topdir(const char *dir, TopDir *topdirs, const char *path) { 394static TopDir *add_topdir(const char *dir, TopDir *topdirs, const char *path) {
395 EUID_ASSERT();
405 assert(dir && path); 396 assert(dir && path);
406 397
407 // /proc and /sys are not allowed 398 // /proc and /sys are not allowed
@@ -516,6 +507,8 @@ static char *extract_topdir(const char *path) {
516} 507}
517 508
518void fs_whitelist(void) { 509void fs_whitelist(void) {
510 EUID_ASSERT();
511
519 ProfileEntry *entry = cfg.profile; 512 ProfileEntry *entry = cfg.profile;
520 if (!entry) 513 if (!entry)
521 return; 514 return;
@@ -536,7 +529,6 @@ void fs_whitelist(void) {
536 errExit("calloc"); 529 errExit("calloc");
537 530
538 // verify whitelist files, extract symbolic links, etc. 531 // verify whitelist files, extract symbolic links, etc.
539 EUID_USER();
540 while (entry) { 532 while (entry) {
541 int nowhitelist_flag = 0; 533 int nowhitelist_flag = 0;
542 534
@@ -630,7 +622,7 @@ void fs_whitelist(void) {
630 if (!fname) { 622 if (!fname) {
631 if (arg_debug || arg_debug_whitelists) { 623 if (arg_debug || arg_debug_whitelists) {
632 printf("Removed path: %s\n", entry->data); 624 printf("Removed path: %s\n", entry->data);
633 printf("\texpanded: %s\n", new_name); 625 printf("\tnew_name: %s\n", new_name);
634 printf("\trealpath: (null)\n"); 626 printf("\trealpath: (null)\n");
635 printf("\t%s\n", strerror(errno)); 627 printf("\t%s\n", strerror(errno));
636 } 628 }
@@ -712,7 +704,6 @@ void fs_whitelist(void) {
712 free(nowhitelist); 704 free(nowhitelist);
713 705
714 // mount tmpfs on all top level directories 706 // mount tmpfs on all top level directories
715 EUID_ROOT();
716 tmpfs_topdirs(topdirs); 707 tmpfs_topdirs(topdirs);
717 708
718 // go through profile rules again, and interpret whitelist commands 709 // go through profile rules again, and interpret whitelist commands
diff --git a/src/firejail/ids.c b/src/firejail/ids.c
index 59acdb1fe..a9ff59be4 100644
--- a/src/firejail/ids.c
+++ b/src/firejail/ids.c
@@ -86,4 +86,4 @@ void run_ids(int argc, char **argv) {
86 fprintf(stderr, "Error: unrecognized IDS command\n"); 86 fprintf(stderr, "Error: unrecognized IDS command\n");
87 87
88 exit(0); 88 exit(0);
89} \ No newline at end of file 89}
diff --git a/src/firejail/join.c b/src/firejail/join.c
index 394bbb528..a869f6b64 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -45,7 +45,7 @@ static unsigned display = 0;
45static void signal_handler(int sig){ 45static void signal_handler(int sig){
46 flush_stdin(); 46 flush_stdin();
47 47
48 exit(sig); 48 exit(128 + sig);
49} 49}
50 50
51static void install_handler(void) { 51static void install_handler(void) {
@@ -536,7 +536,6 @@ void join(pid_t pid, int argc, char **argv, int index) {
536 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); 536 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
537 537
538#ifdef HAVE_APPARMOR 538#ifdef HAVE_APPARMOR
539 // add apparmor confinement after the execve
540 set_apparmor(); 539 set_apparmor();
541#endif 540#endif
542 541
@@ -552,10 +551,6 @@ void join(pid_t pid, int argc, char **argv, int index) {
552 if (cfg.cpus) // not available for uid 0 551 if (cfg.cpus) // not available for uid 0
553 set_cpu_affinity(); 552 set_cpu_affinity();
554 553
555 // set nice value
556 if (arg_nice)
557 set_nice(cfg.nice);
558
559 // add x11 display 554 // add x11 display
560 if (display) { 555 if (display) {
561 char *display_str; 556 char *display_str;
@@ -574,6 +569,11 @@ void join(pid_t pid, int argc, char **argv, int index) {
574 dbus_set_system_bus_env(); 569 dbus_set_system_bus_env();
575#endif 570#endif
576 571
572 // set nice and rlimits
573 if (arg_nice)
574 set_nice(cfg.nice);
575 set_rlimits();
576
577 start_application(0, shfd, NULL); 577 start_application(0, shfd, NULL);
578 578
579 __builtin_unreachable(); 579 __builtin_unreachable();
@@ -596,15 +596,17 @@ void join(pid_t pid, int argc, char **argv, int index) {
596 596
597 // end of signal-safe code 597 // end of signal-safe code
598 //***************************** 598 //*****************************
599 flush_stdin();
600 599
601 if (WIFEXITED(status)) { 600 if (WIFEXITED(status)) {
601 // if we had a proper exit, return that exit status
602 status = WEXITSTATUS(status); 602 status = WEXITSTATUS(status);
603 } else if (WIFSIGNALED(status)) { 603 } else if (WIFSIGNALED(status)) {
604 status = WTERMSIG(status); 604 // distinguish fatal signals by adding 128
605 status = 128 + WTERMSIG(status);
605 } else { 606 } else {
606 status = 0; 607 status = -1;
607 } 608 }
608 609
610 flush_stdin();
609 exit(status); 611 exit(status);
610} 612}
diff --git a/src/firejail/main.c b/src/firejail/main.c
index e0bf44f62..81d148257 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -189,13 +189,15 @@ static void my_handler(int s) {
189 logsignal(s); 189 logsignal(s);
190 190
191 if (waitpid(child, NULL, WNOHANG) == 0) { 191 if (waitpid(child, NULL, WNOHANG) == 0) {
192 if (has_handler(child, s)) // signals are not delivered if there is no handler yet 192 // child is pid 1 of a pid namespace:
193 // signals are not delivered if there is no handler yet
194 if (has_handler(child, s))
193 kill(child, s); 195 kill(child, s);
194 else 196 else
195 kill(child, SIGKILL); 197 kill(child, SIGKILL);
196 waitpid(child, NULL, 0); 198 waitpid(child, NULL, 0);
197 } 199 }
198 myexit(s); 200 myexit(128 + s);
199} 201}
200 202
201static void install_handler(void) { 203static void install_handler(void) {
@@ -1263,9 +1265,9 @@ int main(int argc, char **argv, char **envp) {
1263 arg_debug = 1; 1265 arg_debug = 1;
1264 arg_quiet = 0; 1266 arg_quiet = 0;
1265 } 1267 }
1266 else if (strcmp(argv[i], "--debug-deny") == 0) 1268 else if (strcmp(argv[i], "--debug-blacklists") == 0)
1267 arg_debug_blacklists = 1; 1269 arg_debug_blacklists = 1;
1268 else if (strcmp(argv[i], "--debug-allow") == 0) 1270 else if (strcmp(argv[i], "--debug-whitelists") == 0)
1269 arg_debug_whitelists = 1; 1271 arg_debug_whitelists = 1;
1270 else if (strcmp(argv[i], "--debug-private-lib") == 0) 1272 else if (strcmp(argv[i], "--debug-private-lib") == 0)
1271 arg_debug_private_lib = 1; 1273 arg_debug_private_lib = 1;
@@ -3216,10 +3218,11 @@ printf("link #%s#\n", prf->link);
3216 if (WIFEXITED(status)){ 3218 if (WIFEXITED(status)){
3217 myexit(WEXITSTATUS(status)); 3219 myexit(WEXITSTATUS(status));
3218 } else if (WIFSIGNALED(status)) { 3220 } else if (WIFSIGNALED(status)) {
3219 myexit(WTERMSIG(status)); 3221 // distinguish fatal signals by adding 128
3222 myexit(128 + WTERMSIG(status));
3220 } else { 3223 } else {
3221 myexit(0); 3224 myexit(1);
3222 } 3225 }
3223 3226
3224 return 0; 3227 return 1;
3225} 3228}
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c
index 64a94bd84..304f80eee 100644
--- a/src/firejail/mountinfo.c
+++ b/src/firejail/mountinfo.c
@@ -19,6 +19,7 @@
19*/ 19*/
20 20
21#include "firejail.h" 21#include "firejail.h"
22#include <errno.h>
22 23
23#include <fcntl.h> 24#include <fcntl.h>
24#ifndef O_PATH 25#ifndef O_PATH
@@ -151,53 +152,71 @@ MountData *get_last_mount(void) {
151 return &mdata; 152 return &mdata;
152} 153}
153 154
154// Extract the mount id from /proc/self/fdinfo and return it. 155// Returns mount id, or -1 if fd refers to a procfs or sysfs file
155int get_mount_id(const char *path) { 156static int get_mount_id_from_handle(int fd) {
156 EUID_ASSERT(); 157 EUID_ASSERT();
157 assert(path);
158 158
159 int fd = open(path, O_PATH|O_CLOEXEC); 159 char *proc;
160 if (fd == -1) 160 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
161 return -1; 161 errExit("asprintf");
162 struct file_handle *fh = malloc(sizeof *fh);
163 if (!fh)
164 errExit("malloc");
165 fh->handle_bytes = 0;
166
167 int rv = -1;
168 int tmp;
169 if (name_to_handle_at(-1, proc, fh, &tmp, AT_SYMLINK_FOLLOW) != -1) {
170 fprintf(stderr, "Error: unexpected result from name_to_handle_at\n");
171 exit(1);
172 }
173 if (errno == EOVERFLOW && fh->handle_bytes)
174 rv = tmp;
175
176 free(proc);
177 free(fh);
178 return rv;
179}
180
181// Returns mount id, or -1 on kernels < 3.15
182static int get_mount_id_from_fdinfo(int fd) {
183 EUID_ASSERT();
184 int rv = -1;
162 185
163 char *fdinfo; 186 char *proc;
164 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) 187 if (asprintf(&proc, "/proc/self/fdinfo/%d", fd) == -1)
165 errExit("asprintf"); 188 errExit("asprintf");
166 EUID_ROOT(); 189 EUID_ROOT();
167 FILE *fp = fopen(fdinfo, "re"); 190 FILE *fp = fopen(proc, "re");
168 EUID_USER(); 191 EUID_USER();
169 free(fdinfo);
170 if (!fp) 192 if (!fp)
171 goto errexit; 193 goto errexit;
172 194
173 // read the file
174 char buf[MAX_BUF]; 195 char buf[MAX_BUF];
175 if (fgets(buf, MAX_BUF, fp) == NULL) 196 while (fgets(buf, MAX_BUF, fp)) {
176 goto errexit;
177 do {
178 if (strncmp(buf, "mnt_id:", 7) == 0) { 197 if (strncmp(buf, "mnt_id:", 7) == 0) {
179 char *ptr = buf + 7; 198 if (sscanf(buf + 7, "%d", &rv) != 1)
180 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
181 ptr++;
182 }
183 if (*ptr == '\0')
184 goto errexit; 199 goto errexit;
185 fclose(fp); 200 break;
186 close(fd);
187 return atoi(ptr);
188 } 201 }
189 } while (fgets(buf, MAX_BUF, fp)); 202 }
190 203
191 // fallback, kernels older than 3.15 don't expose the mount id in this place 204 free(proc);
192 fclose(fp); 205 fclose(fp);
193 close(fd); 206 return rv;
194 return -2;
195 207
196errexit: 208errexit:
197 fprintf(stderr, "Error: cannot read proc file\n"); 209 fprintf(stderr, "Error: cannot read proc file\n");
198 exit(1); 210 exit(1);
199} 211}
200 212
213int get_mount_id(int fd) {
214 int rv = get_mount_id_from_fdinfo(fd);
215 if (rv < 0)
216 rv = get_mount_id_from_handle(fd);
217 return rv;
218}
219
201// Check /proc/self/mountinfo if path contains any mounts points. 220// Check /proc/self/mountinfo if path contains any mounts points.
202// Returns an array that can be iterated over for recursive remounting. 221// Returns an array that can be iterated over for recursive remounting.
203char **build_mount_array(const int mount_id, const char *path) { 222char **build_mount_array(const int mount_id, const char *path) {
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 7c7c7a025..5390249ea 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -635,7 +635,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
635#endif 635#endif
636 return 0; 636 return 0;
637 } 637 }
638 else if (strncmp(ptr, "netns ", 6) == 0) { 638 else if (strncmp(ptr, "netns ", 6) == 0) {
639#ifdef HAVE_NETWORK 639#ifdef HAVE_NETWORK
640 if (checkcfg(CFG_NETWORK)) { 640 if (checkcfg(CFG_NETWORK)) {
641 arg_netns = ptr + 6; 641 arg_netns = ptr + 6;
@@ -986,10 +986,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
986 warning_feature_disabled("seccomp"); 986 warning_feature_disabled("seccomp");
987 return 0; 987 return 0;
988 } 988 }
989 if (strncmp(ptr, "seccomp.32.drop ", 13) == 0) { 989 if (strncmp(ptr, "seccomp.32.drop ", 16) == 0) {
990 if (checkcfg(CFG_SECCOMP)) { 990 if (checkcfg(CFG_SECCOMP)) {
991 arg_seccomp32 = 1; 991 arg_seccomp32 = 1;
992 cfg.seccomp_list_drop32 = seccomp_check_list(ptr + 13); 992 cfg.seccomp_list_drop32 = seccomp_check_list(ptr + 16);
993 } 993 }
994 else 994 else
995 warning_feature_disabled("seccomp"); 995 warning_feature_disabled("seccomp");
@@ -1006,10 +1006,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1006 warning_feature_disabled("seccomp"); 1006 warning_feature_disabled("seccomp");
1007 return 0; 1007 return 0;
1008 } 1008 }
1009 if (strncmp(ptr, "seccomp.32.keep ", 13) == 0) { 1009 if (strncmp(ptr, "seccomp.32.keep ", 16) == 0) {
1010 if (checkcfg(CFG_SECCOMP)) { 1010 if (checkcfg(CFG_SECCOMP)) {
1011 arg_seccomp32 = 1; 1011 arg_seccomp32 = 1;
1012 cfg.seccomp_list_keep32 = seccomp_check_list(ptr + 13); 1012 cfg.seccomp_list_keep32 = seccomp_check_list(ptr + 16);
1013 } 1013 }
1014 else 1014 else
1015 warning_feature_disabled("seccomp"); 1015 warning_feature_disabled("seccomp");
@@ -1943,7 +1943,7 @@ char *profile_list_compress(char *list)
1943 /* Include non-empty item */ 1943 /* Include non-empty item */
1944 if (!*item) 1944 if (!*item)
1945 in[i] = 0; 1945 in[i] = 0;
1946 /* Remove all allready included items */ 1946 /* Remove all already included items */
1947 for (k = 0; k < i; ++k) 1947 for (k = 0; k < i; ++k)
1948 in[k] = 0; 1948 in[k] = 0;
1949 break; 1949 break;
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 59ddfb855..83e50aee2 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -87,9 +87,9 @@ static void sandbox_handler(int sig){
87 87
88 // broadcast a SIGKILL 88 // broadcast a SIGKILL
89 kill(-1, SIGKILL); 89 kill(-1, SIGKILL);
90 flush_stdin();
91 90
92 exit(sig); 91 flush_stdin();
92 exit(128 + sig);
93} 93}
94 94
95static void install_handler(void) { 95static void install_handler(void) {
@@ -1004,10 +1004,12 @@ int sandbox(void* sandbox_arg) {
1004 // apply the profile file 1004 // apply the profile file
1005 //**************************** 1005 //****************************
1006 // apply all whitelist commands ... 1006 // apply all whitelist commands ...
1007 EUID_USER();
1007 fs_whitelist(); 1008 fs_whitelist();
1008 1009
1009 // ... followed by blacklist commands 1010 // ... followed by blacklist commands
1010 fs_blacklist(); // mkdir and mkfile are processed all over again 1011 fs_blacklist(); // mkdir and mkfile are processed all over again
1012 EUID_ROOT();
1011 1013
1012 //**************************** 1014 //****************************
1013 // nosound/no3d/notv/novideo and fix for pulseaudio 7.0 1015 // nosound/no3d/notv/novideo and fix for pulseaudio 7.0
@@ -1243,7 +1245,6 @@ int sandbox(void* sandbox_arg) {
1243 1245
1244 if (app_pid == 0) { 1246 if (app_pid == 0) {
1245#ifdef HAVE_APPARMOR 1247#ifdef HAVE_APPARMOR
1246 // add apparmor confinement after the execve
1247 set_apparmor(); 1248 set_apparmor();
1248#endif 1249#endif
1249 1250
@@ -1258,13 +1259,17 @@ int sandbox(void* sandbox_arg) {
1258 munmap(set_sandbox_status, 1); 1259 munmap(set_sandbox_status, 1);
1259 1260
1260 int status = monitor_application(app_pid); // monitor application 1261 int status = monitor_application(app_pid); // monitor application
1261 flush_stdin();
1262 1262
1263 if (WIFEXITED(status)) { 1263 if (WIFEXITED(status)) {
1264 // if we had a proper exit, return that exit status 1264 // if we had a proper exit, return that exit status
1265 return WEXITSTATUS(status); 1265 status = WEXITSTATUS(status);
1266 } else if (WIFSIGNALED(status)) {
1267 // distinguish fatal signals by adding 128
1268 status = 128 + WTERMSIG(status);
1266 } else { 1269 } else {
1267 // something else went wrong! 1270 status = -1;
1268 return -1;
1269 } 1271 }
1272
1273 flush_stdin();
1274 return status;
1270} 1275}
diff --git a/src/firejail/selinux.c b/src/firejail/selinux.c
index 6969e7a3d..fa59882ed 100644
--- a/src/firejail/selinux.c
+++ b/src/firejail/selinux.c
@@ -21,6 +21,7 @@
21#include "firejail.h" 21#include "firejail.h"
22#include <sys/types.h> 22#include <sys/types.h>
23#include <sys/stat.h> 23#include <sys/stat.h>
24#include <errno.h>
24 25
25#include <fcntl.h> 26#include <fcntl.h>
26#ifndef O_PATH 27#ifndef O_PATH
@@ -57,7 +58,17 @@ void selinux_relabel_path(const char *path, const char *inside_path)
57 58
58 /* Open the file as O_PATH, to pin it while we determine and adjust the label 59 /* Open the file as O_PATH, to pin it while we determine and adjust the label
59 * Defeat symlink races by not allowing symbolic links */ 60 * Defeat symlink races by not allowing symbolic links */
61 int called_as_root = 0;
62 if (geteuid() == 0)
63 called_as_root = 1;
64 if (called_as_root)
65 EUID_USER();
66
60 fd = safer_openat(-1, path, O_NOFOLLOW|O_CLOEXEC|O_PATH); 67 fd = safer_openat(-1, path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
68
69 if (called_as_root)
70 EUID_ROOT();
71
61 if (fd < 0) 72 if (fd < 0)
62 return; 73 return;
63 if (fstat(fd, &st) < 0) 74 if (fstat(fd, &st) < 0)
@@ -68,8 +79,16 @@ void selinux_relabel_path(const char *path, const char *inside_path)
68 if (arg_debug) 79 if (arg_debug)
69 printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); 80 printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon);
70 81
71 setfilecon_raw(procfs_path, fcon); 82 if (!called_as_root)
83 EUID_ROOT();
84
85 if (setfilecon_raw(procfs_path, fcon) != 0 && arg_debug)
86 printf("Cannot relabel %s: %s\n", path, strerror(errno));
87
88 if (!called_as_root)
89 EUID_USER();
72 } 90 }
91
73 freecon(fcon); 92 freecon(fcon);
74 close: 93 close:
75 close(fd); 94 close(fd);
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index d843c74ae..43f862b9d 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -28,7 +28,6 @@ static char *usage_str =
28 "\n" 28 "\n"
29 "Options:\n" 29 "Options:\n"
30 " -- - signal the end of options and disables further option processing.\n" 30 " -- - signal the end of options and disables further option processing.\n"
31 " --allow=filename - allow file system access.\n"
32 " --allow-debuggers - allow tools such as strace and gdb inside the sandbox.\n" 31 " --allow-debuggers - allow tools such as strace and gdb inside the sandbox.\n"
33 " --allusers - all user home directories are visible inside the sandbox.\n" 32 " --allusers - all user home directories are visible inside the sandbox.\n"
34 " --apparmor - enable AppArmor confinement.\n" 33 " --apparmor - enable AppArmor confinement.\n"
@@ -39,12 +38,13 @@ static char *usage_str =
39#endif 38#endif
40 " --bind=dirname1,dirname2 - mount-bind dirname1 on top of dirname2.\n" 39 " --bind=dirname1,dirname2 - mount-bind dirname1 on top of dirname2.\n"
41 " --bind=filename1,filename2 - mount-bind filename1 on top of filename2.\n" 40 " --bind=filename1,filename2 - mount-bind filename1 on top of filename2.\n"
42 " --build - build a profile for the application.\n" 41 " --blacklist=filename - blacklist directory or file.\n"
43 " --build=filename - build a profile for the application.\n" 42 " --build - build a whitelisted profile for the application.\n"
43 " --build=filename - build a whitelisted profile for the application.\n"
44 " --caps - enable default Linux capabilities filter.\n" 44 " --caps - enable default Linux capabilities filter.\n"
45 " --caps.drop=all - drop all capabilities.\n" 45 " --caps.drop=all - drop all capabilities.\n"
46 " --caps.drop=capability,capability - drop capabilities.\n" 46 " --caps.drop=capability,capability - blacklist capabilities filter.\n"
47 " --caps.keep=capability,capability - allow capabilities.\n" 47 " --caps.keep=capability,capability - whitelist capabilities filter.\n"
48 " --caps.print=name|pid - print the caps filter.\n" 48 " --caps.print=name|pid - print the caps filter.\n"
49#ifdef HAVE_FILE_TRANSFER 49#ifdef HAVE_FILE_TRANSFER
50 " --cat=name|pid filename - print content of file from sandbox container.\n" 50 " --cat=name|pid filename - print content of file from sandbox container.\n"
@@ -75,18 +75,17 @@ static char *usage_str =
75 " --dbus-user.talk=name - allow talking to name on the session DBus.\n" 75 " --dbus-user.talk=name - allow talking to name on the session DBus.\n"
76#endif 76#endif
77 " --debug - print sandbox debug messages.\n" 77 " --debug - print sandbox debug messages.\n"
78 " --debug-allow - debug file system access.\n" 78 " --debug-blacklists - debug blacklisting.\n"
79 " --debug-deny - debug file system access.\n"
80 " --debug-caps - print all recognized capabilities.\n" 79 " --debug-caps - print all recognized capabilities.\n"
81 " --debug-errnos - print all recognized error numbers.\n" 80 " --debug-errnos - print all recognized error numbers.\n"
82 " --debug-private-lib - debug for --private-lib option.\n" 81 " --debug-private-lib - debug for --private-lib option.\n"
83 " --debug-protocols - print all recognized protocols.\n" 82 " --debug-protocols - print all recognized protocols.\n"
84 " --debug-syscalls - print all recognized system calls.\n" 83 " --debug-syscalls - print all recognized system calls.\n"
85 " --debug-syscalls32 - print all recognized 32 bit system calls.\n" 84 " --debug-syscalls32 - print all recognized 32 bit system calls.\n"
85 " --debug-whitelists - debug whitelisting.\n"
86#ifdef HAVE_NETWORK 86#ifdef HAVE_NETWORK
87 " --defaultgw=address - configure default gateway.\n" 87 " --defaultgw=address - configure default gateway.\n"
88#endif 88#endif
89 " --deny=filename - deny access to directory or file.\n"
90 " --deterministic-exit-code - always exit with first child's status code.\n" 89 " --deterministic-exit-code - always exit with first child's status code.\n"
91 " --dns=address - set DNS server.\n" 90 " --dns=address - set DNS server.\n"
92 " --dns.print=name|pid - print DNS configuration.\n" 91 " --dns.print=name|pid - print DNS configuration.\n"
@@ -147,14 +146,13 @@ static char *usage_str =
147 " --netfilter6=filename - enable IPv6 firewall.\n" 146 " --netfilter6=filename - enable IPv6 firewall.\n"
148 " --netfilter6.print=name|pid - print the IPv6 firewall.\n" 147 " --netfilter6.print=name|pid - print the IPv6 firewall.\n"
149 " --netmask=address - define a network mask when dealing with unconfigured\n" 148 " --netmask=address - define a network mask when dealing with unconfigured\n"
150 "\tparrent interfaces.\n" 149 "\tparent interfaces.\n"
151 " --netns=name - Run the program in a named, persistent network namespace.\n" 150 " --netns=name - Run the program in a named, persistent network namespace.\n"
152 " --netstats - monitor network statistics.\n" 151 " --netstats - monitor network statistics.\n"
153#endif 152#endif
154 " --nice=value - set nice value.\n" 153 " --nice=value - set nice value.\n"
155 " --no3d - disable 3D hardware acceleration.\n" 154 " --no3d - disable 3D hardware acceleration.\n"
156 " --noallow=filename - disable allow command for file or directory.\n" 155 " --noblacklist=filename - disable blacklist for file or directory.\n"
157 " --nodeny=filename - disable deny command for file or directory.\n"
158 " --nodbus - disable D-Bus access.\n" 156 " --nodbus - disable D-Bus access.\n"
159 " --nodvd - disable DVD and audio CD devices.\n" 157 " --nodvd - disable DVD and audio CD devices.\n"
160 " --noexec=filename - remount the file or directory noexec nosuid and nodev.\n" 158 " --noexec=filename - remount the file or directory noexec nosuid and nodev.\n"
@@ -169,6 +167,7 @@ static char *usage_str =
169 " --noautopulse - disable automatic ~/.config/pulse init.\n" 167 " --noautopulse - disable automatic ~/.config/pulse init.\n"
170 " --novideo - disable video devices.\n" 168 " --novideo - disable video devices.\n"
171 " --nou2f - disable U2F devices.\n" 169 " --nou2f - disable U2F devices.\n"
170 " --nowhitelist=filename - disable whitelist for file or directory.\n"
172#ifdef HAVE_OUTPUT 171#ifdef HAVE_OUTPUT
173 " --output=logfile - stdout logging and log rotation.\n" 172 " --output=logfile - stdout logging and log rotation.\n"
174 " --output-stderr=logfile - stdout and stderr logging and log rotation.\n" 173 " --output-stderr=logfile - stdout and stderr logging and log rotation.\n"
@@ -225,14 +224,14 @@ static char *usage_str =
225#ifdef HAVE_NETWORK 224#ifdef HAVE_NETWORK
226 " --scan - ARP-scan all the networks from inside a network namespace.\n" 225 " --scan - ARP-scan all the networks from inside a network namespace.\n"
227#endif 226#endif
228 " --seccomp - enable seccomp filter and drop the default syscalls.\n" 227 " --seccomp - enable seccomp filter and apply the default blacklist.\n"
229 " --seccomp=syscall,syscall,syscall - enable seccomp filter, drop the\n" 228 " --seccomp=syscall,syscall,syscall - enable seccomp filter, blacklist the\n"
230 "\tdefault syscall list and the syscalls specified by the command.\n" 229 "\tdefault syscall list and the syscalls specified by the command.\n"
231 " --seccomp.block-secondary - build only the native architecture filters.\n" 230 " --seccomp.block-secondary - build only the native architecture filters.\n"
232 " --seccomp.drop=syscall,syscall,syscall - enable seccomp filter, and\n" 231 " --seccomp.drop=syscall,syscall,syscall - enable seccomp filter, and\n"
233 "\tdrop the syscalls specified by the command.\n" 232 "\tblacklist the syscalls specified by the command.\n"
234 " --seccomp.keep=syscall,syscall,syscall - enable seccomp filter, and\n" 233 " --seccomp.keep=syscall,syscall,syscall - enable seccomp filter, and\n"
235 "\tallow the syscalls specified by the command.\n" 234 "\twhitelist the syscalls specified by the command.\n"
236 " --seccomp.print=name|pid - print the seccomp filter for the sandbox\n" 235 " --seccomp.print=name|pid - print the seccomp filter for the sandbox\n"
237 "\tidentified by name or PID.\n" 236 "\tidentified by name or PID.\n"
238 " --seccomp.32[.drop,.keep][=syscall] - like above but for 32 bit architecture.\n" 237 " --seccomp.32[.drop,.keep][=syscall] - like above but for 32 bit architecture.\n"
@@ -247,7 +246,7 @@ static char *usage_str =
247 " --top - monitor the most CPU-intensive sandboxes.\n" 246 " --top - monitor the most CPU-intensive sandboxes.\n"
248 " --trace - trace open, access and connect system calls.\n" 247 " --trace - trace open, access and connect system calls.\n"
249 " --tracelog - add a syslog message for every access to files or\n" 248 " --tracelog - add a syslog message for every access to files or\n"
250 "\tdirectories dropped by the security profile.\n" 249 "\tdirectories blacklisted by the security profile.\n"
251 " --tree - print a tree of all sandboxed processes.\n" 250 " --tree - print a tree of all sandboxed processes.\n"
252 " --tunnel[=devname] - connect the sandbox to a tunnel created by\n" 251 " --tunnel[=devname] - connect the sandbox to a tunnel created by\n"
253 "\tfiretunnel utility.\n" 252 "\tfiretunnel utility.\n"
@@ -255,6 +254,7 @@ static char *usage_str =
255#ifdef HAVE_NETWORK 254#ifdef HAVE_NETWORK
256 " --veth-name=name - use this name for the interface connected to the bridge.\n" 255 " --veth-name=name - use this name for the interface connected to the bridge.\n"
257#endif 256#endif
257 " --whitelist=filename - whitelist directory or file.\n"
258 " --writable-etc - /etc directory is mounted read-write.\n" 258 " --writable-etc - /etc directory is mounted read-write.\n"
259 " --writable-run-user - allow access to /run/user/$UID/systemd and\n" 259 " --writable-run-user - allow access to /run/user/$UID/systemd and\n"
260 "\t/run/user/$UID/gnupg.\n" 260 "\t/run/user/$UID/gnupg.\n"
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 094a68c60..f0df45eb2 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -459,31 +459,21 @@ int is_dir(const char *fname) {
459 if (*fname == '\0') 459 if (*fname == '\0')
460 return 0; 460 return 0;
461 461
462 int called_as_root = 0;
463 if (geteuid() == 0)
464 called_as_root = 1;
465
466 if (called_as_root)
467 EUID_USER();
468
469 // if fname doesn't end in '/', add one 462 // if fname doesn't end in '/', add one
470 int rv; 463 int rv;
471 struct stat s; 464 struct stat s;
472 if (fname[strlen(fname) - 1] == '/') 465 if (fname[strlen(fname) - 1] == '/')
473 rv = stat(fname, &s); 466 rv = stat_as_user(fname, &s);
474 else { 467 else {
475 char *tmp; 468 char *tmp;
476 if (asprintf(&tmp, "%s/", fname) == -1) { 469 if (asprintf(&tmp, "%s/", fname) == -1) {
477 fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); 470 fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__);
478 errExit("asprintf"); 471 errExit("asprintf");
479 } 472 }
480 rv = stat(tmp, &s); 473 rv = stat_as_user(tmp, &s);
481 free(tmp); 474 free(tmp);
482 } 475 }
483 476
484 if (called_as_root)
485 EUID_ROOT();
486
487 if (rv == -1) 477 if (rv == -1)
488 return 0; 478 return 0;
489 479
diff --git a/src/jailcheck/jailcheck.h b/src/jailcheck/jailcheck.h
index be3104da3..3f8c89bfb 100644
--- a/src/jailcheck/jailcheck.h
+++ b/src/jailcheck/jailcheck.h
@@ -61,4 +61,4 @@ char *get_homedir(const char *user, uid_t *uid, gid_t *gid);
61int find_child(pid_t pid); 61int find_child(pid_t pid);
62pid_t switch_to_child(pid_t pid); 62pid_t switch_to_child(pid_t pid);
63 63
64#endif \ No newline at end of file 64#endif
diff --git a/src/jailcheck/noexec.c b/src/jailcheck/noexec.c
index 7f994d6a1..be18ac109 100644
--- a/src/jailcheck/noexec.c
+++ b/src/jailcheck/noexec.c
@@ -110,4 +110,4 @@ void noexec_test(const char *path) {
110 wait(&status); 110 wait(&status);
111 int rv = unlink(fname); 111 int rv = unlink(fname);
112 (void) rv; 112 (void) rv;
113} \ No newline at end of file 113}
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index adb79234b..a1eccaa5e 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -78,7 +78,7 @@ in your desktop environment copy the profile file in ~/.config/firejail director
78Several command line options can be passed to the program using 78Several command line options can be passed to the program using
79profile files. Firejail chooses the profile file as follows: 79profile files. Firejail chooses the profile file as follows:
80 80
81\fB1.\fR If a profile file is provided by the user with \-\-profile option, the profile file is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. 81\fB1.\fR If a profile file is provided by the user with \-\-profile option, the profile file is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix.
82Example: 82Example:
83.PP 83.PP
84.RS 84.RS
@@ -156,7 +156,7 @@ Scripting commands:
156\fBFile and directory names 156\fBFile and directory names
157File and directory names containing spaces are supported. The space character ' ' should not be escaped. 157File and directory names containing spaces are supported. The space character ' ' should not be escaped.
158 158
159Example: "deny ~/My Virtual Machines" 159Example: "blacklist ~/My Virtual Machines"
160 160
161.TP 161.TP
162\fB# this is a comment 162\fB# this is a comment
@@ -170,9 +170,9 @@ net none # this command creates an empty network namespace
170\fB?CONDITIONAL: profile line 170\fB?CONDITIONAL: profile line
171Conditionally add profile line. 171Conditionally add profile line.
172 172
173Example: "?HAS_APPIMAGE: allow ${HOME}/special/appimage/dir" 173Example: "?HAS_APPIMAGE: whitelist ${HOME}/special/appimage/dir"
174 174
175This example will load the profile line only if the \-\-appimage option has been specified on the command line. 175This example will load the whitelist profile line only if the \-\-appimage option has been specified on the command line.
176 176
177Currently the only conditionals supported this way are HAS_APPIMAGE, HAS_NET, HAS_NODBUS, HAS_NOSOUND, HAS_PRIVATE and HAS_X11. The conditionals ALLOW_TRAY, BROWSER_DISABLE_U2F and BROWSER_ALLOW_DRM 177Currently the only conditionals supported this way are HAS_APPIMAGE, HAS_NET, HAS_NODBUS, HAS_NOSOUND, HAS_PRIVATE and HAS_X11. The conditionals ALLOW_TRAY, BROWSER_DISABLE_U2F and BROWSER_ALLOW_DRM
178can be enabled or disabled globally in Firejail's configuration file. 178can be enabled or disabled globally in Firejail's configuration file.
@@ -205,16 +205,16 @@ storing modifications to the persistent configuration. Persistent .local files
205are included at the start of regular profile files. 205are included at the start of regular profile files.
206 206
207.TP 207.TP
208\fBnoallow file_name 208\fBnoblacklist file_name
209If the file name matches file_name, the file will not be allowed in any allow commands that follow. 209If the file name matches file_name, the file will not be blacklisted in any blacklist commands that follow.
210 210
211Example: "nowhitelist ~/.config" 211Example: "noblacklist ${HOME}/.mozilla"
212 212
213.TP 213.TP
214\fBnodeny file_name 214\fBnowhitelist file_name
215If the file name matches file_name, the file will not be denied any deny commands that follow. 215If the file name matches file_name, the file will not be whitelisted in any whitelist commands that follow.
216 216
217Example: "nodeny ${HOME}/.mozilla" 217Example: "nowhitelist ~/.config"
218 218
219.TP 219.TP
220\fBignore 220\fBignore
@@ -242,17 +242,19 @@ HOME directories are searched, see the \fBfirejail\f(1) \fBFILE GLOBBING\fR sect
242for more details. 242for more details.
243Examples: 243Examples:
244.TP 244.TP
245\fBallow file_or_directory 245\fBblacklist file_or_directory
246Allow directory or file. A temporary file system is mounted on the top directory, and the 246Blacklist directory or file. Examples:
247allowed files are mount-binded inside. Modifications to allowd files are persistent,
248everything else is discarded when the sandbox is closed. The top directory can be
249all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and
250all directories in /usr.
251.br 247.br
252 248
253.br 249.br
254Symbolic link handling: with the exception of user home, both the link and the real file should be in 250blacklist /usr/bin
255the same top directory. For user home, both the link and the real file should be owned by the user. 251.br
252blacklist /usr/bin/gcc*
253.br
254blacklist ${PATH}/ifconfig
255.br
256blacklist ${HOME}/.ssh
257
256.TP 258.TP
257\fBblacklist-nolog file_or_directory 259\fBblacklist-nolog file_or_directory
258When --tracelog flag is set, blacklisting generates syslog messages if the sandbox tries to access the file or directory. 260When --tracelog flag is set, blacklisting generates syslog messages if the sandbox tries to access the file or directory.
@@ -271,20 +273,6 @@ Mount-bind directory1 on top of directory2. This option is only available when r
271\fBbind file1,file2 273\fBbind file1,file2
272Mount-bind file1 on top of file2. This option is only available when running as root. 274Mount-bind file1 on top of file2. This option is only available when running as root.
273.TP 275.TP
274\fBdeny file_or_directory
275Deny access to directory or file. Examples:
276.br
277
278.br
279deny /usr/bin
280.br
281deny /usr/bin/gcc*
282.br
283deny ${PATH}/ifconfig
284.br
285deny ${HOME}/.ssh
286
287.TP
288\fBdisable-mnt 276\fBdisable-mnt
289Disable /mnt, /media, /run/mount and /run/media access. 277Disable /mnt, /media, /run/mount and /run/media access.
290.TP 278.TP
@@ -304,7 +292,7 @@ The directory is created if it doesn't already exist.
304.br 292.br
305 293
306.br 294.br
307Use this command for allowed directories you need to preserve 295Use this command for whitelisted directories you need to preserve
308when the sandbox is closed. Without it, the application will create the directory, and the directory 296when the sandbox is closed. Without it, the application will create the directory, and the directory
309will be deleted when the sandbox is closed. Subdirectories are recursively created. Example from 297will be deleted when the sandbox is closed. Subdirectories are recursively created. Example from
310firefox profile: 298firefox profile:
@@ -317,7 +305,7 @@ whitelist ~/.mozilla
317.br 305.br
318mkdir ~/.cache/mozilla/firefox 306mkdir ~/.cache/mozilla/firefox
319.br 307.br
320allow ~/.cache/mozilla/firefox 308whitelist ~/.cache/mozilla/firefox
321.br 309.br
322 310
323.br 311.br
@@ -336,16 +324,16 @@ Remount the file or the directory noexec, nodev and nosuid.
336#ifdef HAVE_OVERLAYFS 324#ifdef HAVE_OVERLAYFS
337.TP 325.TP
338\fBoverlay 326\fBoverlay
339Mount a filesystem overlay on top of the current filesystem. 327Mount a filesystem overlay on top of the current filesystem.
340The overlay is stored in $HOME/.firejail/<PID> directory. 328The overlay is stored in $HOME/.firejail/<PID> directory.
341.TP 329.TP
342\fBoverlay-named name 330\fBoverlay-named name
343Mount a filesystem overlay on top of the current filesystem. 331Mount a filesystem overlay on top of the current filesystem.
344The overlay is stored in $HOME/.firejail/name directory. 332The overlay is stored in $HOME/.firejail/name directory.
345.TP 333.TP
346\fBoverlay-tmpfs 334\fBoverlay-tmpfs
347Mount a filesystem overlay on top of the current filesystem. 335Mount a filesystem overlay on top of the current filesystem.
348All filesystem modifications are discarded when the sandbox is closed. 336All filesystem modifications are discarded when the sandbox is closed.
349#endif 337#endif
350.TP 338.TP
351\fBprivate 339\fBprivate
@@ -423,7 +411,7 @@ expressed as foo/bar -- is disallowed).
423All modifications are discarded when the sandbox is closed. 411All modifications are discarded when the sandbox is closed.
424.TP 412.TP
425\fBprivate-tmp 413\fBprivate-tmp
426Mount an empty temporary filesystem on top of /tmp directory allowing /tmp/.X11-unix. 414Mount an empty temporary filesystem on top of /tmp directory whitelisting /tmp/.X11-unix.
427.TP 415.TP
428\fBread-only file_or_directory 416\fBread-only file_or_directory
429Make directory or file read-only. 417Make directory or file read-only.
@@ -435,13 +423,25 @@ Make directory or file read-write.
435Mount an empty tmpfs filesystem on top of directory. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions. 423Mount an empty tmpfs filesystem on top of directory. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions.
436.TP 424.TP
437\fBtracelog 425\fBtracelog
438File system deny violations logged to syslog. 426Blacklist violations logged to syslog.
427.TP
428\fBwhitelist file_or_directory
429Whitelist directory or file. A temporary file system is mounted on the top directory, and the
430whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent,
431everything else is discarded when the sandbox is closed. The top directory can be
432all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and
433all directories in /usr.
434.br
435
436.br
437Symbolic link handling: with the exception of user home, both the link and the real file should be in
438the same top directory. For user home, both the link and the real file should be owned by the user.
439.TP 439.TP
440\fBwritable-etc 440\fBwritable-etc
441Mount /etc directory read-write. 441Mount /etc directory read-write.
442.TP 442.TP
443\fBwritable-run-user 443\fBwritable-run-user
444Disable the default denying of run/user/$UID/systemd and /run/user/$UID/gnupg. 444Disable the default blacklisting of run/user/$UID/systemd and /run/user/$UID/gnupg.
445.TP 445.TP
446\fBwritable-var 446\fBwritable-var
447Mount /var directory read-write. 447Mount /var directory read-write.
@@ -455,7 +455,7 @@ The following security filters are currently implemented:
455 455
456.TP 456.TP
457\fBallow-debuggers 457\fBallow-debuggers
458Allow tools such as strace and gdb inside the sandbox by allowing system calls ptrace and process_vm_readv. 458Allow tools such as strace and gdb inside the sandbox by whitelisting system calls ptrace and process_vm_readv.
459#ifdef HAVE_APPARMOR 459#ifdef HAVE_APPARMOR
460.TP 460.TP
461\fBapparmor 461\fBapparmor
@@ -466,13 +466,13 @@ Enable AppArmor confinement.
466Enable default Linux capabilities filter. 466Enable default Linux capabilities filter.
467.TP 467.TP
468\fBcaps.drop capability,capability,capability 468\fBcaps.drop capability,capability,capability
469Deny given Linux capabilities. 469Blacklist given Linux capabilities.
470.TP 470.TP
471\fBcaps.drop all 471\fBcaps.drop all
472Deny all Linux capabilities. 472Blacklist all Linux capabilities.
473.TP 473.TP
474\fBcaps.keep capability,capability,capability 474\fBcaps.keep capability,capability,capability
475Allow given Linux capabilities. 475Whitelist given Linux capabilities.
476.TP 476.TP
477\fBmemory-deny-write-execute 477\fBmemory-deny-write-execute
478Install a seccomp filter to block attempts to create memory mappings 478Install a seccomp filter to block attempts to create memory mappings
@@ -487,42 +487,42 @@ does not result in an increase of privilege.
487#ifdef HAVE_USERNS 487#ifdef HAVE_USERNS
488.TP 488.TP
489\fBnoroot 489\fBnoroot
490Use this command to enable an user namespace. The namespace has only one user, the current user. 490Use this command to enable an user namespace. The namespace has only one user, the current user.
491There is no root account (uid 0) defined in the namespace. 491There is no root account (uid 0) defined in the namespace.
492#endif 492#endif
493.TP 493.TP
494\fBprotocol protocol1,protocol2,protocol3 494\fBprotocol protocol1,protocol2,protocol3
495Enable protocol filter. The filter is based on seccomp and checks the 495Enable protocol filter. The filter is based on seccomp and checks the
496first argument to socket system call. Recognized values: \fBunix\fR, 496first argument to socket system call. Recognized values: \fBunix\fR,
497\fBinet\fR, \fBinet6\fR, \fBnetlink\fR, \fBpacket\fR and \fBbluetooth\fR. 497\fBinet\fR, \fBinet6\fR, \fBnetlink\fR, \fBpacket\fR and \fBbluetooth\fR.
498.TP 498.TP
499\fBseccomp 499\fBseccomp
500Enable seccomp filter and deny the syscalls in the default list. See man 1 firejail for more details. 500Enable seccomp filter and blacklist the syscalls in the default list. See man 1 firejail for more details.
501.TP 501.TP
502\fBseccomp.32 502\fBseccomp.32
503Enable seccomp filter and deny the syscalls in the default list for 32 bit system calls on a 64 bit architecture system. 503Enable seccomp filter and blacklist the syscalls in the default list for 32 bit system calls on a 64 bit architecture system.
504.TP 504.TP
505\fBseccomp syscall,syscall,syscall 505\fBseccomp syscall,syscall,syscall
506Enable seccomp filter and deny the system calls in the list on top of default seccomp filter. 506Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter.
507.TP 507.TP
508\fBseccomp.32 syscall,syscall,syscall 508\fBseccomp.32 syscall,syscall,syscall
509Enable seccomp filter and deny the system calls in the list on top of default seccomp filter for 32 bit system calls on a 64 bit architecture system. 509Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter for 32 bit system calls on a 64 bit architecture system.
510.TP 510.TP
511\fBseccomp.block-secondary 511\fBseccomp.block-secondary
512Enable seccomp filter and filter system call architectures 512Enable seccomp filter and filter system call architectures
513so that only the native architecture is allowed. 513so that only the native architecture is allowed.
514.TP 514.TP
515\fBseccomp.drop syscall,syscall,syscall 515\fBseccomp.drop syscall,syscall,syscall
516Enable seccomp filter and deny the system calls in the list. 516Enable seccomp filter and blacklist the system calls in the list.
517.TP 517.TP
518\fBseccomp.32.drop syscall,syscall,syscall 518\fBseccomp.32.drop syscall,syscall,syscall
519Enable seccomp filter and deny the system calls in the list for 32 bit system calls on a 64 bit architecture system. 519Enable seccomp filter and blacklist the system calls in the list for 32 bit system calls on a 64 bit architecture system.
520.TP 520.TP
521\fBseccomp.keep syscall,syscall,syscall 521\fBseccomp.keep syscall,syscall,syscall
522Enable seccomp filter and allow the system calls in the list. 522Enable seccomp filter and whitelist the system calls in the list.
523.TP 523.TP
524\fBseccomp.32.keep syscall,syscall,syscall 524\fBseccomp.32.keep syscall,syscall,syscall
525Enable seccomp filter and allow the system calls in the list for 32 bit system calls on a 64 bit architecture system. 525Enable seccomp filter and whitelist the system calls in the list for 32 bit system calls on a 64 bit architecture system.
526.TP 526.TP
527\fBseccomp-error-action kill | log | ERRNO 527\fBseccomp-error-action kill | log | ERRNO
528Return a different error instead of EPERM to the process, kill it when 528Return a different error instead of EPERM to the process, kill it when
@@ -534,7 +534,7 @@ attempt.
534Enable X11 sandboxing. 534Enable X11 sandboxing.
535.TP 535.TP
536\fBx11 none 536\fBx11 none
537Deny access to /tmp/.X11-unix directory, ${HOME}/.Xauthority and file specified in ${XAUTHORITY} environment variable. 537Blacklist /tmp/.X11-unix directory, ${HOME}/.Xauthority and file specified in ${XAUTHORITY} environment variable.
538Remove DISPLAY and XAUTHORITY environment variables. 538Remove DISPLAY and XAUTHORITY environment variables.
539Stop with error message if X11 abstract socket will be accessible in jail. 539Stop with error message if X11 abstract socket will be accessible in jail.
540.TP 540.TP
@@ -606,7 +606,7 @@ Allow the application to see but not talk to the name org.freedesktop.Notificati
606Allow the application to call methods of the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus. 606Allow the application to call methods of the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus.
607.TP 607.TP
608\fBdbus-system.broadcast org.freedesktop.Notifications=org.freedesktop.Notifications.*@/org/freedesktop/Notifications 608\fBdbus-system.broadcast org.freedesktop.Notifications=org.freedesktop.Notifications.*@/org/freedesktop/Notifications
609Allow the application to receive broadcast signals from the the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus. 609Allow the application to receive broadcast signals from the interface org.freedesktop.Notifications of the object exposed at the path /org/freedesktop/Notifications by the client owning the bus name org.freedesktop.Notifications on the system DBus.
610.TP 610.TP
611\fBdbus-user filter 611\fBdbus-user filter
612Enable filtered access to the session DBus. Filters can be specified with the dbus-user.talk and dbus-user.own commands. 612Enable filtered access to the session DBus. Filters can be specified with the dbus-user.talk and dbus-user.own commands.
@@ -873,8 +873,8 @@ a DHCP client and releasing the lease manually.
873 873
874.TP 874.TP
875\fBiprange address,address 875\fBiprange address,address
876Assign an IP address in the provided range to the last network 876Assign an IP address in the provided range to the last network
877interface defined by a net command. A default gateway is assigned by default. 877interface defined by a net command. A default gateway is assigned by default.
878.br 878.br
879 879
880.br 880.br
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 498ff9aa9..2883ab257 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -45,7 +45,7 @@ firejail {\-? | \-\-debug-caps | \-\-debug-errnos | \-\-debug-syscalls | \-\-deb
45#ifdef HAVE_LTS 45#ifdef HAVE_LTS
46This is Firejail long-term support (LTS), an enterprise focused version of the software, 46This is Firejail long-term support (LTS), an enterprise focused version of the software,
47LTS is usually supported for two or three years. 47LTS is usually supported for two or three years.
48During this time only bugs and the occasional documentation problems are fixed. 48During this time only bugs and the occasional documentation problems are fixed.
49The attack surface of the SUID executable was greatly reduced by removing some of the features. 49The attack surface of the SUID executable was greatly reduced by removing some of the features.
50.br 50.br
51 51
@@ -99,40 +99,6 @@ $ firejail [OPTIONS] firefox # starting Mozilla Firefox
99\fB\-\- 99\fB\-\-
100Signal the end of options and disables further option processing. 100Signal the end of options and disables further option processing.
101.TP 101.TP
102\fB\-\-allow=dirname_or_filename
103Allow access to a directory or file. A temporary file system is mounted on the top directory, and the
104allowed files are mount-binded inside. Modifications to allowed files are persistent,
105everything else is discarded when the sandbox is closed. The top directory can be
106all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and
107all directories in /usr.
108.br
109
110.br
111Symbolic link handling: with the exception of user home, both the link and the real file should be in
112the same top directory. For user home, both the link and the real file should be owned by the user.
113.br
114
115.br
116File globbing is supported, see \fBFILE GLOBBING\fR section for more details.
117.br
118
119.br
120Example:
121.br
122$ firejail \-\-noprofile \-\-allow=~/.mozilla
123.br
124$ firejail \-\-allow=/tmp/.X11-unix --allow=/dev/null
125.br
126$ firejail "\-\-allow=/home/username/My Virtual Machines"
127.br
128$ firejail \-\-allow=~/work* \-\-allow=/var/backups*
129
130
131
132
133
134
135.TP
136\fB\-\-allow-debuggers 102\fB\-\-allow-debuggers
137Allow tools such as strace and gdb inside the sandbox by whitelisting 103Allow tools such as strace and gdb inside the sandbox by whitelisting
138system calls ptrace and process_vm_readv. This option is only 104system calls ptrace and process_vm_readv. This option is only
@@ -143,7 +109,7 @@ ptrace system call allows a full bypass of the seccomp filter.
143.br 109.br
144Example: 110Example:
145.br 111.br
146$ firejail --allow-debuggers --profile=/etc/firejail/firefox.profile strace -f firefox 112$ firejail --allow-debuggers --profile=/etc/firejail/firefox.profile strace -f firefox
147.TP 113.TP
148\fB\-\-allusers 114\fB\-\-allusers
149All directories under /home are visible inside the sandbox. By default, only current user home directory is visible. 115All directories under /home are visible inside the sandbox. By default, only current user home directory is visible.
@@ -203,6 +169,21 @@ Example:
203.br 169.br
204# firejail \-\-bind=/config/etc/passwd,/etc/passwd 170# firejail \-\-bind=/config/etc/passwd,/etc/passwd
205.TP 171.TP
172\fB\-\-blacklist=dirname_or_filename
173Blacklist directory or file. File globbing is supported, see \fBFILE GLOBBING\fR section for more details.
174.br
175
176.br
177Example:
178.br
179$ firejail \-\-blacklist=/sbin \-\-blacklist=/usr/sbin
180.br
181$ firejail \-\-blacklist=~/.mozilla
182.br
183$ firejail "\-\-blacklist=/home/username/My Virtual Machines"
184.br
185$ firejail \-\-blacklist=/home/username/My\\ Virtual\\ Machines
186.TP
206\fB\-\-build 187\fB\-\-build
207The command builds a whitelisted profile. The profile is printed on the screen. If /usr/bin/strace is installed on the system, it also 188The command builds a whitelisted profile. The profile is printed on the screen. If /usr/bin/strace is installed on the system, it also
208builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox, 189builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox,
@@ -262,7 +243,7 @@ $ firejail \-\-caps.drop=all warzone2100
262 243
263.TP 244.TP
264\fB\-\-caps.drop=capability,capability,capability 245\fB\-\-caps.drop=capability,capability,capability
265Define a custom Linux capabilities filter. 246Define a custom blacklist Linux capabilities filter.
266.br 247.br
267 248
268.br 249.br
@@ -643,14 +624,14 @@ Example:
643$ firejail \-\-debug firefox 624$ firejail \-\-debug firefox
644 625
645.TP 626.TP
646\fB\-\-debug-allow\fR 627\fB\-\-debug-blacklists\fR
647Debug file system access. 628Debug blacklisting.
648.br 629.br
649 630
650.br 631.br
651Example: 632Example:
652.br 633.br
653$ firejail \-\-debug-allow firefox 634$ firejail \-\-debug-blacklists firefox
654 635
655.TP 636.TP
656\fB\-\-debug-caps 637\fB\-\-debug-caps
@@ -663,16 +644,6 @@ Example:
663$ firejail \-\-debug-caps 644$ firejail \-\-debug-caps
664 645
665.TP 646.TP
666\fB\-\-debug-deny\fR
667Debug file access.
668.br
669
670.br
671Example:
672.br
673$ firejail \-\-debug-deny firefox
674
675.TP
676\fB\-\-debug-errnos 647\fB\-\-debug-errnos
677Print all recognized error numbers in the current Firejail software build and exit. 648Print all recognized error numbers in the current Firejail software build and exit.
678.br 649.br
@@ -706,44 +677,33 @@ $ firejail \-\-debug-syscalls
706\fB\-\-debug-syscalls32 677\fB\-\-debug-syscalls32
707Print all recognized 32 bit system calls in the current Firejail software build and exit. 678Print all recognized 32 bit system calls in the current Firejail software build and exit.
708.br 679.br
709
710#ifdef HAVE_NETWORK
711.TP 680.TP
712\fB\-\-defaultgw=address 681\fB\-\-debug-whitelists\fR
713Use this address as default gateway in the new network namespace. 682Debug whitelisting.
714.br 683.br
715 684
716.br 685.br
717Example: 686Example:
718.br 687.br
719$ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox 688$ firejail \-\-debug-whitelists firefox
720#endif 689#ifdef HAVE_NETWORK
721
722.TP 690.TP
723\fB\-\-deny=dirname_or_filename 691\fB\-\-defaultgw=address
724Deny access to directory or file. File globbing is supported, see \fBFILE GLOBBING\fR section for more details. 692Use this address as default gateway in the new network namespace.
725.br 693.br
726 694
727.br 695.br
728Example: 696Example:
729.br 697.br
730$ firejail \-\-deny=/sbin \-\-deny=/usr/sbin 698$ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox
731.br 699#endif
732$ firejail \-\-deny=~/.mozilla
733.br
734$ firejail "\-\-deny=/home/username/My Virtual Machines"
735.br
736$ firejail \-\-deny=/home/username/My\\ Virtual\\ Machines
737
738
739
740.TP 700.TP
741\fB\-\-deterministic-exit-code 701\fB\-\-deterministic-exit-code
742Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic. 702Always exit firejail with the first child's exit status. The default behavior is to use the exit status of the final child to exit, which can be nondeterministic.
743.br 703.br
744.TP 704.TP
745\fB\-\-disable-mnt 705\fB\-\-disable-mnt
746Deny access to /mnt, /media, /run/mount and /run/media. 706Blacklist /mnt, /media, /run/mount and /run/media access.
747.br 707.br
748 708
749.br 709.br
@@ -987,7 +947,7 @@ $ firejail \-\-net=eth0 \-\-\iprange=192.168.1.100,192.168.1.150
987 947
988.TP 948.TP
989\fB\-\-ipc-namespace 949\fB\-\-ipc-namespace
990Enable a new IPC namespace if the sandbox was started as a regular user. IPC namespace is enabled by default 950Enable a new IPC namespace if the sandbox was started as a regular user. IPC namespace is enabled by default
991for sandboxes started as root. 951for sandboxes started as root.
992.br 952.br
993 953
@@ -1054,7 +1014,7 @@ $ sudo firejail --join-network=browser /sbin/iptables -vL
1054.br 1014.br
1055 1015
1056.br 1016.br
1057# verify IP addresses 1017# verify IP addresses
1058.br 1018.br
1059$ sudo firejail --join-network=browser ip addr 1019$ sudo firejail --join-network=browser ip addr
1060.br 1020.br
@@ -1511,16 +1471,12 @@ Example:
1511$ firejail --no3d firefox 1471$ firejail --no3d firefox
1512 1472
1513.TP 1473.TP
1514\fB\-\-noallow=dirname_or_filename
1515Disable \-\-allow for this directory or file.
1516
1517.TP
1518\fB\-\-noautopulse \fR(deprecated) 1474\fB\-\-noautopulse \fR(deprecated)
1519See --keep-config-pulse. 1475See --keep-config-pulse.
1520 1476
1521.TP 1477.TP
1522\fB\-\-nodeny=dirname_or_filename 1478\fB\-\-noblacklist=dirname_or_filename
1523Disable \-\-deny for this directory or file. 1479Disable blacklist for this directory or file.
1524.br 1480.br
1525 1481
1526.br 1482.br
@@ -1536,7 +1492,7 @@ $ exit
1536.br 1492.br
1537 1493
1538.br 1494.br
1539$ firejail --nodeny=/bin/nc 1495$ firejail --noblacklist=/bin/nc
1540.br 1496.br
1541$ nc dict.org 2628 1497$ nc dict.org 2628
1542.br 1498.br
@@ -1710,6 +1666,10 @@ $ firejail \-\-nou2f
1710Disable video devices. 1666Disable video devices.
1711.br 1667.br
1712 1668
1669.TP
1670\fB\-\-nowhitelist=dirname_or_filename
1671Disable whitelist for this directory or file.
1672
1713#ifdef HAVE_OUTPUT 1673#ifdef HAVE_OUTPUT
1714.TP 1674.TP
1715\fB\-\-output=logfile 1675\fB\-\-output=logfile
@@ -2174,7 +2134,7 @@ Use k(ilobyte), m(egabyte) or g(igabyte) for size suffix (base 1024).
2174.TP 2134.TP
2175\fB\-\-rlimit-cpu=number 2135\fB\-\-rlimit-cpu=number
2176Set the maximum limit, in seconds, for the amount of CPU time each 2136Set the maximum limit, in seconds, for the amount of CPU time each
2177sandboxed process can consume. When the limit is reached, the processes are killed. 2137sandboxed process can consume. When the limit is reached, the processes are killed.
2178 2138
2179The CPU limit is a limit on CPU seconds rather than elapsed time. CPU seconds is basically how many seconds 2139The CPU limit is a limit on CPU seconds rather than elapsed time. CPU seconds is basically how many seconds
2180the CPU has been in use and does not necessarily directly relate to the elapsed time. Linux kernel keeps 2140the CPU has been in use and does not necessarily directly relate to the elapsed time. Linux kernel keeps
@@ -2218,7 +2178,7 @@ $ firejail \-\-net=eth0 \-\-scan
2218.TP 2178.TP
2219\fB\-\-seccomp 2179\fB\-\-seccomp
2220Enable seccomp filter and blacklist the syscalls in the default list, 2180Enable seccomp filter and blacklist the syscalls in the default list,
2221which is @default-nodebuggers unless \-\-allow-debuggers is specified, 2181which is @default-nodebuggers unless \-\-allow-debuggers is specified,
2222then it is @default. 2182then it is @default.
2223 2183
2224.br 2184.br
@@ -2773,6 +2733,34 @@ Example:
2773.br 2733.br
2774$ firejail \-\-net=br0 --veth-name=if0 2734$ firejail \-\-net=br0 --veth-name=if0
2775#endif 2735#endif
2736.TP
2737\fB\-\-whitelist=dirname_or_filename
2738Whitelist directory or file. A temporary file system is mounted on the top directory, and the
2739whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent,
2740everything else is discarded when the sandbox is closed. The top directory can be
2741all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and
2742all directories in /usr.
2743.br
2744
2745.br
2746Symbolic link handling: with the exception of user home, both the link and the real file should be in
2747the same top directory. For user home, both the link and the real file should be owned by the user.
2748.br
2749
2750.br
2751File globbing is supported, see \fBFILE GLOBBING\fR section for more details.
2752.br
2753
2754.br
2755Example:
2756.br
2757$ firejail \-\-noprofile \-\-whitelist=~/.mozilla
2758.br
2759$ firejail \-\-whitelist=/tmp/.X11-unix --whitelist=/dev/null
2760.br
2761$ firejail "\-\-whitelist=/home/username/My Virtual Machines"
2762.br
2763$ firejail \-\-whitelist=~/work* \-\-whitelist=/var/backups*
2776 2764
2777.TP 2765.TP
2778\fB\-\-writable-etc 2766\fB\-\-writable-etc
@@ -2877,7 +2865,7 @@ and it is installed by default on most Linux distributions. It provides support
2877connection model. Untrusted clients are restricted in certain ways to prevent them from reading window 2865connection model. Untrusted clients are restricted in certain ways to prevent them from reading window
2878contents of other clients, stealing input events, etc. 2866contents of other clients, stealing input events, etc.
2879 2867
2880The untrusted mode has several limitations. A lot of regular programs assume they are a trusted X11 clients 2868The untrusted mode has several limitations. A lot of regular programs assume they are a trusted X11 clients
2881and will crash or lock up when run in untrusted mode. Chromium browser and xterm are two examples. 2869and will crash or lock up when run in untrusted mode. Chromium browser and xterm are two examples.
2882Firefox and transmission-gtk seem to be working fine. 2870Firefox and transmission-gtk seem to be working fine.
2883A network namespace is not required for this option. 2871A network namespace is not required for this option.
@@ -3268,7 +3256,7 @@ The owner of the sandbox.
3268.SH RESTRICTED SHELL 3256.SH RESTRICTED SHELL
3269To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in 3257To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in
3270/etc/passwd file for each user that needs to be restricted. Alternatively, 3258/etc/passwd file for each user that needs to be restricted. Alternatively,
3271you can specify /usr/bin/firejail in adduser command: 3259you can specify /usr/bin/firejail in adduser command:
3272 3260
3273adduser \-\-shell /usr/bin/firejail username 3261adduser \-\-shell /usr/bin/firejail username
3274 3262
@@ -3278,7 +3266,7 @@ Additional arguments passed to firejail executable upon login are declared in /e
3278Several command line options can be passed to the program using 3266Several command line options can be passed to the program using
3279profile files. Firejail chooses the profile file as follows: 3267profile files. Firejail chooses the profile file as follows:
3280 3268
32811. If a profile file is provided by the user with --profile=FILE option, the profile FILE is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. If there is a file with the same name as the given profile name, it will be used instead of doing the profile search. To force a profile search, prefix the profile name with a colon (:), eg. --profile=:PROFILE_NAME. 32691. If a profile file is provided by the user with --profile=FILE option, the profile FILE is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. If there is a file with the same name as the given profile name, it will be used instead of doing the profile search. To force a profile search, prefix the profile name with a colon (:), eg. --profile=:PROFILE_NAME.
3282Example: 3270Example:
3283.PP 3271.PP
3284.RS 3272.RS
diff --git a/src/man/firemon.txt b/src/man/firemon.txt
index 76b2f7be2..c4e6e15b3 100644
--- a/src/man/firemon.txt
+++ b/src/man/firemon.txt
@@ -56,7 +56,7 @@ Print route table for each sandbox.
56Print seccomp configuration for each sandbox. 56Print seccomp configuration for each sandbox.
57.TP 57.TP
58\fB\-\-top 58\fB\-\-top
59Monitor the most CPU-intensive sandboxes. This command is similar to 59Monitor the most CPU-intensive sandboxes. This command is similar to
60the regular UNIX top command, however it applies only to sandboxes. 60the regular UNIX top command, however it applies only to sandboxes.
61.TP 61.TP
62\fB\-\-tree 62\fB\-\-tree
diff --git a/src/tools/profcleaner.c b/src/tools/profcleaner.c
index 93bb3f73d..beff93199 100644
--- a/src/tools/profcleaner.c
+++ b/src/tools/profcleaner.c
@@ -72,4 +72,4 @@ int main(int argc, char **argv) {
72 } 72 }
73 73
74 return 0; 74 return 0;
75} \ No newline at end of file 75}
diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in
index 666dfd4c2..c7f6ee3f1 100644
--- a/src/zsh_completion/_firejail.in
+++ b/src/zsh_completion/_firejail.in
@@ -218,7 +218,7 @@ _firejail_args=(
218 '--netfilter.print=-[print the firewall name|pid]: :_all_firejails' 218 '--netfilter.print=-[print the firewall name|pid]: :_all_firejails'
219 '--netfilter6=-[enable IPv6 firewall]: :' 219 '--netfilter6=-[enable IPv6 firewall]: :'
220 '--netfilter6.print=-[print the IPv6 firewall name|pid]: :_all_firejails' 220 '--netfilter6.print=-[print the IPv6 firewall name|pid]: :_all_firejails'
221 '--netmask=-[define a network mask when dealing with unconfigured parrent interfaces]: :' 221 '--netmask=-[define a network mask when dealing with unconfigured parent interfaces]: :'
222 '--netns=-[Run the program in a named, persistent network namespace]: :' 222 '--netns=-[Run the program in a named, persistent network namespace]: :'
223 '--netstats[monitor network statistics]' 223 '--netstats[monitor network statistics]'
224 '--interface=-[move interface in sandbox]: :' 224 '--interface=-[move interface in sandbox]: :'