aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fbuilder/build_bin.c9
-rw-r--r--src/fbuilder/build_fs.c128
-rw-r--r--src/fbuilder/build_home.c28
-rw-r--r--src/fbuilder/build_profile.c73
-rw-r--r--src/fbuilder/fbuilder.h1
-rw-r--r--src/fbuilder/filedb.c49
-rw-r--r--src/fbuilder/main.c12
-rw-r--r--src/firecfg/firecfg.config9
-rw-r--r--src/firejail/appimage.c6
-rw-r--r--src/firejail/bandwidth.c32
-rw-r--r--src/firejail/caps.c2
-rw-r--r--src/firejail/cgroup.c20
-rw-r--r--src/firejail/checkcfg.c2
-rw-r--r--src/firejail/cpu.c6
-rw-r--r--src/firejail/dhcp.c2
-rw-r--r--src/firejail/env.c7
-rw-r--r--src/firejail/firejail.h6
-rw-r--r--src/firejail/fs_dev.c20
-rw-r--r--src/firejail/fs_etc.c63
-rw-r--r--src/firejail/fs_home.c4
-rw-r--r--src/firejail/fs_hostname.c6
-rw-r--r--src/firejail/fs_lib.c2
-rw-r--r--src/firejail/fs_logger.c25
-rw-r--r--src/firejail/fs_trace.c9
-rw-r--r--src/firejail/fs_var.c13
-rw-r--r--src/firejail/join.c6
-rw-r--r--src/firejail/ls.c2
-rw-r--r--src/firejail/macros.c2
-rw-r--r--src/firejail/main.c40
-rw-r--r--src/firejail/network.c2
-rw-r--r--src/firejail/network_main.c2
-rw-r--r--src/firejail/no_sandbox.c14
-rw-r--r--src/firejail/preproc.c2
-rw-r--r--src/firejail/profile.c14
-rw-r--r--src/firejail/protocol.c4
-rw-r--r--src/firejail/pulseaudio.c2
-rw-r--r--src/firejail/restrict_users.c8
-rw-r--r--src/firejail/restricted_shell.c4
-rw-r--r--src/firejail/run_files.c6
-rw-r--r--src/firejail/sandbox.c9
-rw-r--r--src/firejail/sbox.c4
-rw-r--r--src/firejail/seccomp.c8
-rw-r--r--src/firejail/shutdown.c2
-rw-r--r--src/firejail/usage.c4
-rw-r--r--src/firejail/util.c25
-rw-r--r--src/firejail/x11.c4
-rw-r--r--src/firemon/firemon.c2
-rw-r--r--src/man/firejail-profile.txt114
-rw-r--r--src/man/firejail.txt43
-rw-r--r--src/profstats/main.c11
-rw-r--r--src/zsh_completion/_firejail.in2
51 files changed, 550 insertions, 320 deletions
diff --git a/src/fbuilder/build_bin.c b/src/fbuilder/build_bin.c
index 96bd351f3..9577042c4 100644
--- a/src/fbuilder/build_bin.c
+++ b/src/fbuilder/build_bin.c
@@ -83,11 +83,9 @@ static void process_bin(const char *fname) {
83 continue; 83 continue;
84 *ptr2 = '\0'; 84 *ptr2 = '\0';
85 85
86 // skip strace 86 // skip strace and firejail (in case we hit a symlink in /usr/local/bin)
87 if (strcmp(ptr, "strace") == 0) 87 if (strcmp(ptr, "strace") && strcmp(ptr, "firejail"))
88 continue; 88 bin_out = filedb_add(bin_out, ptr);
89
90 bin_out = filedb_add(bin_out, ptr);
91 } 89 }
92 90
93 fclose(fp); 91 fclose(fp);
@@ -121,6 +119,5 @@ void build_bin(const char *fname, FILE *fp) {
121 ptr = ptr->next; 119 ptr = ptr->next;
122 } 120 }
123 fprintf(fp, "\n"); 121 fprintf(fp, "\n");
124 fprintf(fp, "# private-lib\n");
125 } 122 }
126} 123}
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c
index 495f71ab8..8700e0ba1 100644
--- a/src/fbuilder/build_fs.c
+++ b/src/fbuilder/build_fs.c
@@ -146,31 +146,49 @@ void build_etc(const char *fname, FILE *fp) {
146//******************************************* 146//*******************************************
147// var directory 147// var directory
148//******************************************* 148//*******************************************
149#if 0
150// todo: load the list from whitelist-var-common.inc
151static char *var_skip[] = {
152 "/var/lib/ca-certificates",
153 "/var/lib/dbus",
154 "/var/lib/menu-xdg",
155 "/var/lib/uim",
156 "/var/cache/fontconfig",
157 "/var/tmp",
158 "/var/run",
159 "/var/lock",
160 NULL
161};
162#endif
149static FileDB *var_out = NULL; 163static FileDB *var_out = NULL;
164static FileDB *var_skip = NULL;
150static void var_callback(char *ptr) { 165static void var_callback(char *ptr) {
151 if (strcmp(ptr, "/var/lib") == 0) 166 // extract the directory:
152 ; 167 assert(strncmp(ptr, "/var", 4) == 0);
153 else if (strcmp(ptr, "/var/cache") == 0) 168 char *p1 = ptr + 4;
154 ; 169 if (*p1 != '/')
155 else if (strncmp(ptr, "/var/lib/menu-xdg", 17) == 0) 170 return;
156 var_out = filedb_add(var_out, "/var/lib/menu-xdg"); 171 p1++;
157 else if (strncmp(ptr, "/var/cache/fontconfig", 21) == 0) 172
158 var_out = filedb_add(var_out, "/var/cache/fontconfig"); 173 if (*p1 == '/') // double '/'
159 else 174 p1++;
160 var_out = filedb_add(var_out, ptr); 175 if (*p1 == '\0')
176 return;
177
178 if (!filedb_find(var_skip, p1))
179 var_out = filedb_add(var_out, p1);
161} 180}
162 181
163void build_var(const char *fname, FILE *fp) { 182void build_var(const char *fname, FILE *fp) {
164 assert(fname); 183 assert(fname);
165 184
185 var_skip = filedb_load_whitelist(var_skip, "whitelist-var-common.inc", "whitelist /var/");
166 process_files(fname, "/var", var_callback); 186 process_files(fname, "/var", var_callback);
167 187
168 if (var_out == NULL) { 188 // always whitelist /var
169 fprintf(fp, "blacklist /var\n"); 189 if (var_out)
170 } else { 190 filedb_print(var_out, "whitelist /var/", fp);
171 filedb_print(var_out, "whitelist ", fp); 191 fprintf(fp, "include whitelist-var-common.inc\n");
172 fprintf(fp, "include whitelist-var-common.inc\n");
173 }
174} 192}
175 193
176 194
@@ -178,6 +196,7 @@ void build_var(const char *fname, FILE *fp) {
178// usr/share directory 196// usr/share directory
179//******************************************* 197//*******************************************
180static FileDB *share_out = NULL; 198static FileDB *share_out = NULL;
199static FileDB *share_skip = NULL;
181static void share_callback(char *ptr) { 200static void share_callback(char *ptr) {
182 // extract the directory: 201 // extract the directory:
183 assert(strncmp(ptr, "/usr/share", 10) == 0); 202 assert(strncmp(ptr, "/usr/share", 10) == 0);
@@ -195,21 +214,21 @@ static void share_callback(char *ptr) {
195 if (p2) 214 if (p2)
196 *p2 = '\0'; 215 *p2 = '\0';
197 216
198 // store the file 217
199 share_out = filedb_add(share_out, ptr); 218 if (!filedb_find(share_skip, p1))
219 share_out = filedb_add(share_out, p1);
200} 220}
201 221
202void build_share(const char *fname, FILE *fp) { 222void build_share(const char *fname, FILE *fp) {
203 assert(fname); 223 assert(fname);
204 224
225 share_skip = filedb_load_whitelist(share_skip, "whitelist-usr-share-common.inc", "whitelist /usr/share/");
205 process_files(fname, "/usr/share", share_callback); 226 process_files(fname, "/usr/share", share_callback);
206 227
207 if (share_out == NULL) { 228 // always whitelist /usr/share
208 fprintf(fp, "blacklist /usr/share\n"); 229 if (share_out)
209 } else { 230 filedb_print(share_out, "whitelist /usr/share/", fp);
210 filedb_print(share_out, "whitelist ", fp); 231 fprintf(fp, "include whitelist-usr-share-common.inc\n");
211 fprintf(fp, "include whitelist-usr-share-common.inc\n");
212 }
213} 232}
214 233
215//******************************************* 234//*******************************************
@@ -220,6 +239,10 @@ static void tmp_callback(char *ptr) {
220 // skip strace file 239 // skip strace file
221 if (strncmp(ptr, "/tmp/firejail-strace", 20) == 0) 240 if (strncmp(ptr, "/tmp/firejail-strace", 20) == 0)
222 return; 241 return;
242 if (strncmp(ptr, "/tmp/runtime-", 13) == 0)
243 return;
244 if (strcmp(ptr, "/tmp") == 0)
245 return;
223 246
224 tmp_out = filedb_add(tmp_out, ptr); 247 tmp_out = filedb_add(tmp_out, ptr);
225} 248}
@@ -232,8 +255,7 @@ void build_tmp(const char *fname, FILE *fp) {
232 if (tmp_out == NULL) 255 if (tmp_out == NULL)
233 fprintf(fp, "private-tmp\n"); 256 fprintf(fp, "private-tmp\n");
234 else { 257 else {
235 fprintf(fp, "\n"); 258 fprintf(fp, "#private-tmp\n");
236 fprintf(fp, "# private-tmp\n");
237 fprintf(fp, "# File accessed in /tmp directory:\n"); 259 fprintf(fp, "# File accessed in /tmp directory:\n");
238 fprintf(fp, "# "); 260 fprintf(fp, "# ");
239 FileDB *ptr = tmp_out; 261 FileDB *ptr = tmp_out;
@@ -249,40 +271,37 @@ void build_tmp(const char *fname, FILE *fp) {
249// dev directory 271// dev directory
250//******************************************* 272//*******************************************
251static char *dev_skip[] = { 273static char *dev_skip[] = {
274 "/dev/stdin",
275 "/dev/stdout",
276 "/dev/stderr",
252 "/dev/zero", 277 "/dev/zero",
253 "/dev/null", 278 "/dev/null",
254 "/dev/full", 279 "/dev/full",
255 "/dev/random", 280 "/dev/random",
281 "/dev/srandom",
256 "/dev/urandom", 282 "/dev/urandom",
283 "/dev/sr0",
284 "/dev/cdrom",
285 "/dev/cdrw",
286 "/dev/dvd",
287 "/dev/dvdrw",
288 "/dev/fd",
289 "/dev/pts",
290 "/dev/ptmx",
291 "/dev/log",
292
293 "/dev/aload", // old ALSA devices, not covered in private-dev
294 "/dev/dsp", // old OSS device, deprecated
295
257 "/dev/tty", 296 "/dev/tty",
258 "/dev/snd", 297 "/dev/snd",
259 "/dev/dri", 298 "/dev/dri",
260 "/dev/pts", 299 "/dev/nvidia",
261 "/dev/nvidia0", 300 "/dev/video",
262 "/dev/nvidia1",
263 "/dev/nvidia2",
264 "/dev/nvidia3",
265 "/dev/nvidia4",
266 "/dev/nvidia5",
267 "/dev/nvidia6",
268 "/dev/nvidia7",
269 "/dev/nvidia8",
270 "/dev/nvidia9",
271 "/dev/nvidiactl",
272 "/dev/nvidia-modeset",
273 "/dev/nvidia-uvm",
274 "/dev/video0",
275 "/dev/video1",
276 "/dev/video2",
277 "/dev/video3",
278 "/dev/video4",
279 "/dev/video5",
280 "/dev/video6",
281 "/dev/video7",
282 "/dev/video8",
283 "/dev/video9",
284 "/dev/dvb", 301 "/dev/dvb",
285 "/dev/sr0", 302 "/dev/hidraw",
303 "/dev/usb",
304 "/dev/input",
286 NULL 305 NULL
287}; 306};
288 307
@@ -292,7 +311,7 @@ static void dev_callback(char *ptr) {
292 int i = 0; 311 int i = 0;
293 int found = 0; 312 int found = 0;
294 while (dev_skip[i]) { 313 while (dev_skip[i]) {
295 if (strcmp(ptr, dev_skip[i]) == 0) { 314 if (strncmp(ptr, dev_skip[i], strlen(dev_skip[i])) == 0) {
296 found = 1; 315 found = 1;
297 break; 316 break;
298 } 317 }
@@ -310,9 +329,8 @@ void build_dev(const char *fname, FILE *fp) {
310 if (dev_out == NULL) 329 if (dev_out == NULL)
311 fprintf(fp, "private-dev\n"); 330 fprintf(fp, "private-dev\n");
312 else { 331 else {
313 fprintf(fp, "\n"); 332 fprintf(fp, "#private-dev\n");
314 fprintf(fp, "# private-dev\n"); 333 fprintf(fp, "# This is the list of devices accessed on top of regular private-dev devices:\n");
315 fprintf(fp, "# This is the list of devices accessed (on top of regular private-dev devices:\n");
316 fprintf(fp, "# "); 334 fprintf(fp, "# ");
317 FileDB *ptr = dev_out; 335 FileDB *ptr = dev_out;
318 while (ptr) { 336 while (ptr) {
diff --git a/src/fbuilder/build_home.c b/src/fbuilder/build_home.c
index 683009b71..b3ec6cffd 100644
--- a/src/fbuilder/build_home.c
+++ b/src/fbuilder/build_home.c
@@ -23,30 +23,6 @@
23static FileDB *db_skip = NULL; 23static FileDB *db_skip = NULL;
24static FileDB *db_out = NULL; 24static FileDB *db_out = NULL;
25 25
26static void load_whitelist_common(void) {
27 FILE *fp = fopen(SYSCONFDIR "/whitelist-common.inc", "r");
28 if (!fp) {
29 fprintf(stderr, "Error: cannot open whitelist-common.inc\n");
30 exit(1);
31 }
32
33 char buf[MAX_BUF];
34 while (fgets(buf, MAX_BUF, fp)) {
35 if (strncmp(buf, "whitelist ${HOME}/", 18) != 0)
36 continue;
37 char *fn = buf + 18;
38 char *ptr = strchr(buf, '\n');
39 if (!ptr)
40 continue;
41 *ptr = '\0';
42
43 // add the file to skip list
44 db_skip = filedb_add(db_skip, fn);
45 }
46
47 fclose(fp);
48}
49
50void process_home(const char *fname, char *home, int home_len) { 26void process_home(const char *fname, char *home, int home_len) {
51 assert(fname); 27 assert(fname);
52 assert(home); 28 assert(home);
@@ -141,7 +117,7 @@ void process_home(const char *fname, char *home, int home_len) {
141 } 117 }
142 118
143 // skip files and directories in whitelist-common.inc 119 // skip files and directories in whitelist-common.inc
144 if (filedb_find(db_skip, toadd)) { 120 if (strlen(toadd) == 0 || filedb_find(db_skip, toadd)) {
145 if (dir) 121 if (dir)
146 free(dir); 122 free(dir);
147 continue; 123 continue;
@@ -162,7 +138,7 @@ void build_home(const char *fname, FILE *fp) {
162 assert(fname); 138 assert(fname);
163 139
164 // load whitelist common 140 // load whitelist common
165 load_whitelist_common(); 141 db_skip = filedb_load_whitelist(db_skip, "whitelist-common.inc", "whitelist ${HOME}/");
166 142
167 // find user home directory 143 // find user home directory
168 struct passwd *pw = getpwuid(getuid()); 144 struct passwd *pw = getpwuid(getuid());
diff --git a/src/fbuilder/build_profile.c b/src/fbuilder/build_profile.c
index 96a83954d..1726b4dbb 100644
--- a/src/fbuilder/build_profile.c
+++ b/src/fbuilder/build_profile.c
@@ -141,6 +141,12 @@ void build_profile(int argc, char **argv, int index, FILE *fp) {
141 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 141 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
142 if (fp == stdout) 142 if (fp == stdout)
143 printf("--- Built profile beings after this line ---\n"); 143 printf("--- Built profile beings after this line ---\n");
144 fprintf(fp, "# Save this file as \"application.profile\" (change \"application\" with the\n");
145 fprintf(fp, "# program name) in ~/.config/firejail directory. Firejail will find it\n");
146 fprintf(fp, "# automatically every time you sandbox your application.\n#\n");
147 fprintf(fp, "# Run \"firejail application\" to test it. In the file there are\n");
148 fprintf(fp, "# some other commands you can try. Enable them by removing the \"#\".\n\n");
149
144 fprintf(fp, "# Firejail profile for %s\n", argv[index]); 150 fprintf(fp, "# Firejail profile for %s\n", argv[index]);
145 fprintf(fp, "# Persistent local customizations\n"); 151 fprintf(fp, "# Persistent local customizations\n");
146 fprintf(fp, "#include %s.local\n", argv[index]); 152 fprintf(fp, "#include %s.local\n", argv[index]);
@@ -148,56 +154,69 @@ void build_profile(int argc, char **argv, int index, FILE *fp) {
148 fprintf(fp, "#include globals.local\n"); 154 fprintf(fp, "#include globals.local\n");
149 fprintf(fp, "\n"); 155 fprintf(fp, "\n");
150 156
151 fprintf(fp, "### basic blacklisting\n"); 157 fprintf(fp, "### Basic Blacklisting ###\n");
158 fprintf(fp, "### Enable as many of them as you can! A very important one is\n");
159 fprintf(fp, "### \"disable-exec.inc\". This will make among other things your home\n");
160 fprintf(fp, "### and /tmp directories non-executable.\n");
152 fprintf(fp, "include disable-common.inc\n"); 161 fprintf(fp, "include disable-common.inc\n");
153 fprintf(fp, "# include disable-devel.inc\n"); 162 fprintf(fp, "#include disable-devel.inc\n");
154 fprintf(fp, "# include disable-exec.inc\n"); 163 fprintf(fp, "#include disable-exec.inc\n");
155 fprintf(fp, "# include disable-interpreters.inc\n"); 164 fprintf(fp, "#include disable-interpreters.inc\n");
156 fprintf(fp, "include disable-passwdmgr.inc\n"); 165 fprintf(fp, "include disable-passwdmgr.inc\n");
157 fprintf(fp, "# include disable-programs.inc\n"); 166 fprintf(fp, "include disable-programs.inc\n");
158 fprintf(fp, "# include disable-xdg.inc\n"); 167 fprintf(fp, "#include disable-shell.inc\n");
168 fprintf(fp, "#include disable-xdg.inc\n");
159 fprintf(fp, "\n"); 169 fprintf(fp, "\n");
160 170
161 fprintf(fp, "### home directory whitelisting\n"); 171 fprintf(fp, "### Home Directory Whitelisting ###\n");
172 fprintf(fp, "### If something goes wrong, this section is the first one to comment out.\n");
173 fprintf(fp, "### Instead, you'll have to relay on the basic blacklisting above.\n");
162 build_home(trace_output, fp); 174 build_home(trace_output, fp);
163 fprintf(fp, "\n"); 175 fprintf(fp, "\n");
164 176
165 fprintf(fp, "### filesystem\n"); 177 fprintf(fp, "### Filesystem Whitelisting ###\n");
166 fprintf(fp, "# /usr/share:\n");
167 build_share(trace_output, fp); 178 build_share(trace_output, fp);
168 fprintf(fp, "# /var:\n"); 179 //todo: include whitelist-runuser-common.inc
169 build_var(trace_output, fp); 180 build_var(trace_output, fp);
170 fprintf(fp, "\n"); 181 fprintf(fp, "\n");
171 fprintf(fp, "# $PATH:\n");
172 build_bin(trace_output, fp);
173 fprintf(fp, "# /dev:\n");
174 build_dev(trace_output, fp);
175 fprintf(fp, "# /etc:\n");
176 build_etc(trace_output, fp);
177 fprintf(fp, "# /tmp:\n");
178 build_tmp(trace_output, fp);
179 fprintf(fp, "\n");
180 182
181 fprintf(fp, "### security filters\n"); 183 fprintf(fp, "#apparmor\n");
182 fprintf(fp, "caps.drop all\n"); 184 fprintf(fp, "caps.drop all\n");
185 fprintf(fp, "ipc-namespace\n");
186 fprintf(fp, "netfilter\n");
187 fprintf(fp, "#nodvd\n");
188 fprintf(fp, "#nogroups\n");
189 fprintf(fp, "#noinput\n");
183 fprintf(fp, "nonewprivs\n"); 190 fprintf(fp, "nonewprivs\n");
191 fprintf(fp, "noroot\n");
192 fprintf(fp, "#notv\n");
193 fprintf(fp, "#nou2f\n");
194 fprintf(fp, "#novideo\n");
195 build_protocol(trace_output, fp);
184 fprintf(fp, "seccomp\n"); 196 fprintf(fp, "seccomp\n");
185 if (!have_strace) { 197 if (!have_strace) {
186 fprintf(fp, "# If you install strace on your system, Firejail will also create a\n"); 198 fprintf(fp, "### If you install strace on your system, Firejail will also create a\n");
187 fprintf(fp, "# whitelisted seccomp filter.\n"); 199 fprintf(fp, "### whitelisted seccomp filter.\n");
188 } 200 }
189 else if (!have_yama_permission) 201 else if (!have_yama_permission)
190 fprintf(fp, "# Yama security module prevents creation of a whitelisted seccomp filter\n"); 202 fprintf(fp, "### Yama security module prevents creation of a whitelisted seccomp filter\n");
191 else 203 else
192 build_seccomp(strace_output, fp); 204 build_seccomp(strace_output, fp);
205 fprintf(fp, "shell none\n");
206 fprintf(fp, "#tracelog\n");
193 fprintf(fp, "\n"); 207 fprintf(fp, "\n");
194 208
195 fprintf(fp, "### network\n"); 209 fprintf(fp, "#disable-mnt\n");
196 build_protocol(trace_output, fp); 210 build_bin(trace_output, fp);
211 fprintf(fp, "#private-lib\n");
212 build_dev(trace_output, fp);
213 build_etc(trace_output, fp);
214 build_tmp(trace_output, fp);
197 fprintf(fp, "\n"); 215 fprintf(fp, "\n");
198 216
199 fprintf(fp, "### environment\n"); 217 fprintf(fp, "#dbus-user none\n");
200 fprintf(fp, "shell none\n"); 218 fprintf(fp, "#dbus-system none\n");
219 fprintf(fp, "#memory-deny-write-execute\n");
201 220
202 if (!arg_debug) { 221 if (!arg_debug) {
203 unlink(trace_output); 222 unlink(trace_output);
diff --git a/src/fbuilder/fbuilder.h b/src/fbuilder/fbuilder.h
index 8d3621c02..08dd35e10 100644
--- a/src/fbuilder/fbuilder.h
+++ b/src/fbuilder/fbuilder.h
@@ -66,5 +66,6 @@ typedef struct filedb_t {
66FileDB *filedb_add(FileDB *head, const char *fname); 66FileDB *filedb_add(FileDB *head, const char *fname);
67FileDB *filedb_find(FileDB *head, const char *fname); 67FileDB *filedb_find(FileDB *head, const char *fname);
68void filedb_print(FileDB *head, const char *prefix, FILE *fp); 68void filedb_print(FileDB *head, const char *prefix, FILE *fp);
69FileDB *filedb_load_whitelist(FileDB *head, const char *fname, const char *prefix);
69 70
70#endif 71#endif
diff --git a/src/fbuilder/filedb.c b/src/fbuilder/filedb.c
index 6e302a606..94a226cb7 100644
--- a/src/fbuilder/filedb.c
+++ b/src/fbuilder/filedb.c
@@ -20,7 +20,9 @@
20 20
21#include "fbuilder.h" 21#include "fbuilder.h"
22 22
23// find exact name or an exact name in a parent directory
23FileDB *filedb_find(FileDB *head, const char *fname) { 24FileDB *filedb_find(FileDB *head, const char *fname) {
25 assert(fname);
24 FileDB *ptr = head; 26 FileDB *ptr = head;
25 int found = 0; 27 int found = 0;
26 int len = strlen(fname); 28 int len = strlen(fname);
@@ -52,6 +54,8 @@ FileDB *filedb_find(FileDB *head, const char *fname) {
52FileDB *filedb_add(FileDB *head, const char *fname) { 54FileDB *filedb_add(FileDB *head, const char *fname) {
53 assert(fname); 55 assert(fname);
54 56
57 // todo: support fnames such as ${RUNUSER}/.mutter-Xwaylandauth.*
58
55 // don't add it if it is already there or if the parent directory is already in the list 59 // don't add it if it is already there or if the parent directory is already in the list
56 if (filedb_find(head, fname)) 60 if (filedb_find(head, fname))
57 return head; 61 return head;
@@ -70,9 +74,52 @@ FileDB *filedb_add(FileDB *head, const char *fname) {
70}; 74};
71 75
72void filedb_print(FileDB *head, const char *prefix, FILE *fp) { 76void filedb_print(FileDB *head, const char *prefix, FILE *fp) {
77 assert(head);
78 assert(prefix);
79
73 FileDB *ptr = head; 80 FileDB *ptr = head;
74 while (ptr) { 81 while (ptr) {
75 fprintf(fp, "%s%s\n", prefix, ptr->fname); 82 if (fp)
83 fprintf(fp, "%s%s\n", prefix, ptr->fname);
84 else
85 printf("%s%s\n", prefix, ptr->fname);
76 ptr = ptr->next; 86 ptr = ptr->next;
77 } 87 }
78} 88}
89
90FileDB *filedb_load_whitelist(FileDB *head, const char *fname, const char *prefix) {
91 assert(fname);
92 assert(prefix);
93 int len = strlen(prefix);
94 char *f;
95 if (asprintf(&f, "%s/%s", SYSCONFDIR, fname) == -1)
96 errExit("asprintf");
97 FILE *fp = fopen(f, "r");
98 if (!fp) {
99 fprintf(stderr, "Error: cannot open whitelist-common.inc\n");
100 free(f);
101 exit(1);
102 }
103
104 char buf[MAX_BUF];
105 while (fgets(buf, MAX_BUF, fp)) {
106 if (strncmp(buf, prefix, len) != 0)
107 continue;
108
109 char *fn = buf + len;
110 char *ptr = strchr(buf, '\n');
111 if (!ptr)
112 continue;
113 *ptr = '\0';
114
115 // add the file to skip list
116 head = filedb_add(head, fn);
117 }
118
119 fclose(fp);
120 free(f);
121//printf("***************************************************\n");
122//filedb_print(head, prefix, NULL);
123//printf("***************************************************\n");
124 return head;
125}
diff --git a/src/fbuilder/main.c b/src/fbuilder/main.c
index f4917aefc..35ec49519 100644
--- a/src/fbuilder/main.c
+++ b/src/fbuilder/main.c
@@ -58,10 +58,16 @@ printf("\n");
58 exit(1); 58 exit(1);
59 } 59 }
60 60
61 // don't run if the file exists
62 if (access(argv[i] + 8, F_OK) == 0) {
63 fprintf(stderr, "Error: the profile file already exists. Please use a different file name.\n");
64 exit(1);
65 }
66
61 // check file access 67 // check file access
62 fp = fopen(argv[i] + 8, "w"); 68 fp = fopen(argv[i] + 8, "w");
63 if (!fp) { 69 if (!fp) {
64 fprintf(stderr, "Error fbuild: cannot open profile file.\n"); 70 fprintf(stderr, "Error: cannot open profile file.\n");
65 exit(1); 71 exit(1);
66 } 72 }
67 prof_file = 1; 73 prof_file = 1;
@@ -69,7 +75,7 @@ printf("\n");
69 } 75 }
70 else { 76 else {
71 if (*argv[i] == '-') { 77 if (*argv[i] == '-') {
72 fprintf(stderr, "Error fbuilder: invalid program\n"); 78 fprintf(stderr, "Error: invalid program\n");
73 usage(); 79 usage();
74 exit(1); 80 exit(1);
75 } 81 }
@@ -79,7 +85,7 @@ printf("\n");
79 } 85 }
80 86
81 if (prog_index == 0) { 87 if (prog_index == 0) {
82 fprintf(stderr, "Error fbuilder: program and arguments required\n"); 88 fprintf(stderr, "Error : program and arguments required\n");
83 usage(); 89 usage();
84 if (prof_file) 90 if (prof_file)
85 fclose(fp); 91 fclose(fp);
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index be50d5f44..474904ebf 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -74,6 +74,7 @@ autokey-run
74autokey-shell 74autokey-shell
75avidemux3_qt5 75avidemux3_qt5
76aweather 76aweather
77ballbuster
77baloo_file 78baloo_file
78baloo_filemetadata_temp_extractor 79baloo_filemetadata_temp_extractor
79balsa 80balsa
@@ -147,6 +148,7 @@ cmus
147code 148code
148code-oss 149code-oss
149cola 150cola
151colorful
150com.github.bleakgrey.tootle 152com.github.bleakgrey.tootle
151com.github.dahenson.agenda 153com.github.dahenson.agenda
152com.github.johnfactotum.Foliate 154com.github.johnfactotum.Foliate
@@ -236,6 +238,7 @@ ffplay
236ffprobe 238ffprobe
237file-roller 239file-roller
238filezilla 240filezilla
241firedragon
239firefox 242firefox
240firefox-beta 243firefox-beta
241firefox-developer-edition 244firefox-developer-edition
@@ -293,6 +296,8 @@ git-cola
293github-desktop 296github-desktop
294gitter 297gitter
295# gjs -- https://github.com/netblue30/firejail/issues/3333#issuecomment-612601102 298# gjs -- https://github.com/netblue30/firejail/issues/3333#issuecomment-612601102
299gl-117
300glaxium
296globaltime 301globaltime
297gmpc 302gmpc
298gnome-2048 303gnome-2048
@@ -550,6 +555,7 @@ mypaint
550mypaint-ora-thumbnailer 555mypaint-ora-thumbnailer
551natron 556natron
552ncdu 557ncdu
558neochat
553neomutt 559neomutt
554netactview 560netactview
555nethack 561nethack
@@ -615,6 +621,7 @@ penguin-command
615photoflare 621photoflare
616picard 622picard
617pidgin 623pidgin
624pinball
618#ping - disabled until we fix #1912 625#ping - disabled until we fix #1912
619pingus 626pingus
620pinta 627pinta
@@ -673,7 +680,6 @@ runenpass.sh
673sayonara 680sayonara
674scallion 681scallion
675scorched3d 682scorched3d
676scorched3d-wrapper
677scorchwentbonkers 683scorchwentbonkers
678scribus 684scribus
679sdat2img 685sdat2img
@@ -867,7 +873,6 @@ xmr-stak
867xonotic 873xonotic
868xonotic-glx 874xonotic-glx
869xonotic-sdl 875xonotic-sdl
870xonotic-sdl-wrapper
871xournal 876xournal
872xournalpp 877xournalpp
873xpdf 878xpdf
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
index 59758bf2d..6b9fed765 100644
--- a/src/firejail/appimage.c
+++ b/src/firejail/appimage.c
@@ -67,7 +67,7 @@ void appimage_set(const char *appimage) {
67 67
68 // find or allocate a free loop device to use 68 // find or allocate a free loop device to use
69 EUID_ROOT(); 69 EUID_ROOT();
70 int cfd = open("/dev/loop-control", O_RDWR); 70 int cfd = open("/dev/loop-control", O_RDWR|O_CLOEXEC);
71 if (cfd == -1) 71 if (cfd == -1)
72 err_loop(); 72 err_loop();
73 int devnr = ioctl(cfd, LOOP_CTL_GET_FREE); 73 int devnr = ioctl(cfd, LOOP_CTL_GET_FREE);
@@ -78,7 +78,7 @@ void appimage_set(const char *appimage) {
78 errExit("asprintf"); 78 errExit("asprintf");
79 79
80 // associate loop device with appimage 80 // associate loop device with appimage
81 int lfd = open(devloop, O_RDONLY); 81 int lfd = open(devloop, O_RDONLY|O_CLOEXEC);
82 if (lfd == -1) 82 if (lfd == -1)
83 err_loop(); 83 err_loop();
84 if (ioctl(lfd, LOOP_SET_FD, ffd) == -1) 84 if (ioctl(lfd, LOOP_SET_FD, ffd) == -1)
@@ -146,7 +146,7 @@ void appimage_mount(void) {
146void appimage_clear(void) { 146void appimage_clear(void) {
147 EUID_ROOT(); 147 EUID_ROOT();
148 if (devloop) { 148 if (devloop) {
149 int lfd = open(devloop, O_RDONLY); 149 int lfd = open(devloop, O_RDONLY|O_CLOEXEC);
150 if (lfd != -1) { 150 if (lfd != -1) {
151 if (ioctl(lfd, LOOP_CLR_FD, 0) != -1) 151 if (ioctl(lfd, LOOP_CLR_FD, 0) != -1)
152 fmessage("AppImage detached\n"); 152 fmessage("AppImage detached\n");
diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c
index 1c952c0bc..a085f2c27 100644
--- a/src/firejail/bandwidth.c
+++ b/src/firejail/bandwidth.c
@@ -22,6 +22,7 @@
22#include <sys/types.h> 22#include <sys/types.h>
23#include <sys/stat.h> 23#include <sys/stat.h>
24#include <unistd.h> 24#include <unistd.h>
25#include <errno.h>
25#include <net/if.h> 26#include <net/if.h>
26#include "firejail.h" 27#include "firejail.h"
27 28
@@ -119,26 +120,19 @@ static void bandwidth_create_run_file(pid_t pid) {
119 if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) 120 if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1)
120 errExit("asprintf"); 121 errExit("asprintf");
121 122
122 // if the file already exists, do nothing
123 struct stat s;
124 if (stat(fname, &s) == 0) {
125 free(fname);
126 return;
127 }
128
129 // create an empty file and set mod and ownership 123 // create an empty file and set mod and ownership
130 /* coverity[toctou] */ 124 // if the file already exists, do nothing
131 FILE *fp = fopen(fname, "w"); 125 FILE *fp = fopen(fname, "wxe");
132 if (fp) { 126 free(fname);
133 SET_PERMS_STREAM(fp, 0, 0, 0644); 127 if (!fp) {
134 fclose(fp); 128 if (errno == EEXIST)
135 } 129 return;
136 else {
137 fprintf(stderr, "Error: cannot create bandwidth file\n"); 130 fprintf(stderr, "Error: cannot create bandwidth file\n");
138 exit(1); 131 exit(1);
139 } 132 }
140 133
141 free(fname); 134 SET_PERMS_STREAM(fp, 0, 0, 0644);
135 fclose(fp);
142} 136}
143 137
144 138
@@ -148,7 +142,7 @@ void network_set_run_file(pid_t pid) {
148 errExit("asprintf"); 142 errExit("asprintf");
149 143
150 // create an empty file and set mod and ownership 144 // create an empty file and set mod and ownership
151 FILE *fp = fopen(fname, "w"); 145 FILE *fp = fopen(fname, "we");
152 if (fp) { 146 if (fp) {
153 if (cfg.bridge0.configured) 147 if (cfg.bridge0.configured)
154 fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox); 148 fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox);
@@ -178,7 +172,7 @@ static void read_bandwidth_file(pid_t pid) {
178 if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) 172 if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1)
179 errExit("asprintf"); 173 errExit("asprintf");
180 174
181 FILE *fp = fopen(fname, "r"); 175 FILE *fp = fopen(fname, "re");
182 if (fp) { 176 if (fp) {
183 char buf[1024]; 177 char buf[1024];
184 while (fgets(buf, 1024,fp)) { 178 while (fgets(buf, 1024,fp)) {
@@ -214,7 +208,7 @@ static void write_bandwidth_file(pid_t pid) {
214 if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1) 208 if (asprintf(&fname, "%s/%d-bandwidth", RUN_FIREJAIL_BANDWIDTH_DIR, (int) pid) == -1)
215 errExit("asprintf"); 209 errExit("asprintf");
216 210
217 FILE *fp = fopen(fname, "w"); 211 FILE *fp = fopen(fname, "we");
218 if (fp) { 212 if (fp) {
219 IFBW *ptr = ifbw; 213 IFBW *ptr = ifbw;
220 while (ptr) { 214 while (ptr) {
@@ -307,7 +301,7 @@ void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, in
307 char *fname; 301 char *fname;
308 if (asprintf(&fname, "%s/%d-netmap", RUN_FIREJAIL_NETWORK_DIR, (int) pid) == -1) 302 if (asprintf(&fname, "%s/%d-netmap", RUN_FIREJAIL_NETWORK_DIR, (int) pid) == -1)
309 errExit("asprintf"); 303 errExit("asprintf");
310 FILE *fp = fopen(fname, "r"); 304 FILE *fp = fopen(fname, "re");
311 if (!fp) { 305 if (!fp) {
312 fprintf(stderr, "Error: cannot read network map file %s\n", fname); 306 fprintf(stderr, "Error: cannot read network map file %s\n", fname);
313 exit(1); 307 exit(1);
diff --git a/src/firejail/caps.c b/src/firejail/caps.c
index 597f9915b..5e02b99c2 100644
--- a/src/firejail/caps.c
+++ b/src/firejail/caps.c
@@ -389,7 +389,7 @@ static uint64_t extract_caps(int pid) {
389 errExit("asprintf"); 389 errExit("asprintf");
390 390
391 EUID_ROOT(); // grsecurity 391 EUID_ROOT(); // grsecurity
392 FILE *fp = fopen(file, "r"); 392 FILE *fp = fopen(file, "re");
393 EUID_USER(); // grsecurity 393 EUID_USER(); // grsecurity
394 if (!fp) 394 if (!fp)
395 goto errexit; 395 goto errexit;
diff --git a/src/firejail/cgroup.c b/src/firejail/cgroup.c
index 986b1157d..e7ffbca36 100644
--- a/src/firejail/cgroup.c
+++ b/src/firejail/cgroup.c
@@ -26,7 +26,7 @@ void save_cgroup(void) {
26 if (cfg.cgroup == NULL) 26 if (cfg.cgroup == NULL)
27 return; 27 return;
28 28
29 FILE *fp = fopen(RUN_CGROUP_CFG, "w"); 29 FILE *fp = fopen(RUN_CGROUP_CFG, "wxe");
30 if (fp) { 30 if (fp) {
31 fprintf(fp, "%s", cfg.cgroup); 31 fprintf(fp, "%s", cfg.cgroup);
32 fflush(0); 32 fflush(0);
@@ -48,7 +48,7 @@ void load_cgroup(const char *fname) {
48 if (!fname) 48 if (!fname)
49 return; 49 return;
50 50
51 FILE *fp = fopen(fname, "r"); 51 FILE *fp = fopen(fname, "re");
52 if (fp) { 52 if (fp) {
53 char buf[MAXBUF]; 53 char buf[MAXBUF];
54 if (fgets(buf, MAXBUF, fp)) { 54 if (fgets(buf, MAXBUF, fp)) {
@@ -91,19 +91,19 @@ void set_cgroup(const char *path) {
91 goto errout; 91 goto errout;
92 92
93 // tasks file exists 93 // tasks file exists
94 struct stat s; 94 FILE *fp = fopen(path, "ae");
95 if (stat(path, &s) == -1) 95 if (!fp)
96 goto errout; 96 goto errout;
97
98 // task file belongs to the user running the sandbox 97 // task file belongs to the user running the sandbox
98 int fd = fileno(fp);
99 if (fd == -1)
100 errExit("fileno");
101 struct stat s;
102 if (fstat(fd, &s) == -1)
103 errExit("fstat");
99 if (s.st_uid != getuid() && s.st_gid != getgid()) 104 if (s.st_uid != getuid() && s.st_gid != getgid())
100 goto errout2; 105 goto errout2;
101
102 // add the task to cgroup 106 // add the task to cgroup
103 /* coverity[toctou] */
104 FILE *fp = fopen(path, "a");
105 if (!fp)
106 goto errout;
107 pid_t pid = getpid(); 107 pid_t pid = getpid();
108 int rv = fprintf(fp, "%d\n", pid); 108 int rv = fprintf(fp, "%d\n", pid);
109 (void) rv; 109 (void) rv;
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c
index 8a6e47e17..614b144e5 100644
--- a/src/firejail/checkcfg.c
+++ b/src/firejail/checkcfg.c
@@ -60,7 +60,7 @@ int checkcfg(int val) {
60 60
61 // open configuration file 61 // open configuration file
62 const char *fname = SYSCONFDIR "/firejail.config"; 62 const char *fname = SYSCONFDIR "/firejail.config";
63 fp = fopen(fname, "r"); 63 fp = fopen(fname, "re");
64 if (!fp) { 64 if (!fp) {
65#ifdef HAVE_GLOBALCFG 65#ifdef HAVE_GLOBALCFG
66 fprintf(stderr, "Error: Firejail configuration file %s not found\n", fname); 66 fprintf(stderr, "Error: Firejail configuration file %s not found\n", fname);
diff --git a/src/firejail/cpu.c b/src/firejail/cpu.c
index 3427e8ade..fe7258fb0 100644
--- a/src/firejail/cpu.c
+++ b/src/firejail/cpu.c
@@ -75,7 +75,7 @@ void save_cpu(void) {
75 if (cfg.cpus == 0) 75 if (cfg.cpus == 0)
76 return; 76 return;
77 77
78 FILE *fp = fopen(RUN_CPU_CFG, "w"); 78 FILE *fp = fopen(RUN_CPU_CFG, "wxe");
79 if (fp) { 79 if (fp) {
80 fprintf(fp, "%x\n", cfg.cpus); 80 fprintf(fp, "%x\n", cfg.cpus);
81 SET_PERMS_STREAM(fp, 0, 0, 0600); 81 SET_PERMS_STREAM(fp, 0, 0, 0600);
@@ -91,7 +91,7 @@ void load_cpu(const char *fname) {
91 if (!fname) 91 if (!fname)
92 return; 92 return;
93 93
94 FILE *fp = fopen(fname, "r"); 94 FILE *fp = fopen(fname, "re");
95 if (fp) { 95 if (fp) {
96 unsigned tmp; 96 unsigned tmp;
97 int rv = fscanf(fp, "%x", &tmp); 97 int rv = fscanf(fp, "%x", &tmp);
@@ -139,7 +139,7 @@ static void print_cpu(int pid) {
139 } 139 }
140 140
141 EUID_ROOT(); // grsecurity 141 EUID_ROOT(); // grsecurity
142 FILE *fp = fopen(file, "r"); 142 FILE *fp = fopen(file, "re");
143 EUID_USER(); // grsecurity 143 EUID_USER(); // grsecurity
144 if (!fp) { 144 if (!fp) {
145 printf(" Error: cannot open %s\n", file); 145 printf(" Error: cannot open %s\n", file);
diff --git a/src/firejail/dhcp.c b/src/firejail/dhcp.c
index bdbb338d5..5bcdcad37 100644
--- a/src/firejail/dhcp.c
+++ b/src/firejail/dhcp.c
@@ -93,7 +93,7 @@ static pid_t dhcp_read_pidfile(const Dhclient *client) {
93 while (found == 0 && tries < 10) { 93 while (found == 0 && tries < 10) {
94 if (tries >= 1) 94 if (tries >= 1)
95 usleep(100000); 95 usleep(100000);
96 FILE *pidfile = fopen(client->pid_file, "r"); 96 FILE *pidfile = fopen(client->pid_file, "re");
97 if (pidfile) { 97 if (pidfile) {
98 long pid; 98 long pid;
99 if (fscanf(pidfile, "%ld", &pid) == 1) 99 if (fscanf(pidfile, "%ld", &pid) == 1)
diff --git a/src/firejail/env.c b/src/firejail/env.c
index 03818df0b..f5e9dd980 100644
--- a/src/firejail/env.c
+++ b/src/firejail/env.c
@@ -59,12 +59,7 @@ void env_ibus_load(void) {
59 if (asprintf(&dirname, "%s/.config/ibus/bus", cfg.homedir) == -1) 59 if (asprintf(&dirname, "%s/.config/ibus/bus", cfg.homedir) == -1)
60 errExit("asprintf"); 60 errExit("asprintf");
61 61
62 struct stat s;
63 if (stat(dirname, &s) == -1)
64 return;
65
66 // find the file 62 // find the file
67 /* coverity[toctou] */
68 DIR *dir = opendir(dirname); 63 DIR *dir = opendir(dirname);
69 if (!dir) { 64 if (!dir) {
70 free(dirname); 65 free(dirname);
@@ -84,7 +79,7 @@ void env_ibus_load(void) {
84 char *fname; 79 char *fname;
85 if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1) 80 if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1)
86 errExit("asprintf"); 81 errExit("asprintf");
87 FILE *fp = fopen(fname, "r"); 82 FILE *fp = fopen(fname, "re");
88 free(fname); 83 free(fname);
89 if (!fp) 84 if (!fp)
90 continue; 85 continue;
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 20de229df..1c1ad4e97 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -310,7 +310,6 @@ extern int arg_private_cwd; // private working directory
310extern int arg_scan; // arp-scan all interfaces 310extern int arg_scan; // arp-scan all interfaces
311extern int arg_whitelist; // whitelist command 311extern int arg_whitelist; // whitelist command
312extern int arg_nosound; // disable sound 312extern int arg_nosound; // disable sound
313extern int arg_noautopulse; // disable automatic ~/.config/pulse init
314extern int arg_novideo; //disable video devices in /dev 313extern int arg_novideo; //disable video devices in /dev
315extern int arg_no3d; // disable 3d hardware acceleration 314extern int arg_no3d; // disable 3d hardware acceleration
316extern int arg_quiet; // no output for scripting 315extern int arg_quiet; // no output for scripting
@@ -319,6 +318,7 @@ extern int arg_join_filesystem; // join only the mount namespace
319extern int arg_nice; // nice value configured 318extern int arg_nice; // nice value configured
320extern int arg_ipc; // enable ipc namespace 319extern int arg_ipc; // enable ipc namespace
321extern int arg_writable_etc; // writable etc 320extern int arg_writable_etc; // writable etc
321extern int arg_keep_config_pulse; // disable automatic ~/.config/pulse init
322extern int arg_writable_var; // writable var 322extern int arg_writable_var; // writable var
323extern int arg_keep_var_tmp; // don't overwrite /var/tmp 323extern int arg_keep_var_tmp; // don't overwrite /var/tmp
324extern int arg_writable_run_user; // writable /run/user 324extern int arg_writable_run_user; // writable /run/user
@@ -335,7 +335,8 @@ extern int arg_noprofile; // use default.profile if none other found/specified
335extern int arg_memory_deny_write_execute; // block writable and executable memory 335extern int arg_memory_deny_write_execute; // block writable and executable memory
336extern int arg_notv; // --notv 336extern int arg_notv; // --notv
337extern int arg_nodvd; // --nodvd 337extern int arg_nodvd; // --nodvd
338extern int arg_nou2f; // --nou2f 338extern int arg_nou2f; // --nou2f
339extern int arg_noinput; // --noinput
339extern int arg_deterministic_exit_code; // always exit with first child's exit status 340extern int arg_deterministic_exit_code; // always exit with first child's exit status
340 341
341typedef enum { 342typedef enum {
@@ -565,6 +566,7 @@ void fs_dev_disable_video(void);
565void fs_dev_disable_tv(void); 566void fs_dev_disable_tv(void);
566void fs_dev_disable_dvd(void); 567void fs_dev_disable_dvd(void);
567void fs_dev_disable_u2f(void); 568void fs_dev_disable_u2f(void);
569void fs_dev_disable_input(void);
568 570
569// fs_home.c 571// fs_home.c
570// private mode (--private) 572// private mode (--private)
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index b2fa60f63..8c2870a4d 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -41,6 +41,7 @@ typedef enum {
41 DEV_TV, 41 DEV_TV,
42 DEV_DVD, 42 DEV_DVD,
43 DEV_U2F, 43 DEV_U2F,
44 DEV_INPUT
44} DEV_TYPE; 45} DEV_TYPE;
45 46
46 47
@@ -89,6 +90,7 @@ static DevEntry dev[] = {
89 {"/dev/hidraw8", RUN_DEV_DIR "/hidraw8", DEV_U2F}, 90 {"/dev/hidraw8", RUN_DEV_DIR "/hidraw8", DEV_U2F},
90 {"/dev/hidraw9", RUN_DEV_DIR "/hidraw9", DEV_U2F}, 91 {"/dev/hidraw9", RUN_DEV_DIR "/hidraw9", DEV_U2F},
91 {"/dev/usb", RUN_DEV_DIR "/usb", DEV_U2F}, // USB devices such as Yubikey, U2F 92 {"/dev/usb", RUN_DEV_DIR "/usb", DEV_U2F}, // USB devices such as Yubikey, U2F
93 {"/dev/input", RUN_DEV_DIR "/input", DEV_INPUT},
92 {NULL, NULL, DEV_NONE} 94 {NULL, NULL, DEV_NONE}
93}; 95};
94 96
@@ -103,7 +105,8 @@ static void deventry_mount(void) {
103 (dev[i].type == DEV_VIDEO && arg_novideo == 0) || 105 (dev[i].type == DEV_VIDEO && arg_novideo == 0) ||
104 (dev[i].type == DEV_TV && arg_notv == 0) || 106 (dev[i].type == DEV_TV && arg_notv == 0) ||
105 (dev[i].type == DEV_DVD && arg_nodvd == 0) || 107 (dev[i].type == DEV_DVD && arg_nodvd == 0) ||
106 (dev[i].type == DEV_U2F && arg_nou2f == 0)) { 108 (dev[i].type == DEV_U2F && arg_nou2f == 0) ||
109 (dev[i].type == DEV_INPUT && arg_noinput == 0)) {
107 110
108 int dir = is_dir(dev[i].run_fname); 111 int dir = is_dir(dev[i].run_fname);
109 if (arg_debug) 112 if (arg_debug)
@@ -119,7 +122,7 @@ static void deventry_mount(void) {
119 i++; 122 i++;
120 continue; 123 continue;
121 } 124 }
122 FILE *fp = fopen(dev[i].dev_fname, "w"); 125 FILE *fp = fopen(dev[i].dev_fname, "we");
123 if (fp) { 126 if (fp) {
124 fprintf(fp, "\n"); 127 fprintf(fp, "\n");
125 SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode); 128 SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode);
@@ -215,7 +218,7 @@ void fs_private_dev(void){
215 struct stat s; 218 struct stat s;
216 if (stat("/dev/log", &s) == 0) { 219 if (stat("/dev/log", &s) == 0) {
217 have_devlog = 1; 220 have_devlog = 1;
218 FILE *fp = fopen(RUN_DEVLOG_FILE, "w"); 221 FILE *fp = fopen(RUN_DEVLOG_FILE, "we");
219 if (!fp) 222 if (!fp)
220 have_devlog = 0; 223 have_devlog = 0;
221 else { 224 else {
@@ -236,7 +239,7 @@ void fs_private_dev(void){
236 239
237 // bring back /dev/log 240 // bring back /dev/log
238 if (have_devlog) { 241 if (have_devlog) {
239 FILE *fp = fopen("/dev/log", "w"); 242 FILE *fp = fopen("/dev/log", "we");
240 if (fp) { 243 if (fp) {
241 fprintf(fp, "\n"); 244 fprintf(fp, "\n");
242 fclose(fp); 245 fclose(fp);
@@ -386,3 +389,12 @@ void fs_dev_disable_u2f(void) {
386 i++; 389 i++;
387 } 390 }
388} 391}
392
393void fs_dev_disable_input(void) {
394 int i = 0;
395 while (dev[i].dev_fname != NULL) {
396 if (dev[i].type == DEV_INPUT)
397 disable_file_or_dir(dev[i].dev_fname);
398 i++;
399 }
400}
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index abec25d45..b0e1e1bf1 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -52,7 +52,7 @@ void fs_machineid(void) {
52 mid.u8[8] = (mid.u8[8] & 0x3F) | 0x80; 52 mid.u8[8] = (mid.u8[8] & 0x3F) | 0x80;
53 53
54 // write it in a file 54 // write it in a file
55 FILE *fp = fopen(RUN_MACHINEID, "w"); 55 FILE *fp = fopen(RUN_MACHINEID, "we");
56 if (!fp) 56 if (!fp)
57 errExit("fopen"); 57 errExit("fopen");
58 fprintf(fp, "%08x%08x%08x%08x\n", mid.u32[0], mid.u32[1], mid.u32[2], mid.u32[3]); 58 fprintf(fp, "%08x%08x%08x%08x\n", mid.u32[0], mid.u32[1], mid.u32[2], mid.u32[3]);
@@ -76,6 +76,44 @@ void fs_machineid(void) {
76 } 76 }
77} 77}
78 78
79// Duplicate directory structure from src to dst by creating empty directories.
80// The paths _must_ be identical after their respective prefixes.
81// When finished, dst will point to the target directory. That is, if
82// it starts out pointing to a file, it will instead be truncated so
83// that it contains the parent directory instead.
84static void build_dirs(char *src, char *dst, size_t src_prefix_len, size_t dst_prefix_len) {
85 char *p = src + src_prefix_len + 1;
86 char *q = dst + dst_prefix_len + 1;
87 char *r = dst + dst_prefix_len;
88 struct stat s;
89 bool last = false;
90 *r = '\0';
91 for (; !last; p++, q++) {
92 if (*p == '\0') {
93 last = true;
94 }
95 if (*p == '\0' || (*p == '/' && *(p - 1) != '/')) {
96 // We found a new component of our src path.
97 // Null-terminate it temporarily here so that we can work
98 // with it.
99 *p = '\0';
100 if (stat(src, &s) == 0 && S_ISDIR(s.st_mode)) {
101 // Null-terminate the dst path and undo its previous
102 // termination.
103 *q = '\0';
104 *r = '/';
105 r = q;
106 create_empty_dir_as_root(dst, s.st_mode);
107 }
108 if (!last) {
109 // If we're not at the final terminating null, restore
110 // the slash so that we can continue our traversal.
111 *p = '/';
112 }
113 }
114 }
115}
116
79// return 0 if file not found, 1 if found 117// return 0 if file not found, 1 if found
80static int check_dir_or_file(const char *fname) { 118static int check_dir_or_file(const char *fname) {
81 assert(fname); 119 assert(fname);
@@ -103,7 +141,7 @@ errexit:
103static void duplicate(const char *fname, const char *private_dir, const char *private_run_dir) { 141static void duplicate(const char *fname, const char *private_dir, const char *private_run_dir) {
104 assert(fname); 142 assert(fname);
105 143
106 if (*fname == '~' || strchr(fname, '/') || strcmp(fname, "..") == 0) { 144 if (*fname == '~' || *fname == '/' || strncmp(fname, "..", 2) == 0) {
107 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); 145 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
108 exit(1); 146 exit(1);
109 } 147 }
@@ -119,21 +157,16 @@ static void duplicate(const char *fname, const char *private_dir, const char *pr
119 } 157 }
120 158
121 if (arg_debug) 159 if (arg_debug)
122 printf("copying %s to private %s\n", src, private_dir); 160 printf("Copying %s to private %s\n", src, private_dir);
123 161
124 struct stat s; 162 char *dst;
125 if (stat(src, &s) == 0 && S_ISDIR(s.st_mode)) { 163 if (asprintf(&dst, "%s/%s", private_run_dir, fname) == -1)
126 // create the directory in RUN_ETC_DIR 164 errExit("asprintf");
127 char *dirname; 165
128 if (asprintf(&dirname, "%s/%s", private_run_dir, fname) == -1) 166 build_dirs(src, dst, strlen(private_dir), strlen(private_run_dir));
129 errExit("asprintf"); 167 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, PATH_FCOPY, src, dst);
130 create_empty_dir_as_root(dirname, s.st_mode);
131 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, dirname);
132 free(dirname);
133 }
134 else
135 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, private_run_dir);
136 168
169 free(dst);
137 fs_logger2("clone", src); 170 fs_logger2("clone", src);
138 free(src); 171 free(src);
139} 172}
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index e3b044a3b..4bcefa443 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -130,7 +130,7 @@ static int store_xauthority(void) {
130 } 130 }
131 131
132 // create an empty file as root, and change ownership to user 132 // create an empty file as root, and change ownership to user
133 FILE *fp = fopen(dest, "w"); 133 FILE *fp = fopen(dest, "we");
134 if (fp) { 134 if (fp) {
135 fprintf(fp, "\n"); 135 fprintf(fp, "\n");
136 SET_PERMS_STREAM(fp, getuid(), getgid(), 0600); 136 SET_PERMS_STREAM(fp, getuid(), getgid(), 0600);
@@ -178,7 +178,7 @@ static int store_asoundrc(void) {
178 } 178 }
179 179
180 // create an empty file as root, and change ownership to user 180 // create an empty file as root, and change ownership to user
181 FILE *fp = fopen(dest, "w"); 181 FILE *fp = fopen(dest, "we");
182 if (fp) { 182 if (fp) {
183 fprintf(fp, "\n"); 183 fprintf(fp, "\n");
184 SET_PERMS_STREAM(fp, getuid(), getgid(), 0644); 184 SET_PERMS_STREAM(fp, getuid(), getgid(), 0644);
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c
index 8a3bb71ea..80046f7ae 100644
--- a/src/firejail/fs_hostname.c
+++ b/src/firejail/fs_hostname.c
@@ -47,11 +47,11 @@ void fs_hostname(const char *hostname) {
47 printf("Creating a new /etc/hosts file\n"); 47 printf("Creating a new /etc/hosts file\n");
48 // copy /etc/host into our new file, and modify it on the fly 48 // copy /etc/host into our new file, and modify it on the fly
49 /* coverity[toctou] */ 49 /* coverity[toctou] */
50 FILE *fp1 = fopen("/etc/hosts", "r"); 50 FILE *fp1 = fopen("/etc/hosts", "re");
51 if (!fp1) 51 if (!fp1)
52 goto errexit; 52 goto errexit;
53 53
54 FILE *fp2 = fopen(RUN_HOSTS_FILE, "w"); 54 FILE *fp2 = fopen(RUN_HOSTS_FILE, "we");
55 if (!fp2) { 55 if (!fp2) {
56 fclose(fp1); 56 fclose(fp1);
57 goto errexit; 57 goto errexit;
@@ -165,7 +165,7 @@ void fs_resolvconf(void) {
165 165
166 if (arg_debug) 166 if (arg_debug)
167 printf("Creating a new /etc/resolv.conf file\n"); 167 printf("Creating a new /etc/resolv.conf file\n");
168 FILE *fp = fopen("/etc/resolv.conf", "w"); 168 FILE *fp = fopen("/etc/resolv.conf", "wxe");
169 if (!fp) { 169 if (!fp) {
170 fprintf(stderr, "Error: cannot create /etc/resolv.conf file\n"); 170 fprintf(stderr, "Error: cannot create /etc/resolv.conf file\n");
171 exit(1); 171 exit(1);
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c
index 85fb70854..5df356d04 100644
--- a/src/firejail/fs_lib.c
+++ b/src/firejail/fs_lib.c
@@ -221,7 +221,7 @@ void fslib_mount_libs(const char *full_path, unsigned user) {
221 sbox_run(mask | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); 221 sbox_run(mask | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE);
222 222
223 // open the list of libraries and install them on by one 223 // open the list of libraries and install them on by one
224 FILE *fp = fopen(RUN_LIB_FILE, "r"); 224 FILE *fp = fopen(RUN_LIB_FILE, "re");
225 if (!fp) 225 if (!fp)
226 errExit("fopen"); 226 errExit("fopen");
227 227
diff --git a/src/firejail/fs_logger.c b/src/firejail/fs_logger.c
index 67ad4b52e..604e297b1 100644
--- a/src/firejail/fs_logger.c
+++ b/src/firejail/fs_logger.c
@@ -92,7 +92,7 @@ void fs_logger_print(void) {
92 if (!head) 92 if (!head)
93 return; 93 return;
94 94
95 FILE *fp = fopen(RUN_FSLOGGER_FILE, "a"); 95 FILE *fp = fopen(RUN_FSLOGGER_FILE, "ae");
96 if (!fp) { 96 if (!fp) {
97 perror("fopen"); 97 perror("fopen");
98 return; 98 return;
@@ -123,15 +123,8 @@ void fs_logger_print_log(pid_t pid) {
123 // in case the pid is that of a firejail process, use the pid of the first child process 123 // in case the pid is that of a firejail process, use the pid of the first child process
124 pid = switch_to_child(pid); 124 pid = switch_to_child(pid);
125 125
126 // check privileges for non-root users 126 // exit if no permission to join the sandbox
127 uid_t uid = getuid(); 127 check_join_permission(pid);
128 if (uid != 0) {
129 uid_t sandbox_uid = pid_get_uid(pid);
130 if (uid != sandbox_uid) {
131 fprintf(stderr, "Error: permission denied\n");
132 exit(1);
133 }
134 }
135 128
136 // print RUN_FSLOGGER_FILE 129 // print RUN_FSLOGGER_FILE
137 char *fname; 130 char *fname;
@@ -139,24 +132,16 @@ void fs_logger_print_log(pid_t pid) {
139 errExit("asprintf"); 132 errExit("asprintf");
140 133
141 EUID_ROOT(); 134 EUID_ROOT();
142 struct stat s; 135 FILE *fp = fopen(fname, "re");
143 if (stat(fname, &s) == -1 || s.st_uid != 0) { 136 free(fname);
144 fprintf(stderr, "Error: Cannot access filesystem log\n");
145 exit(1);
146 }
147
148 /* coverity[toctou] */
149 FILE *fp = fopen(fname, "r");
150 if (!fp) { 137 if (!fp) {
151 fprintf(stderr, "Error: Cannot open filesystem log\n"); 138 fprintf(stderr, "Error: Cannot open filesystem log\n");
152 exit(1); 139 exit(1);
153 } 140 }
154
155 char buf[MAXBUF]; 141 char buf[MAXBUF];
156 while (fgets(buf, MAXBUF, fp)) 142 while (fgets(buf, MAXBUF, fp))
157 printf("%s", buf); 143 printf("%s", buf);
158 fclose(fp); 144 fclose(fp);
159 free(fname);
160 145
161 exit(0); 146 exit(0);
162} 147}
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c
index 8f939b5f5..1fc38361e 100644
--- a/src/firejail/fs_trace.c
+++ b/src/firejail/fs_trace.c
@@ -33,8 +33,7 @@ void fs_trace_preload(void) {
33 if (stat("/etc/ld.so.preload", &s)) { 33 if (stat("/etc/ld.so.preload", &s)) {
34 if (arg_debug) 34 if (arg_debug)
35 printf("Creating an empty /etc/ld.so.preload file\n"); 35 printf("Creating an empty /etc/ld.so.preload file\n");
36 /* coverity[toctou] */ 36 FILE *fp = fopen("/etc/ld.so.preload", "wxe");
37 FILE *fp = fopen("/etc/ld.so.preload", "w");
38 if (!fp) 37 if (!fp)
39 errExit("fopen"); 38 errExit("fopen");
40 SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); 39 SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH);
@@ -64,11 +63,11 @@ void fs_tracefile(void) {
64 if (ftruncate(fd, 0) == -1) 63 if (ftruncate(fd, 0) == -1)
65 errExit("ftruncate"); 64 errExit("ftruncate");
66 EUID_ROOT(); 65 EUID_ROOT();
67 FILE *fp = fopen(RUN_TRACE_FILE, "w"); 66 FILE *fp = fopen(RUN_TRACE_FILE, "we");
68 if (!fp) 67 if (!fp)
69 errExit("fopen " RUN_TRACE_FILE); 68 errExit("fopen " RUN_TRACE_FILE);
70 fclose(fp); 69 fclose(fp);
71 fs_logger2("touch ", arg_tracefile); 70 fs_logger2("touch", arg_tracefile);
72 // mount using the symbolic link in /proc/self/fd 71 // mount using the symbolic link in /proc/self/fd
73 if (arg_debug) 72 if (arg_debug)
74 printf("Bind mount %s to %s\n", arg_tracefile, RUN_TRACE_FILE); 73 printf("Bind mount %s to %s\n", arg_tracefile, RUN_TRACE_FILE);
@@ -88,7 +87,7 @@ void fs_trace(void) {
88 if (arg_debug) 87 if (arg_debug)
89 printf("Create the new ld.so.preload file\n"); 88 printf("Create the new ld.so.preload file\n");
90 89
91 FILE *fp = fopen(RUN_LDPRELOAD_FILE, "w"); 90 FILE *fp = fopen(RUN_LDPRELOAD_FILE, "we");
92 if (!fp) 91 if (!fp)
93 errExit("fopen"); 92 errExit("fopen");
94 const char *prefix = RUN_FIREJAIL_LIB_DIR; 93 const char *prefix = RUN_FIREJAIL_LIB_DIR;
diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c
index f07581cd8..bae3d6df0 100644
--- a/src/firejail/fs_var.c
+++ b/src/firejail/fs_var.c
@@ -127,7 +127,7 @@ void fs_var_log(void) {
127 127
128 // create an empty /var/log/wtmp file 128 // create an empty /var/log/wtmp file
129 /* coverity[toctou] */ 129 /* coverity[toctou] */
130 FILE *fp = fopen("/var/log/wtmp", "w"); 130 FILE *fp = fopen("/var/log/wtmp", "wxe");
131 if (fp) { 131 if (fp) {
132 SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH); 132 SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH);
133 fclose(fp); 133 fclose(fp);
@@ -135,7 +135,7 @@ void fs_var_log(void) {
135 fs_logger("touch /var/log/wtmp"); 135 fs_logger("touch /var/log/wtmp");
136 136
137 // create an empty /var/log/btmp file 137 // create an empty /var/log/btmp file
138 fp = fopen("/var/log/btmp", "w"); 138 fp = fopen("/var/log/btmp", "wxe");
139 if (fp) { 139 if (fp) {
140 SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP); 140 SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP);
141 fclose(fp); 141 fclose(fp);
@@ -158,8 +158,7 @@ void fs_var_lib(void) {
158 fs_logger("tmpfs /var/lib/dhcp"); 158 fs_logger("tmpfs /var/lib/dhcp");
159 159
160 // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file 160 // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file
161 FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "w"); 161 FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "wxe");
162
163 if (fp) { 162 if (fp) {
164 fprintf(fp, "\n"); 163 fprintf(fp, "\n");
165 SET_PERMS_STREAM(fp, 0, 0, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 164 SET_PERMS_STREAM(fp, 0, 0, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
@@ -287,7 +286,7 @@ void fs_var_utmp(void) {
287 if (stat(UTMP_FILE, &s) == 0) 286 if (stat(UTMP_FILE, &s) == 0)
288 utmp_group = s.st_gid; 287 utmp_group = s.st_gid;
289 else { 288 else {
290 fwarning("cannot find /var/run/utmp\n"); 289 fwarning("cannot find %s\n", UTMP_FILE);
291 return; 290 return;
292 } 291 }
293 292
@@ -296,7 +295,7 @@ void fs_var_utmp(void) {
296 printf("Create the new utmp file\n"); 295 printf("Create the new utmp file\n");
297 296
298 /* coverity[toctou] */ 297 /* coverity[toctou] */
299 FILE *fp = fopen(RUN_UTMP_FILE, "w"); 298 FILE *fp = fopen(RUN_UTMP_FILE, "we");
300 if (!fp) 299 if (!fp)
301 errExit("fopen"); 300 errExit("fopen");
302 301
@@ -323,5 +322,5 @@ void fs_var_utmp(void) {
323 printf("Mount the new utmp file\n"); 322 printf("Mount the new utmp file\n");
324 if (mount(RUN_UTMP_FILE, UTMP_FILE, NULL, MS_BIND|MS_NOSUID|MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) 323 if (mount(RUN_UTMP_FILE, UTMP_FILE, NULL, MS_BIND|MS_NOSUID|MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
325 errExit("mount bind utmp"); 324 errExit("mount bind utmp");
326 fs_logger("create /var/run/utmp"); 325 fs_logger2("create", UTMP_FILE);
327} 326}
diff --git a/src/firejail/join.c b/src/firejail/join.c
index 1575a7469..bab4b830f 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -103,7 +103,7 @@ static void extract_x11_display(pid_t pid) {
103 if (asprintf(&fname, "%s/%d", RUN_FIREJAIL_X11_DIR, pid) == -1) 103 if (asprintf(&fname, "%s/%d", RUN_FIREJAIL_X11_DIR, pid) == -1)
104 errExit("asprintf"); 104 errExit("asprintf");
105 105
106 FILE *fp = fopen(fname, "r"); 106 FILE *fp = fopen(fname, "re");
107 free(fname); 107 free(fname);
108 if (!fp) 108 if (!fp)
109 return; 109 return;
@@ -219,7 +219,7 @@ static void extract_caps(pid_t pid) {
219 perror("asprintf"); 219 perror("asprintf");
220 exit(1); 220 exit(1);
221 } 221 }
222 FILE *fp = fopen(file, "r"); 222 FILE *fp = fopen(file, "re");
223 if (!fp) 223 if (!fp)
224 goto errexit; 224 goto errexit;
225 225
@@ -266,7 +266,7 @@ static void extract_user_namespace(pid_t pid) {
266 char *uidmap; 266 char *uidmap;
267 if (asprintf(&uidmap, "/proc/%u/uid_map", pid) == -1) 267 if (asprintf(&uidmap, "/proc/%u/uid_map", pid) == -1)
268 errExit("asprintf"); 268 errExit("asprintf");
269 FILE *fp = fopen(uidmap, "r"); 269 FILE *fp = fopen(uidmap, "re");
270 if (!fp) { 270 if (!fp) {
271 free(uidmap); 271 free(uidmap);
272 return; 272 return;
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index 63ef2309b..796c42290 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -221,7 +221,7 @@ void cat(const char *path) {
221 221
222 if (arg_debug) 222 if (arg_debug)
223 printf("cat %s\n", path); 223 printf("cat %s\n", path);
224 FILE *fp = fopen(path, "r"); 224 FILE *fp = fopen(path, "re");
225 if (!fp) { 225 if (!fp) {
226 fprintf(stderr, "Error: cannot read %s\n", path); 226 fprintf(stderr, "Error: cannot read %s\n", path);
227 exit(1); 227 exit(1);
diff --git a/src/firejail/macros.c b/src/firejail/macros.c
index 7f2f6dbf3..bcac1feb4 100644
--- a/src/firejail/macros.c
+++ b/src/firejail/macros.c
@@ -99,7 +99,7 @@ static char *resolve_xdg(const char *var) {
99 99
100 if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1) 100 if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1)
101 errExit("asprintf"); 101 errExit("asprintf");
102 FILE *fp = fopen(fname, "r"); 102 FILE *fp = fopen(fname, "re");
103 if (!fp) { 103 if (!fp) {
104 free(fname); 104 free(fname);
105 return NULL; 105 return NULL;
diff --git a/src/firejail/main.c b/src/firejail/main.c
index b3524fcf5..593835843 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -116,7 +116,6 @@ int arg_private_cwd = 0; // private working directory
116int arg_scan = 0; // arp-scan all interfaces 116int arg_scan = 0; // arp-scan all interfaces
117int arg_whitelist = 0; // whitelist command 117int arg_whitelist = 0; // whitelist command
118int arg_nosound = 0; // disable sound 118int arg_nosound = 0; // disable sound
119int arg_noautopulse = 0; // disable automatic ~/.config/pulse init
120int arg_novideo = 0; //disable video devices in /dev 119int arg_novideo = 0; //disable video devices in /dev
121int arg_no3d; // disable 3d hardware acceleration 120int arg_no3d; // disable 3d hardware acceleration
122int arg_quiet = 0; // no output for scripting 121int arg_quiet = 0; // no output for scripting
@@ -125,6 +124,7 @@ int arg_join_filesystem = 0; // join only the mount namespace
125int arg_nice = 0; // nice value configured 124int arg_nice = 0; // nice value configured
126int arg_ipc = 0; // enable ipc namespace 125int arg_ipc = 0; // enable ipc namespace
127int arg_writable_etc = 0; // writable etc 126int arg_writable_etc = 0; // writable etc
127int arg_keep_config_pulse = 0; // disable automatic ~/.config/pulse init
128int arg_writable_var = 0; // writable var 128int arg_writable_var = 0; // writable var
129int arg_keep_var_tmp = 0; // don't overwrite /var/tmp 129int arg_keep_var_tmp = 0; // don't overwrite /var/tmp
130int arg_writable_run_user = 0; // writable /run/user 130int arg_writable_run_user = 0; // writable /run/user
@@ -143,6 +143,7 @@ int arg_memory_deny_write_execute = 0; // block writable and executable memory
143int arg_notv = 0; // --notv 143int arg_notv = 0; // --notv
144int arg_nodvd = 0; // --nodvd 144int arg_nodvd = 0; // --nodvd
145int arg_nou2f = 0; // --nou2f 145int arg_nou2f = 0; // --nou2f
146int arg_noinput = 0; // --noinput
146int arg_deterministic_exit_code = 0; // always exit with first child's exit status 147int arg_deterministic_exit_code = 0; // always exit with first child's exit status
147DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user 148DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user
148DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system 149DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system
@@ -534,7 +535,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
534 char *fname; 535 char *fname;
535 if (asprintf(&fname, RUN_FIREJAIL_PROFILE_DIR "/%d", pid) == -1) 536 if (asprintf(&fname, RUN_FIREJAIL_PROFILE_DIR "/%d", pid) == -1)
536 errExit("asprintf"); 537 errExit("asprintf");
537 FILE *fp = fopen(fname, "r"); 538 FILE *fp = fopen(fname, "re");
538 if (!fp) { 539 if (!fp) {
539 fprintf(stderr, "Error: sandbox %s not found\n", argv[i] + 16); 540 fprintf(stderr, "Error: sandbox %s not found\n", argv[i] + 16);
540 exit(1); 541 exit(1);
@@ -1042,7 +1043,7 @@ int main(int argc, char **argv, char **envp) {
1042 preproc_build_firejail_dir(); 1043 preproc_build_firejail_dir();
1043 const char *container_name = env_get("container"); 1044 const char *container_name = env_get("container");
1044 if (!container_name || strcmp(container_name, "firejail")) { 1045 if (!container_name || strcmp(container_name, "firejail")) {
1045 lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); 1046 lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
1046 if (lockfd_directory != -1) { 1047 if (lockfd_directory != -1) {
1047 int rv = fchown(lockfd_directory, 0, 0); 1048 int rv = fchown(lockfd_directory, 0, 0);
1048 (void) rv; 1049 (void) rv;
@@ -1144,7 +1145,7 @@ int main(int argc, char **argv, char **envp) {
1144 1145
1145#ifdef DEBUG_RESTRICTED_SHELL 1146#ifdef DEBUG_RESTRICTED_SHELL
1146 {EUID_ROOT(); 1147 {EUID_ROOT();
1147 FILE *fp = fopen("/firelog", "w"); 1148 FILE *fp = fopen("/firelog", "we");
1148 if (fp) { 1149 if (fp) {
1149 int i; 1150 int i;
1150 fprintf(fp, "argc %d: ", argc); 1151 fprintf(fp, "argc %d: ", argc);
@@ -1163,7 +1164,7 @@ int main(int argc, char **argv, char **envp) {
1163 strncmp(argv[2], "scp ", 4) == 0) { 1164 strncmp(argv[2], "scp ", 4) == 0) {
1164#ifdef DEBUG_RESTRICTED_SHELL 1165#ifdef DEBUG_RESTRICTED_SHELL
1165 {EUID_ROOT(); 1166 {EUID_ROOT();
1166 FILE *fp = fopen("/firelog", "a"); 1167 FILE *fp = fopen("/firelog", "ae");
1167 if (fp) { 1168 if (fp) {
1168 fprintf(fp, "run without a sandbox\n"); 1169 fprintf(fp, "run without a sandbox\n");
1169 fclose(fp); 1170 fclose(fp);
@@ -1196,7 +1197,7 @@ int main(int argc, char **argv, char **envp) {
1196 1197
1197#ifdef DEBUG_RESTRICTED_SHELL 1198#ifdef DEBUG_RESTRICTED_SHELL
1198 {EUID_ROOT(); 1199 {EUID_ROOT();
1199 FILE *fp = fopen("/firelog", "a"); 1200 FILE *fp = fopen("/firelog", "ae");
1200 if (fp) { 1201 if (fp) {
1201 fprintf(fp, "fullargc %d: ", fullargc); 1202 fprintf(fp, "fullargc %d: ", fullargc);
1202 int i; 1203 int i;
@@ -1218,7 +1219,7 @@ int main(int argc, char **argv, char **envp) {
1218 1219
1219#ifdef DEBUG_RESTRICTED_SHELL 1220#ifdef DEBUG_RESTRICTED_SHELL
1220 {EUID_ROOT(); 1221 {EUID_ROOT();
1221 FILE *fp = fopen("/firelog", "a"); 1222 FILE *fp = fopen("/firelog", "ae");
1222 if (fp) { 1223 if (fp) {
1223 fprintf(fp, "argc %d: ", argc); 1224 fprintf(fp, "argc %d: ", argc);
1224 int i; 1225 int i;
@@ -1823,6 +1824,8 @@ int main(int argc, char **argv, char **envp) {
1823 exit(1); 1824 exit(1);
1824 } 1825 }
1825 arg_noprofile = 1; 1826 arg_noprofile = 1;
1827 // force keep-config-pulse in order to keep ~/.config/pulse as is
1828 arg_keep_config_pulse = 1;
1826 } 1829 }
1827 else if (strncmp(argv[i], "--ignore=", 9) == 0) { 1830 else if (strncmp(argv[i], "--ignore=", 9) == 0) {
1828 if (custom_profile) { 1831 if (custom_profile) {
@@ -1873,6 +1876,9 @@ int main(int argc, char **argv, char **envp) {
1873 } 1876 }
1874 arg_writable_etc = 1; 1877 arg_writable_etc = 1;
1875 } 1878 }
1879 else if (strcmp(argv[i], "--keep-config-pulse") == 0) {
1880 arg_keep_config_pulse = 1;
1881 }
1876 else if (strcmp(argv[i], "--writable-var") == 0) { 1882 else if (strcmp(argv[i], "--writable-var") == 0) {
1877 arg_writable_var = 1; 1883 arg_writable_var = 1;
1878 } 1884 }
@@ -2075,7 +2081,7 @@ int main(int argc, char **argv, char **envp) {
2075 else if (strcmp(argv[i], "--nosound") == 0) 2081 else if (strcmp(argv[i], "--nosound") == 0)
2076 arg_nosound = 1; 2082 arg_nosound = 1;
2077 else if (strcmp(argv[i], "--noautopulse") == 0) 2083 else if (strcmp(argv[i], "--noautopulse") == 0)
2078 arg_noautopulse = 1; 2084 arg_keep_config_pulse = 1;
2079 else if (strcmp(argv[i], "--novideo") == 0) 2085 else if (strcmp(argv[i], "--novideo") == 0)
2080 arg_novideo = 1; 2086 arg_novideo = 1;
2081 else if (strcmp(argv[i], "--no3d") == 0) 2087 else if (strcmp(argv[i], "--no3d") == 0)
@@ -2086,6 +2092,8 @@ int main(int argc, char **argv, char **envp) {
2086 arg_nodvd = 1; 2092 arg_nodvd = 1;
2087 else if (strcmp(argv[i], "--nou2f") == 0) 2093 else if (strcmp(argv[i], "--nou2f") == 0)
2088 arg_nou2f = 1; 2094 arg_nou2f = 1;
2095 else if (strcmp(argv[i], "--noinput") == 0)
2096 arg_noinput = 1;
2089 else if (strcmp(argv[i], "--nodbus") == 0) { 2097 else if (strcmp(argv[i], "--nodbus") == 0) {
2090 arg_dbus_user = DBUS_POLICY_BLOCK; 2098 arg_dbus_user = DBUS_POLICY_BLOCK;
2091 arg_dbus_system = DBUS_POLICY_BLOCK; 2099 arg_dbus_system = DBUS_POLICY_BLOCK;
@@ -2847,7 +2855,7 @@ int main(int argc, char **argv, char **envp) {
2847 // check and assign an IP address - for macvlan it will be done again in the sandbox! 2855 // check and assign an IP address - for macvlan it will be done again in the sandbox!
2848 if (any_bridge_configured()) { 2856 if (any_bridge_configured()) {
2849 EUID_ROOT(); 2857 EUID_ROOT();
2850 lockfd_network = open(RUN_NETWORK_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); 2858 lockfd_network = open(RUN_NETWORK_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
2851 if (lockfd_network != -1) { 2859 if (lockfd_network != -1) {
2852 int rv = fchown(lockfd_network, 0, 0); 2860 int rv = fchown(lockfd_network, 0, 0);
2853 (void) rv; 2861 (void) rv;
@@ -2869,12 +2877,6 @@ int main(int argc, char **argv, char **envp) {
2869 } 2877 }
2870 EUID_ASSERT(); 2878 EUID_ASSERT();
2871 2879
2872 // create the parent-child communication pipe
2873 if (pipe(parent_to_child_fds) < 0)
2874 errExit("pipe");
2875 if (pipe(child_to_parent_fds) < 0)
2876 errExit("pipe");
2877
2878 if (arg_noroot && arg_overlay) { 2880 if (arg_noroot && arg_overlay) {
2879 fwarning("--overlay and --noroot are mutually exclusive, noroot disabled\n"); 2881 fwarning("--overlay and --noroot are mutually exclusive, noroot disabled\n");
2880 arg_noroot = 0; 2882 arg_noroot = 0;
@@ -2887,7 +2889,7 @@ int main(int argc, char **argv, char **envp) {
2887 2889
2888 // set name and x11 run files 2890 // set name and x11 run files
2889 EUID_ROOT(); 2891 EUID_ROOT();
2890 lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); 2892 lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
2891 if (lockfd_directory != -1) { 2893 if (lockfd_directory != -1) {
2892 int rv = fchown(lockfd_directory, 0, 0); 2894 int rv = fchown(lockfd_directory, 0, 0);
2893 (void) rv; 2895 (void) rv;
@@ -2916,6 +2918,12 @@ int main(int argc, char **argv, char **envp) {
2916 } 2918 }
2917#endif 2919#endif
2918 2920
2921 // create the parent-child communication pipe
2922 if (pipe2(parent_to_child_fds, O_CLOEXEC) < 0)
2923 errExit("pipe");
2924 if (pipe2(child_to_parent_fds, O_CLOEXEC) < 0)
2925 errExit("pipe");
2926
2919 // clone environment 2927 // clone environment
2920 int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD; 2928 int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD;
2921 2929
diff --git a/src/firejail/network.c b/src/firejail/network.c
index f7142cefd..289e164c6 100644
--- a/src/firejail/network.c
+++ b/src/firejail/network.c
@@ -217,7 +217,7 @@ int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) {
217 217
218#define BUFSIZE 1024 218#define BUFSIZE 1024
219uint32_t network_get_defaultgw(void) { 219uint32_t network_get_defaultgw(void) {
220 FILE *fp = fopen("/proc/self/net/route", "r"); 220 FILE *fp = fopen("/proc/self/net/route", "re");
221 if (!fp) 221 if (!fp)
222 errExit("fopen"); 222 errExit("fopen");
223 223
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c
index ee3c00872..d3e75bbed 100644
--- a/src/firejail/network_main.c
+++ b/src/firejail/network_main.c
@@ -292,7 +292,7 @@ void net_dns_print(pid_t pid) {
292 errExit("chdir"); 292 errExit("chdir");
293 293
294 // access /etc/resolv.conf 294 // access /etc/resolv.conf
295 FILE *fp = fopen("/etc/resolv.conf", "r"); 295 FILE *fp = fopen("/etc/resolv.conf", "re");
296 if (!fp) { 296 if (!fp) {
297 fprintf(stderr, "Error: cannot access /etc/resolv.conf\n"); 297 fprintf(stderr, "Error: cannot access /etc/resolv.conf\n");
298 exit(1); 298 exit(1);
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c
index 60a82821e..0e153c47b 100644
--- a/src/firejail/no_sandbox.c
+++ b/src/firejail/no_sandbox.c
@@ -20,6 +20,7 @@
20#include "firejail.h" 20#include "firejail.h"
21#include <sys/types.h> 21#include <sys/types.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <errno.h>
23#include <unistd.h> 24#include <unistd.h>
24#include <grp.h> 25#include <grp.h>
25 26
@@ -47,7 +48,7 @@ int check_namespace_virt(void) {
47 48
48 // check PID 1 container environment variable 49 // check PID 1 container environment variable
49 EUID_ROOT(); 50 EUID_ROOT();
50 FILE *fp = fopen("/proc/1/environ", "r"); 51 FILE *fp = fopen("/proc/1/environ", "re");
51 if (fp) { 52 if (fp) {
52 int c = 0; 53 int c = 0;
53 while (c != EOF) { 54 while (c != EOF) {
@@ -105,20 +106,15 @@ int check_kernel_procs(void) {
105 // look at the first 10 processes 106 // look at the first 10 processes
106 // if a kernel process is found, return 1 107 // if a kernel process is found, return 1
107 for (i = 1; i <= 10; i++) { 108 for (i = 1; i <= 10; i++) {
108 struct stat s;
109 char *fname; 109 char *fname;
110 if (asprintf(&fname, "/proc/%d/comm", i) == -1) 110 if (asprintf(&fname, "/proc/%d/comm", i) == -1)
111 errExit("asprintf"); 111 errExit("asprintf");
112 if (stat(fname, &s) == -1) {
113 free(fname);
114 continue;
115 }
116 112
117 // open file 113 // open file
118 /* coverity[toctou] */ 114 FILE *fp = fopen(fname, "re");
119 FILE *fp = fopen(fname, "r");
120 if (!fp) { 115 if (!fp) {
121 fwarning("cannot open %s\n", fname); 116 if (errno != ENOENT)
117 fwarning("cannot open %s\n", fname);
122 free(fname); 118 free(fname);
123 continue; 119 continue;
124 } 120 }
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c
index 7f602545d..1aafd1ca2 100644
--- a/src/firejail/preproc.c
+++ b/src/firejail/preproc.c
@@ -164,7 +164,7 @@ void preproc_clean_run(void) {
164 int max_pids=32769; 164 int max_pids=32769;
165 int start_pid = 100; 165 int start_pid = 100;
166 // extract real max_pids 166 // extract real max_pids
167 FILE *fp = fopen("/proc/sys/kernel/pid_max", "r"); 167 FILE *fp = fopen("/proc/sys/kernel/pid_max", "re");
168 if (fp) { 168 if (fp) {
169 int val; 169 int val;
170 if (fscanf(fp, "%d", &val) == 1) { 170 if (fscanf(fp, "%d", &val) == 1) {
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 351b760df..dd4506ac1 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -423,7 +423,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
423 return 0; 423 return 0;
424 } 424 }
425 else if (strcmp(ptr, "noautopulse") == 0) { 425 else if (strcmp(ptr, "noautopulse") == 0) {
426 arg_noautopulse = 1; 426 arg_keep_config_pulse = 1;
427 return 0; 427 return 0;
428 } 428 }
429 else if (strcmp(ptr, "notv") == 0) { 429 else if (strcmp(ptr, "notv") == 0) {
@@ -442,6 +442,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
442 arg_no3d = 1; 442 arg_no3d = 1;
443 return 0; 443 return 0;
444 } 444 }
445 else if (strcmp(ptr, "noinput") == 0) {
446 arg_noinput = 1;
447 return 0;
448 }
445 else if (strcmp(ptr, "nodbus") == 0) { 449 else if (strcmp(ptr, "nodbus") == 0) {
446#ifdef HAVE_DBUSPROXY 450#ifdef HAVE_DBUSPROXY
447 arg_dbus_user = DBUS_POLICY_BLOCK; 451 arg_dbus_user = DBUS_POLICY_BLOCK;
@@ -1139,6 +1143,12 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1139 arg_machineid = 1; 1143 arg_machineid = 1;
1140 return 0; 1144 return 0;
1141 } 1145 }
1146
1147 if (strcmp(ptr, "keep-config-pulse") == 0) {
1148 arg_keep_config_pulse = 1;
1149 return 0;
1150 }
1151
1142 // writable-var 1152 // writable-var
1143 if (strcmp(ptr, "writable-var") == 0) { 1153 if (strcmp(ptr, "writable-var") == 0) {
1144 arg_writable_var = 1; 1154 arg_writable_var = 1;
@@ -1687,7 +1697,7 @@ void profile_read(const char *fname) {
1687 } 1697 }
1688 1698
1689 // open profile file: 1699 // open profile file:
1690 FILE *fp = fopen(fname, "r"); 1700 FILE *fp = fopen(fname, "re");
1691 if (fp == NULL) { 1701 if (fp == NULL) {
1692 fprintf(stderr, "Error: cannot open profile file %s\n", fname); 1702 fprintf(stderr, "Error: cannot open profile file %s\n", fname);
1693 exit(1); 1703 exit(1);
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c
index 926af7967..f21f8c96e 100644
--- a/src/firejail/protocol.c
+++ b/src/firejail/protocol.c
@@ -23,7 +23,7 @@
23 23
24void protocol_filter_save(void) { 24void protocol_filter_save(void) {
25 // save protocol filter configuration in PROTOCOL_CFG 25 // save protocol filter configuration in PROTOCOL_CFG
26 FILE *fp = fopen(RUN_PROTOCOL_CFG, "w"); 26 FILE *fp = fopen(RUN_PROTOCOL_CFG, "wxe");
27 if (!fp) 27 if (!fp)
28 errExit("fopen"); 28 errExit("fopen");
29 fprintf(fp, "%s\n", cfg.protocol); 29 fprintf(fp, "%s\n", cfg.protocol);
@@ -35,7 +35,7 @@ void protocol_filter_load(const char *fname) {
35 assert(fname); 35 assert(fname);
36 36
37 // read protocol filter configuration from PROTOCOL_CFG 37 // read protocol filter configuration from PROTOCOL_CFG
38 FILE *fp = fopen(fname, "r"); 38 FILE *fp = fopen(fname, "re");
39 if (!fp) 39 if (!fp)
40 return; 40 return;
41 41
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index a50134893..1b01a71c6 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -106,7 +106,7 @@ void pulseaudio_init(void) {
106 errExit("asprintf"); 106 errExit("asprintf");
107 if (copy_file(PULSE_CLIENT_SYSCONF, pulsecfg, -1, -1, 0644)) // root needed 107 if (copy_file(PULSE_CLIENT_SYSCONF, pulsecfg, -1, -1, 0644)) // root needed
108 errExit("copy_file"); 108 errExit("copy_file");
109 FILE *fp = fopen(pulsecfg, "a"); 109 FILE *fp = fopen(pulsecfg, "ae");
110 if (!fp) 110 if (!fp)
111 errExit("fopen"); 111 errExit("fopen");
112 fprintf(fp, "%s", "\nenable-shm = no\n"); 112 fprintf(fp, "%s", "\nenable-shm = no\n");
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c
index 8368d84a1..53e395b89 100644
--- a/src/firejail/restrict_users.c
+++ b/src/firejail/restrict_users.c
@@ -183,10 +183,10 @@ static void sanitize_passwd(void) {
183 183
184 // open files 184 // open files
185 /* coverity[toctou] */ 185 /* coverity[toctou] */
186 fpin = fopen("/etc/passwd", "r"); 186 fpin = fopen("/etc/passwd", "re");
187 if (!fpin) 187 if (!fpin)
188 goto errout; 188 goto errout;
189 fpout = fopen(RUN_PASSWD_FILE, "w"); 189 fpout = fopen(RUN_PASSWD_FILE, "we");
190 if (!fpout) 190 if (!fpout)
191 goto errout; 191 goto errout;
192 192
@@ -318,10 +318,10 @@ static void sanitize_group(void) {
318 318
319 // open files 319 // open files
320 /* coverity[toctou] */ 320 /* coverity[toctou] */
321 fpin = fopen("/etc/group", "r"); 321 fpin = fopen("/etc/group", "re");
322 if (!fpin) 322 if (!fpin)
323 goto errout; 323 goto errout;
324 fpout = fopen(RUN_GROUP_FILE, "w"); 324 fpout = fopen(RUN_GROUP_FILE, "we");
325 if (!fpout) 325 if (!fpout)
326 goto errout; 326 goto errout;
327 327
diff --git a/src/firejail/restricted_shell.c b/src/firejail/restricted_shell.c
index ae453f4f1..ed66903b5 100644
--- a/src/firejail/restricted_shell.c
+++ b/src/firejail/restricted_shell.c
@@ -32,7 +32,7 @@ int restricted_shell(const char *user) {
32 char *fname; 32 char *fname;
33 if (asprintf(&fname, "%s/login.users", SYSCONFDIR) == -1) 33 if (asprintf(&fname, "%s/login.users", SYSCONFDIR) == -1)
34 errExit("asprintf"); 34 errExit("asprintf");
35 FILE *fp = fopen(fname, "r"); 35 FILE *fp = fopen(fname, "re");
36 free(fname); 36 free(fname);
37 if (fp == NULL) 37 if (fp == NULL)
38 return 0; 38 return 0;
@@ -96,7 +96,7 @@ int restricted_shell(const char *user) {
96 fullargv[i] = ptr; 96 fullargv[i] = ptr;
97#ifdef DEBUG_RESTRICTED_SHELL 97#ifdef DEBUG_RESTRICTED_SHELL
98 {EUID_ROOT(); 98 {EUID_ROOT();
99 FILE *fp = fopen("/firelog", "a"); 99 FILE *fp = fopen("/firelog", "ae");
100 if (fp) { 100 if (fp) {
101 fprintf(fp, "i %d ptr #%s#\n", i, fullargv[i]); 101 fprintf(fp, "i %d ptr #%s#\n", i, fullargv[i]);
102 fclose(fp); 102 fclose(fp);
diff --git a/src/firejail/run_files.c b/src/firejail/run_files.c
index cd44f745f..c28c3e01b 100644
--- a/src/firejail/run_files.c
+++ b/src/firejail/run_files.c
@@ -101,7 +101,7 @@ void set_name_run_file(pid_t pid) {
101 errExit("asprintf"); 101 errExit("asprintf");
102 102
103 // the file is deleted first 103 // the file is deleted first
104 FILE *fp = fopen(fname, "w"); 104 FILE *fp = fopen(fname, "we");
105 if (!fp) { 105 if (!fp) {
106 fprintf(stderr, "Error: cannot create %s\n", fname); 106 fprintf(stderr, "Error: cannot create %s\n", fname);
107 exit(1); 107 exit(1);
@@ -120,7 +120,7 @@ void set_x11_run_file(pid_t pid, int display) {
120 errExit("asprintf"); 120 errExit("asprintf");
121 121
122 // the file is deleted first 122 // the file is deleted first
123 FILE *fp = fopen(fname, "w"); 123 FILE *fp = fopen(fname, "we");
124 if (!fp) { 124 if (!fp) {
125 fprintf(stderr, "Error: cannot create %s\n", fname); 125 fprintf(stderr, "Error: cannot create %s\n", fname);
126 exit(1); 126 exit(1);
@@ -139,7 +139,7 @@ void set_profile_run_file(pid_t pid, const char *fname) {
139 139
140 EUID_ROOT(); 140 EUID_ROOT();
141 // the file is deleted first 141 // the file is deleted first
142 FILE *fp = fopen(runfile, "w"); 142 FILE *fp = fopen(runfile, "we");
143 if (!fp) { 143 if (!fp) {
144 fprintf(stderr, "Error: cannot create %s\n", runfile); 144 fprintf(stderr, "Error: cannot create %s\n", runfile);
145 exit(1); 145 exit(1);
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 743d84b43..08f0f32c9 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -67,7 +67,7 @@ static void sandbox_handler(int sig){
67 if (asprintf(&monfile, "/proc/%d/cmdline", monitored_pid) == -1) 67 if (asprintf(&monfile, "/proc/%d/cmdline", monitored_pid) == -1)
68 errExit("asprintf"); 68 errExit("asprintf");
69 while (monsec) { 69 while (monsec) {
70 FILE *fp = fopen(monfile, "r"); 70 FILE *fp = fopen(monfile, "re");
71 if (!fp) 71 if (!fp)
72 break; 72 break;
73 73
@@ -162,7 +162,7 @@ static void save_nogroups(void) {
162 if (arg_nogroups == 0) 162 if (arg_nogroups == 0)
163 return; 163 return;
164 164
165 FILE *fp = fopen(RUN_GROUPS_CFG, "w"); 165 FILE *fp = fopen(RUN_GROUPS_CFG, "wxe");
166 if (fp) { 166 if (fp) {
167 fprintf(fp, "\n"); 167 fprintf(fp, "\n");
168 SET_PERMS_STREAM(fp, 0, 0, 0644); // assume mode 0644 168 SET_PERMS_STREAM(fp, 0, 0, 0644); // assume mode 0644
@@ -1015,7 +1015,7 @@ int sandbox(void* sandbox_arg) {
1015 // disable /dev/snd 1015 // disable /dev/snd
1016 fs_dev_disable_sound(); 1016 fs_dev_disable_sound();
1017 } 1017 }
1018 else if (!arg_noautopulse) 1018 else if (!arg_keep_config_pulse)
1019 pulseaudio_init(); 1019 pulseaudio_init();
1020 1020
1021 if (arg_no3d) 1021 if (arg_no3d)
@@ -1033,6 +1033,9 @@ int sandbox(void* sandbox_arg) {
1033 if (arg_novideo) 1033 if (arg_novideo)
1034 fs_dev_disable_video(); 1034 fs_dev_disable_video();
1035 1035
1036 if (arg_noinput)
1037 fs_dev_disable_input();
1038
1036 //**************************** 1039 //****************************
1037 // set dns 1040 // set dns
1038 //**************************** 1041 //****************************
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c
index f9c41f661..4a8dd1bf7 100644
--- a/src/firejail/sbox.c
+++ b/src/firejail/sbox.c
@@ -248,7 +248,9 @@ int sbox_run(unsigned filtermask, int num, ...) {
248 va_start(valist, num); 248 va_start(valist, num);
249 249
250 // build argument list 250 // build argument list
251 char **arg = malloc((num + 1) * sizeof(char *)); 251 char **arg = calloc(num + 1, sizeof(char *));
252 if (!arg)
253 errExit("calloc");
252 int i; 254 int i;
253 for (i = 0; i < num; i++) 255 for (i = 0; i < num; i++)
254 arg[i] = va_arg(valist, char *); 256 arg[i] = va_arg(valist, char *);
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index 785c29517..9670fe816 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -86,7 +86,7 @@ int seccomp_install_filters(void) {
86static void seccomp_save_file_list(const char *fname) { 86static void seccomp_save_file_list(const char *fname) {
87 assert(fname); 87 assert(fname);
88 88
89 FILE *fp = fopen(RUN_SECCOMP_LIST, "a+"); 89 FILE *fp = fopen(RUN_SECCOMP_LIST, "ae");
90 if (!fp) 90 if (!fp)
91 errExit("fopen"); 91 errExit("fopen");
92 92
@@ -99,7 +99,7 @@ static void seccomp_save_file_list(const char *fname) {
99#define MAXBUF 4096 99#define MAXBUF 4096
100static int load_file_list_flag = 0; 100static int load_file_list_flag = 0;
101void seccomp_load_file_list(void) { 101void seccomp_load_file_list(void) {
102 FILE *fp = fopen(RUN_SECCOMP_LIST, "r"); 102 FILE *fp = fopen(RUN_SECCOMP_LIST, "re");
103 if (!fp) 103 if (!fp)
104 return; // no seccomp configuration whatsoever 104 return; // no seccomp configuration whatsoever
105 105
@@ -122,7 +122,7 @@ int seccomp_load(const char *fname) {
122 assert(fname); 122 assert(fname);
123 123
124 // open filter file 124 // open filter file
125 int fd = open(fname, O_RDONLY); 125 int fd = open(fname, O_RDONLY|O_CLOEXEC);
126 if (fd == -1) 126 if (fd == -1)
127 goto errexit; 127 goto errexit;
128 128
@@ -438,7 +438,7 @@ void seccomp_print_filter(pid_t pid) {
438 if (stat(fname, &s) == -1) 438 if (stat(fname, &s) == -1)
439 goto errexit; 439 goto errexit;
440 440
441 FILE *fp = fopen(fname, "r"); 441 FILE *fp = fopen(fname, "re");
442 if (!fp) 442 if (!fp)
443 goto errexit; 443 goto errexit;
444 free(fname); 444 free(fname);
diff --git a/src/firejail/shutdown.c b/src/firejail/shutdown.c
index 8fb03d0a6..fbfe1765b 100644
--- a/src/firejail/shutdown.c
+++ b/src/firejail/shutdown.c
@@ -64,7 +64,7 @@ void shut(pid_t pid) {
64 monsec--; 64 monsec--;
65 65
66 EUID_ROOT(); 66 EUID_ROOT();
67 FILE *fp = fopen(monfile, "r"); 67 FILE *fp = fopen(monfile, "re");
68 EUID_USER(); 68 EUID_USER();
69 if (!fp) { 69 if (!fp) {
70 killdone = 1; 70 killdone = 1;
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 397150158..888a6ffed 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -114,7 +114,8 @@ static char *usage_str =
114 " --join-network=name|pid - join the network namespace.\n" 114 " --join-network=name|pid - join the network namespace.\n"
115#endif 115#endif
116 " --join-or-start=name|pid - join the sandbox or start a new one.\n" 116 " --join-or-start=name|pid - join the sandbox or start a new one.\n"
117 " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n" 117 " --keep-config-pulse - disable automatic ~/.config/pulse init.\n"
118 " --keep-dev-shm - /dev/shm directory is untouched (even with --private-dev).\n"
118 " --keep-var-tmp - /var/tmp directory is untouched.\n" 119 " --keep-var-tmp - /var/tmp directory is untouched.\n"
119 " --list - list all sandboxes.\n" 120 " --list - list all sandboxes.\n"
120#ifdef HAVE_FILE_TRANSFER 121#ifdef HAVE_FILE_TRANSFER
@@ -154,6 +155,7 @@ static char *usage_str =
154 " --nodvd - disable DVD and audio CD devices.\n" 155 " --nodvd - disable DVD and audio CD devices.\n"
155 " --noexec=filename - remount the file or directory noexec nosuid and nodev.\n" 156 " --noexec=filename - remount the file or directory noexec nosuid and nodev.\n"
156 " --nogroups - disable supplementary groups.\n" 157 " --nogroups - disable supplementary groups.\n"
158 " --noinput - disable input devices.\n"
157 " --nonewprivs - sets the NO_NEW_PRIVS prctl.\n" 159 " --nonewprivs - sets the NO_NEW_PRIVS prctl.\n"
158 " --noprofile - do not use a security profile.\n" 160 " --noprofile - do not use a security profile.\n"
159#ifdef HAVE_USERNS 161#ifdef HAVE_USERNS
diff --git a/src/firejail/util.c b/src/firejail/util.c
index def635ea7..2731f61dc 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -298,14 +298,14 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m
298 assert(destname); 298 assert(destname);
299 299
300 // open source 300 // open source
301 int src = open(srcname, O_RDONLY); 301 int src = open(srcname, O_RDONLY|O_CLOEXEC);
302 if (src < 0) { 302 if (src < 0) {
303 fwarning("cannot open source file %s, file not copied\n", srcname); 303 fwarning("cannot open source file %s, file not copied\n", srcname);
304 return -1; 304 return -1;
305 } 305 }
306 306
307 // open destination 307 // open destination
308 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 308 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
309 if (dst < 0) { 309 if (dst < 0) {
310 fwarning("cannot open destination file %s, file not copied\n", destname); 310 fwarning("cannot open destination file %s, file not copied\n", destname);
311 close(src); 311 close(src);
@@ -348,7 +348,7 @@ void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid
348 348
349void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { 349void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) {
350 // open destination 350 // open destination
351 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 351 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
352 if (dst < 0) { 352 if (dst < 0) {
353 fwarning("cannot open destination file %s, file not copied\n", destname); 353 fwarning("cannot open destination file %s, file not copied\n", destname);
354 return; 354 return;
@@ -361,7 +361,7 @@ void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_
361 // drop privileges 361 // drop privileges
362 drop_privs(0); 362 drop_privs(0);
363 363
364 int src = open(srcname, O_RDONLY); 364 int src = open(srcname, O_RDONLY|O_CLOEXEC);
365 if (src < 0) { 365 if (src < 0) {
366 fwarning("cannot open source file %s, file not copied\n", srcname); 366 fwarning("cannot open source file %s, file not copied\n", srcname);
367 } else { 367 } else {
@@ -626,7 +626,7 @@ int find_child(pid_t parent, pid_t *child) {
626 perror("asprintf"); 626 perror("asprintf");
627 exit(1); 627 exit(1);
628 } 628 }
629 FILE *fp = fopen(file, "r"); 629 FILE *fp = fopen(file, "re");
630 if (!fp) { 630 if (!fp) {
631 free(file); 631 free(file);
632 continue; 632 continue;
@@ -732,7 +732,7 @@ void update_map(char *mapping, char *map_file) {
732 if (mapping[j] == ',') 732 if (mapping[j] == ',')
733 mapping[j] = '\n'; 733 mapping[j] = '\n';
734 734
735 fd = open(map_file, O_RDWR); 735 fd = open(map_file, O_RDWR|O_CLOEXEC);
736 if (fd == -1) { 736 if (fd == -1) {
737 fprintf(stderr, "Error: cannot open %s: %s\n", map_file, strerror(errno)); 737 fprintf(stderr, "Error: cannot open %s: %s\n", map_file, strerror(errno));
738 exit(EXIT_FAILURE); 738 exit(EXIT_FAILURE);
@@ -752,9 +752,9 @@ void wait_for_other(int fd) {
752 // wait for the parent to be initialized 752 // wait for the parent to be initialized
753 //**************************** 753 //****************************
754 char childstr[BUFLEN + 1]; 754 char childstr[BUFLEN + 1];
755 int newfd = dup(fd); 755 int newfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
756 if (newfd == -1) 756 if (newfd == -1)
757 errExit("dup"); 757 errExit("fcntl");
758 FILE* stream; 758 FILE* stream;
759 stream = fdopen(newfd, "r"); 759 stream = fdopen(newfd, "r");
760 *childstr = '\0'; 760 *childstr = '\0';
@@ -801,9 +801,9 @@ void wait_for_other(int fd) {
801 801
802void notify_other(int fd) { 802void notify_other(int fd) {
803 FILE* stream; 803 FILE* stream;
804 int newfd = dup(fd); 804 int newfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
805 if (newfd == -1) 805 if (newfd == -1)
806 errExit("dup"); 806 errExit("fcntl");
807 stream = fdopen(newfd, "w"); 807 stream = fdopen(newfd, "w");
808 fprintf(stream, "arg_noroot=%d\n", arg_noroot); 808 fprintf(stream, "arg_noroot=%d\n", arg_noroot);
809 fflush(stream); 809 fflush(stream);
@@ -821,7 +821,7 @@ uid_t pid_get_uid(pid_t pid) {
821 exit(1); 821 exit(1);
822 } 822 }
823 EUID_ROOT(); // grsecurity fix 823 EUID_ROOT(); // grsecurity fix
824 FILE *fp = fopen(file, "r"); 824 FILE *fp = fopen(file, "re");
825 if (!fp) { 825 if (!fp) {
826 free(file); 826 free(file);
827 fprintf(stderr, "Error: cannot open /proc file\n"); 827 fprintf(stderr, "Error: cannot open /proc file\n");
@@ -1031,8 +1031,7 @@ void create_empty_file_as_root(const char *fname, mode_t mode) {
1031 if (arg_debug) 1031 if (arg_debug)
1032 printf("Creating empty %s file\n", fname); 1032 printf("Creating empty %s file\n", fname);
1033 1033
1034 /* coverity[toctou] */ 1034 FILE *fp = fopen(fname, "wxe");
1035 FILE *fp = fopen(fname, "w");
1036 if (!fp) 1035 if (!fp)
1037 errExit("fopen"); 1036 errExit("fopen");
1038 SET_PERMS_STREAM(fp, 0, 0, mode); 1037 SET_PERMS_STREAM(fp, 0, 0, mode);
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index da0acc69c..257d376a1 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -84,7 +84,7 @@ int x11_display(void) {
84static int x11_abstract_sockets_present(void) { 84static int x11_abstract_sockets_present(void) {
85 85
86 EUID_ROOT(); // grsecurity fix 86 EUID_ROOT(); // grsecurity fix
87 FILE *fp = fopen("/proc/net/unix", "r"); 87 FILE *fp = fopen("/proc/net/unix", "re");
88 if (!fp) 88 if (!fp)
89 errExit("fopen"); 89 errExit("fopen");
90 EUID_USER(); 90 EUID_USER();
@@ -1363,7 +1363,7 @@ void fs_x11(void) {
1363 fs_logger("tmpfs /tmp/.X11-unix"); 1363 fs_logger("tmpfs /tmp/.X11-unix");
1364 1364
1365 // create an empty root-owned file which will have the desired socket bind-mounted over it 1365 // create an empty root-owned file which will have the desired socket bind-mounted over it
1366 int fd = open(x11file, O_RDONLY|O_CREAT|O_EXCL, S_IRUSR | S_IWUSR); 1366 int fd = open(x11file, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR);
1367 if (fd < 0) 1367 if (fd < 0)
1368 errExit(x11file); 1368 errExit(x11file);
1369 close(fd); 1369 close(fd);
diff --git a/src/firemon/firemon.c b/src/firemon/firemon.c
index 37870747d..6c34cd411 100644
--- a/src/firemon/firemon.c
+++ b/src/firemon/firemon.c
@@ -52,7 +52,7 @@ static void my_handler(int s){
52 52
53 if (terminal_set) 53 if (terminal_set)
54 tcsetattr(0, TCSANOW, &tlocal); 54 tcsetattr(0, TCSANOW, &tlocal);
55 exit(0); 55 _exit(0);
56} 56}
57 57
58// find the second child process for the specified pid 58// find the second child process for the specified pid
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index ee685da73..49be8d0b0 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -1,12 +1,78 @@
1.TH FIREJAIL-PROFILE 5 "MONTH YEAR" "VERSION" "firejail profiles man page" 1.TH FIREJAIL-PROFILE 5 "MONTH YEAR" "VERSION" "firejail profiles man page"
2.SH NAME 2.SH NAME
3profile \- Security profile file syntax for Firejail 3profile \- Security profile file syntax, and information about building new application profiles.
4 4
5.SH USAGE 5.SH SYNOPSIS
6
7Using a specific profile:
8.PP
9.RS
10.TP
11\fBfirejail \-\-profile=filename.profile
12.br
13
14.br
15Example:
16.br
17$ firejail --profile=/etc/firejail/kdenlive.profile --appimage kdenlive.appimage
18.br
19
20.br
21.TP
22\fBfirejail \-\-profile=profile_name
23.br
24
25.br
26Example:
27.br
28$ firejail --profile=kdenlive --appimage kdenlive.appimage
29.br
30
31.br
32.RE
33.PP
34
35
36
37Building a profile manually:
38.PP
39.RS
40Start with the template in /usr/share/doc/firejail/profile.template and modify it in a text editor.
41To integrate the program in your desktop environment copy the profile file in ~/.config/firejail
42directory and run "sudo firecfg".
43.RE
44.PP
45
46Aliases and redirections:
47.PP
48.RS
49In some cases the same profile can be used for several applications.
50One such example is LibreOffice.
51Build a regular profile for the main application, and for the rest use
52/usr/share/doc/firejail/redirect_alias-profile.template.
53.RE
54.PP
55
56Running the profile builder:
57.PP
58.RS
6.TP 59.TP
7firejail \-\-profile=filename.profile 60\fBfirejail \-\-build=appname.profile appname
61.br
62
63.br
64Example:
65.br
66$ firejail --build=blobby.profile blobby
67.br
68
69.br
70Run the program in "firejail \-\-build" and try to exercise as many program features as possible.
71The profile is extracted and saved in the current directory. Open it in a text editor and add or remove
72sandboxing options as necessary. Test again after modifying the profile. To integrate the program
73in your desktop environment copy the profile file in ~/.config/firejail directory and run "sudo firecfg".
8.RE 74.RE
9firejail \-\-profile=profile_name 75.PP
10 76
11.SH DESCRIPTION 77.SH DESCRIPTION
12Several command line options can be passed to the program using 78Several command line options can be passed to the program using
@@ -205,6 +271,10 @@ Mount-bind file1 on top of file2. This option is only available when running as
205\fBdisable-mnt 271\fBdisable-mnt
206Disable /mnt, /media, /run/mount and /run/media access. 272Disable /mnt, /media, /run/mount and /run/media access.
207.TP 273.TP
274\fBkeep-config-pulse
275Disable automatic ~/.config/pulse init, for complex setups such as remote
276pulse servers or non-standard socket paths.
277.TP
208\fBkeep-dev-shm 278\fBkeep-dev-shm
209/dev/shm directory is untouched (even with private-dev). 279/dev/shm directory is untouched (even with private-dev).
210.TP 280.TP
@@ -295,7 +365,9 @@ Use the options no3d, nodvd, nosound, notv, nou2f and novideo for additional res
295Build a new /etc in a temporary 365Build a new /etc in a temporary
296filesystem, and copy the files and directories in the list. 366filesystem, and copy the files and directories in the list.
297The files and directories in the list must be expressed as relative to 367The files and directories in the list must be expressed as relative to
298the /etc directory. 368the /etc directory, and must not contain the / character
369(e.g., /etc/foo must be expressed as foo, but /etc/foo/bar --
370expressed as foo/bar -- is disallowed).
299All modifications are discarded when the sandbox is closed. 371All modifications are discarded when the sandbox is closed.
300#ifdef HAVE_PRIVATE_HOME 372#ifdef HAVE_PRIVATE_HOME
301.TP 373.TP
@@ -319,14 +391,18 @@ This feature is still under development, see \fBman 1 firejail\fR for some examp
319Build a new /opt in a temporary 391Build a new /opt in a temporary
320filesystem, and copy the files and directories in the list. 392filesystem, and copy the files and directories in the list.
321The files and directories in the list must be expressed as relative to 393The files and directories in the list must be expressed as relative to
322the /opt directory. 394the /opt directory, and must not contain the / character
395(e.g., /opt/foo must be expressed as foo, but /opt/foo/bar --
396expressed as foo/bar -- is disallowed).
323All modifications are discarded when the sandbox is closed. 397All modifications are discarded when the sandbox is closed.
324.TP 398.TP
325\fBprivate-srv file,directory 399\fBprivate-srv file,directory
326Build a new /srv in a temporary 400Build a new /srv in a temporary
327filesystem, and copy the files and directories in the list. 401filesystem, and copy the files and directories in the list.
328The files and directories in the list must be expressed as relative to 402The files and directories in the list must be expressed as relative to
329the /srv directory. 403the /srv directory, and must not contain the / character
404(e.g., /srv/foo must be expressed as foo, but /srv/foo/bar --
405expressed as foo/bar -- is disallowed).
330All modifications are discarded when the sandbox is closed. 406All modifications are discarded when the sandbox is closed.
331.TP 407.TP
332\fBprivate-tmp 408\fBprivate-tmp
@@ -646,9 +722,8 @@ name browser
646\fBno3d 722\fBno3d
647Disable 3D hardware acceleration. 723Disable 3D hardware acceleration.
648.TP 724.TP
649\fBnoautopulse 725\fBnoautopulse \fR(deprecated)
650Disable automatic ~/.config/pulse init, for complex setups such as remote 726See keep-config-pulse.
651pulse servers or non-standard socket paths.
652.TP 727.TP
653\fBnodvd 728\fBnodvd
654Disable DVD and audio CD devices. 729Disable DVD and audio CD devices.
@@ -668,6 +743,9 @@ Disable U2F devices.
668\fBnovideo 743\fBnovideo
669Disable video capture devices. 744Disable video capture devices.
670.TP 745.TP
746\fBnoinput
747Disable input devices.
748.TP
671\fBshell none 749\fBshell none
672Run the program directly, without a shell. 750Run the program directly, without a shell.
673 751
@@ -882,7 +960,21 @@ Join the sandbox identified by name or start a new one.
882Same as "firejail --join=sandboxname" command if sandbox with specified name exists, otherwise same as "name sandboxname". 960Same as "firejail --join=sandboxname" command if sandbox with specified name exists, otherwise same as "name sandboxname".
883 961
884.SH FILES 962.SH FILES
885/etc/firejail/filename.profile, $HOME/.config/firejail/filename.profile 963.TP
964\fB/etc/firejail/appname.profile
965Global Firejail configuration consisting mainly of profiles for each application supported by default.
966
967.TP
968\fB$HOME/.config/firejail/appname.profile
969User application profiles, will take precedence over the global profiles.
970
971.TP
972\fB/usr/share/doc/firejail/profile.template
973Template for building new profiles.
974
975.TP
976\fB/usr/share/doc/firejail/redirect_alias-profile.template
977Template for aliasing/redirecting profiles.
886 978
887.SH LICENSE 979.SH LICENSE
888Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 980Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index f27379a2d..68aea5857 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -1052,6 +1052,17 @@ Same as "firejail --join=name" if sandbox with specified name exists, otherwise
1052Note that in contrary to other join options there is respective profile option. 1052Note that in contrary to other join options there is respective profile option.
1053 1053
1054.TP 1054.TP
1055\fB\-\-keep-config-pulse
1056Disable automatic ~/.config/pulse init, for complex setups such as remote
1057pulse servers or non-standard socket paths.
1058.br
1059
1060.br
1061Example:
1062.br
1063$ firejail \-\-keep-config-pulse firefox
1064
1065.TP
1055\fB\-\-keep-dev-shm 1066\fB\-\-keep-dev-shm
1056/dev/shm directory is untouched (even with --private-dev) 1067/dev/shm directory is untouched (even with --private-dev)
1057.br 1068.br
@@ -1460,15 +1471,8 @@ Example:
1460$ firejail --no3d firefox 1471$ firejail --no3d firefox
1461 1472
1462.TP 1473.TP
1463\fB\-\-noautopulse 1474\fB\-\-noautopulse \fR(deprecated)
1464Disable automatic ~/.config/pulse init, for complex setups such as remote 1475See --keep-config-pulse.
1465pulse servers or non-standard socket paths.
1466.br
1467
1468.br
1469Example:
1470.br
1471$ firejail \-\-noautopulse firefox
1472 1476
1473.TP 1477.TP
1474\fB\-\-noblacklist=dirname_or_filename 1478\fB\-\-noblacklist=dirname_or_filename
@@ -1515,6 +1519,15 @@ Example:
1515.br 1519.br
1516$ firejail \-\-nodvd 1520$ firejail \-\-nodvd
1517.TP 1521.TP
1522\fB\-\-noinput
1523Disable input devices.
1524.br
1525
1526.br
1527Example:
1528.br
1529$ firejail \-\-noinput
1530.TP
1518\fB\-\-noexec=dirname_or_filename 1531\fB\-\-noexec=dirname_or_filename
1519Remount directory or file noexec, nodev and nosuid. File globbing is supported, see \fBFILE GLOBBING\fR section for more details. 1532Remount directory or file noexec, nodev and nosuid. File globbing is supported, see \fBFILE GLOBBING\fR section for more details.
1520.br 1533.br
@@ -1883,7 +1896,7 @@ $
1883Build a new /etc in a temporary 1896Build a new /etc in a temporary
1884filesystem, and copy the files and directories in the list. 1897filesystem, and copy the files and directories in the list.
1885The files and directories in the list must be expressed as relative to 1898The files and directories in the list must be expressed as relative to
1886the /etc directory. 1899the /etc directory (e.g., /etc/foo must be expressed as foo).
1887If no listed file is found, /etc directory will be empty. 1900If no listed file is found, /etc directory will be empty.
1888All modifications are discarded when the sandbox is closed. 1901All modifications are discarded when the sandbox is closed.
1889.br 1902.br
@@ -1893,7 +1906,7 @@ Example:
1893.br 1906.br
1894$ firejail --private-etc=group,hostname,localtime, \\ 1907$ firejail --private-etc=group,hostname,localtime, \\
1895.br 1908.br
1896nsswitch.conf,passwd,resolv.conf,default/motd-news 1909nsswitch.conf,passwd,resolv.conf
1897#ifdef HAVE_PRIVATE_HOME 1910#ifdef HAVE_PRIVATE_HOME
1898.TP 1911.TP
1899\fB\-\-private-home=file,directory 1912\fB\-\-private-home=file,directory
@@ -1968,7 +1981,9 @@ $
1968Build a new /opt in a temporary 1981Build a new /opt in a temporary
1969filesystem, and copy the files and directories in the list. 1982filesystem, and copy the files and directories in the list.
1970The files and directories in the list must be expressed as relative to 1983The files and directories in the list must be expressed as relative to
1971the /opt directory. 1984the /opt directory, and must not contain the / character
1985(e.g., /opt/foo must be expressed as foo, but /opt/foo/bar --
1986expressed as foo/bar -- is disallowed).
1972If no listed file is found, /opt directory will be empty. 1987If no listed file is found, /opt directory will be empty.
1973All modifications are discarded when the sandbox is closed. 1988All modifications are discarded when the sandbox is closed.
1974.br 1989.br
@@ -1983,7 +1998,9 @@ $ firejail --private-opt=firefox /opt/firefox/firefox
1983Build a new /srv in a temporary 1998Build a new /srv in a temporary
1984filesystem, and copy the files and directories in the list. 1999filesystem, and copy the files and directories in the list.
1985The files and directories in the list must be expressed as relative to 2000The files and directories in the list must be expressed as relative to
1986the /srv directory. 2001the /srv directory, and must not contain the / character
2002(e.g., /srv/foo must be expressed as foo, but /srv/foo/bar --
2003expressed as srv/bar -- is disallowed).
1987If no listed file is found, /srv directory will be empty. 2004If no listed file is found, /srv directory will be empty.
1988All modifications are discarded when the sandbox is closed. 2005All modifications are discarded when the sandbox is closed.
1989.br 2006.br
diff --git a/src/profstats/main.c b/src/profstats/main.c
index 5035280b1..10e44bd65 100644
--- a/src/profstats/main.c
+++ b/src/profstats/main.c
@@ -46,6 +46,7 @@ static int cnt_whitelistusrshare = 0; // include whitelist-usr-share-common.inc
46static int cnt_ssh = 0; 46static int cnt_ssh = 0;
47static int cnt_mdwx = 0; 47static int cnt_mdwx = 0;
48static int cnt_whitelisthome = 0; 48static int cnt_whitelisthome = 0;
49static int cnt_noroot = 0;
49 50
50static int level = 0; 51static int level = 0;
51static int arg_debug = 0; 52static int arg_debug = 0;
@@ -65,6 +66,7 @@ static int arg_mdwx = 0;
65static int arg_dbus_system_none = 0; 66static int arg_dbus_system_none = 0;
66static int arg_dbus_user_none = 0; 67static int arg_dbus_user_none = 0;
67static int arg_whitelisthome = 0; 68static int arg_whitelisthome = 0;
69static int arg_noroot = 0;
68 70
69 71
70static char *profile = NULL; 72static char *profile = NULL;
@@ -80,6 +82,7 @@ static void usage(void) {
80 printf(" --dbus-user-none - profiles without \"dbus-user none\"\n"); 82 printf(" --dbus-user-none - profiles without \"dbus-user none\"\n");
81 printf(" --ssh - print profiles without \"include disable-common.inc\"\n"); 83 printf(" --ssh - print profiles without \"include disable-common.inc\"\n");
82 printf(" --noexec - print profiles without \"include disable-exec.inc\"\n"); 84 printf(" --noexec - print profiles without \"include disable-exec.inc\"\n");
85 printf(" --noroot - print profiles without \"noroot\"\n");
83 printf(" --private-bin - print profiles without private-bin\n"); 86 printf(" --private-bin - print profiles without private-bin\n");
84 printf(" --private-dev - print profiles without private-dev\n"); 87 printf(" --private-dev - print profiles without private-dev\n");
85 printf(" --private-etc - print profiles without private-etc\n"); 88 printf(" --private-etc - print profiles without private-etc\n");
@@ -128,6 +131,8 @@ void process_file(const char *fname) {
128 cnt_caps++; 131 cnt_caps++;
129 else if (strncmp(ptr, "include disable-exec.inc", 24) == 0) 132 else if (strncmp(ptr, "include disable-exec.inc", 24) == 0)
130 cnt_noexec++; 133 cnt_noexec++;
134 else if (strncmp(ptr, "noroot", 6) == 0)
135 cnt_noroot++;
131 else if (strncmp(ptr, "include whitelist-var-common.inc", 32) == 0) 136 else if (strncmp(ptr, "include whitelist-var-common.inc", 32) == 0)
132 cnt_whitelistvar++; 137 cnt_whitelistvar++;
133 else if (strncmp(ptr, "include whitelist-runuser-common.inc", 36) == 0 || 138 else if (strncmp(ptr, "include whitelist-runuser-common.inc", 36) == 0 ||
@@ -212,6 +217,8 @@ int main(int argc, char **argv) {
212 arg_mdwx = 1; 217 arg_mdwx = 1;
213 else if (strcmp(argv[i], "--noexec") == 0) 218 else if (strcmp(argv[i], "--noexec") == 0)
214 arg_noexec = 1; 219 arg_noexec = 1;
220 else if (strcmp(argv[i], "--noroot") == 0)
221 arg_noroot = 1;
215 else if (strcmp(argv[i], "--private-bin") == 0) 222 else if (strcmp(argv[i], "--private-bin") == 0)
216 arg_privatebin = 1; 223 arg_privatebin = 1;
217 else if (strcmp(argv[i], "--private-dev") == 0) 224 else if (strcmp(argv[i], "--private-dev") == 0)
@@ -256,6 +263,7 @@ int main(int argc, char **argv) {
256 int caps = cnt_caps; 263 int caps = cnt_caps;
257 int apparmor = cnt_apparmor; 264 int apparmor = cnt_apparmor;
258 int noexec = cnt_noexec; 265 int noexec = cnt_noexec;
266 int noroot = cnt_noroot;
259 int privatebin = cnt_privatebin; 267 int privatebin = cnt_privatebin;
260 int privatetmp = cnt_privatetmp; 268 int privatetmp = cnt_privatetmp;
261 int privatedev = cnt_privatedev; 269 int privatedev = cnt_privatedev;
@@ -313,6 +321,8 @@ int main(int argc, char **argv) {
313 printf("No seccomp found in %s\n", argv[i]); 321 printf("No seccomp found in %s\n", argv[i]);
314 if (arg_noexec && noexec == cnt_noexec) 322 if (arg_noexec && noexec == cnt_noexec)
315 printf("No include disable-exec.inc found in %s\n", argv[i]); 323 printf("No include disable-exec.inc found in %s\n", argv[i]);
324 if (arg_noroot && noroot == cnt_noroot)
325 printf("No noroot found in %s\n", argv[i]);
316 if (arg_privatedev && privatedev == cnt_privatedev) 326 if (arg_privatedev && privatedev == cnt_privatedev)
317 printf("No private-dev found in %s\n", argv[i]); 327 printf("No private-dev found in %s\n", argv[i]);
318 if (arg_privatebin && privatebin == cnt_privatebin) 328 if (arg_privatebin && privatebin == cnt_privatebin)
@@ -346,6 +356,7 @@ int main(int argc, char **argv) {
346 printf(" seccomp\t\t\t%d\n", cnt_seccomp); 356 printf(" seccomp\t\t\t%d\n", cnt_seccomp);
347 printf(" capabilities\t\t%d\n", cnt_caps); 357 printf(" capabilities\t\t%d\n", cnt_caps);
348 printf(" noexec\t\t\t%d (include disable-exec.inc)\n", cnt_noexec); 358 printf(" noexec\t\t\t%d (include disable-exec.inc)\n", cnt_noexec);
359 printf(" noroot\t\t\t%d\n", cnt_noroot);
349 printf(" memory-deny-write-execute\t%d\n", cnt_mdwx); 360 printf(" memory-deny-write-execute\t%d\n", cnt_mdwx);
350 printf(" apparmor\t\t\t%d\n", cnt_apparmor); 361 printf(" apparmor\t\t\t%d\n", cnt_apparmor);
351 printf(" private-bin\t\t\t%d\n", cnt_privatebin); 362 printf(" private-bin\t\t\t%d\n", cnt_privatebin);
diff --git a/src/zsh_completion/_firejail.in b/src/zsh_completion/_firejail.in
index fd27bb35f..f1a19b86d 100644
--- a/src/zsh_completion/_firejail.in
+++ b/src/zsh_completion/_firejail.in
@@ -98,6 +98,7 @@ _firejail_args=(
98 '*--ignore=-[ignore command in profile files]: :' 98 '*--ignore=-[ignore command in profile files]: :'
99 '--ipc-namespace[enable a new IPC namespace]' 99 '--ipc-namespace[enable a new IPC namespace]'
100 '--join-or-start=-[join the sandbox or start a new one name|pid]: :_all_firejails' 100 '--join-or-start=-[join the sandbox or start a new one name|pid]: :_all_firejails'
101 '--keep-config-pulse[disable automatic ~/.config/pulse init]'
101 '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]' 102 '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]'
102 '--keep-var-tmp[/var/tmp directory is untouched]' 103 '--keep-var-tmp[/var/tmp directory is untouched]'
103 '--machine-id[preserve /etc/machine-id]' 104 '--machine-id[preserve /etc/machine-id]'
@@ -116,6 +117,7 @@ _firejail_args=(
116 '--nodvd[disable DVD and audio CD devices]' 117 '--nodvd[disable DVD and audio CD devices]'
117 '*--noexec=-[remount the file or directory noexec nosuid and nodev]: :_files' 118 '*--noexec=-[remount the file or directory noexec nosuid and nodev]: :_files'
118 '--nogroups[disable supplementary groups]' 119 '--nogroups[disable supplementary groups]'
120 '--noinput[disable input devices]'
119 '--nonewprivs[sets the NO_NEW_PRIVS prctl]' 121 '--nonewprivs[sets the NO_NEW_PRIVS prctl]'
120 '--nosound[disable sound system]' 122 '--nosound[disable sound system]'
121 '--nou2f[disable U2F devices]' 123 '--nou2f[disable U2F devices]'