diff options
Diffstat (limited to 'src')
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 | ||
151 | static 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 | ||
149 | static FileDB *var_out = NULL; | 163 | static FileDB *var_out = NULL; |
164 | static FileDB *var_skip = NULL; | ||
150 | static void var_callback(char *ptr) { | 165 | static 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 | ||
163 | void build_var(const char *fname, FILE *fp) { | 182 | void 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 | //******************************************* |
180 | static FileDB *share_out = NULL; | 198 | static FileDB *share_out = NULL; |
199 | static FileDB *share_skip = NULL; | ||
181 | static void share_callback(char *ptr) { | 200 | static 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 | ||
202 | void build_share(const char *fname, FILE *fp) { | 222 | void 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 | //******************************************* |
251 | static char *dev_skip[] = { | 273 | static 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 @@ | |||
23 | static FileDB *db_skip = NULL; | 23 | static FileDB *db_skip = NULL; |
24 | static FileDB *db_out = NULL; | 24 | static FileDB *db_out = NULL; |
25 | 25 | ||
26 | static 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 | |||
50 | void process_home(const char *fname, char *home, int home_len) { | 26 | void 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 { | |||
66 | FileDB *filedb_add(FileDB *head, const char *fname); | 66 | FileDB *filedb_add(FileDB *head, const char *fname); |
67 | FileDB *filedb_find(FileDB *head, const char *fname); | 67 | FileDB *filedb_find(FileDB *head, const char *fname); |
68 | void filedb_print(FileDB *head, const char *prefix, FILE *fp); | 68 | void filedb_print(FileDB *head, const char *prefix, FILE *fp); |
69 | FileDB *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 | ||
23 | FileDB *filedb_find(FileDB *head, const char *fname) { | 24 | FileDB *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) { | |||
52 | FileDB *filedb_add(FileDB *head, const char *fname) { | 54 | FileDB *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 | ||
72 | void filedb_print(FileDB *head, const char *prefix, FILE *fp) { | 76 | void 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 | |||
90 | FileDB *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 | |||
74 | autokey-shell | 74 | autokey-shell |
75 | avidemux3_qt5 | 75 | avidemux3_qt5 |
76 | aweather | 76 | aweather |
77 | ballbuster | ||
77 | baloo_file | 78 | baloo_file |
78 | baloo_filemetadata_temp_extractor | 79 | baloo_filemetadata_temp_extractor |
79 | balsa | 80 | balsa |
@@ -147,6 +148,7 @@ cmus | |||
147 | code | 148 | code |
148 | code-oss | 149 | code-oss |
149 | cola | 150 | cola |
151 | colorful | ||
150 | com.github.bleakgrey.tootle | 152 | com.github.bleakgrey.tootle |
151 | com.github.dahenson.agenda | 153 | com.github.dahenson.agenda |
152 | com.github.johnfactotum.Foliate | 154 | com.github.johnfactotum.Foliate |
@@ -236,6 +238,7 @@ ffplay | |||
236 | ffprobe | 238 | ffprobe |
237 | file-roller | 239 | file-roller |
238 | filezilla | 240 | filezilla |
241 | firedragon | ||
239 | firefox | 242 | firefox |
240 | firefox-beta | 243 | firefox-beta |
241 | firefox-developer-edition | 244 | firefox-developer-edition |
@@ -293,6 +296,8 @@ git-cola | |||
293 | github-desktop | 296 | github-desktop |
294 | gitter | 297 | gitter |
295 | # gjs -- https://github.com/netblue30/firejail/issues/3333#issuecomment-612601102 | 298 | # gjs -- https://github.com/netblue30/firejail/issues/3333#issuecomment-612601102 |
299 | gl-117 | ||
300 | glaxium | ||
296 | globaltime | 301 | globaltime |
297 | gmpc | 302 | gmpc |
298 | gnome-2048 | 303 | gnome-2048 |
@@ -550,6 +555,7 @@ mypaint | |||
550 | mypaint-ora-thumbnailer | 555 | mypaint-ora-thumbnailer |
551 | natron | 556 | natron |
552 | ncdu | 557 | ncdu |
558 | neochat | ||
553 | neomutt | 559 | neomutt |
554 | netactview | 560 | netactview |
555 | nethack | 561 | nethack |
@@ -615,6 +621,7 @@ penguin-command | |||
615 | photoflare | 621 | photoflare |
616 | picard | 622 | picard |
617 | pidgin | 623 | pidgin |
624 | pinball | ||
618 | #ping - disabled until we fix #1912 | 625 | #ping - disabled until we fix #1912 |
619 | pingus | 626 | pingus |
620 | pinta | 627 | pinta |
@@ -673,7 +680,6 @@ runenpass.sh | |||
673 | sayonara | 680 | sayonara |
674 | scallion | 681 | scallion |
675 | scorched3d | 682 | scorched3d |
676 | scorched3d-wrapper | ||
677 | scorchwentbonkers | 683 | scorchwentbonkers |
678 | scribus | 684 | scribus |
679 | sdat2img | 685 | sdat2img |
@@ -867,7 +873,6 @@ xmr-stak | |||
867 | xonotic | 873 | xonotic |
868 | xonotic-glx | 874 | xonotic-glx |
869 | xonotic-sdl | 875 | xonotic-sdl |
870 | xonotic-sdl-wrapper | ||
871 | xournal | 876 | xournal |
872 | xournalpp | 877 | xournalpp |
873 | xpdf | 878 | xpdf |
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) { | |||
146 | void appimage_clear(void) { | 146 | void 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 | |||
310 | extern int arg_scan; // arp-scan all interfaces | 310 | extern int arg_scan; // arp-scan all interfaces |
311 | extern int arg_whitelist; // whitelist command | 311 | extern int arg_whitelist; // whitelist command |
312 | extern int arg_nosound; // disable sound | 312 | extern int arg_nosound; // disable sound |
313 | extern int arg_noautopulse; // disable automatic ~/.config/pulse init | ||
314 | extern int arg_novideo; //disable video devices in /dev | 313 | extern int arg_novideo; //disable video devices in /dev |
315 | extern int arg_no3d; // disable 3d hardware acceleration | 314 | extern int arg_no3d; // disable 3d hardware acceleration |
316 | extern int arg_quiet; // no output for scripting | 315 | extern int arg_quiet; // no output for scripting |
@@ -319,6 +318,7 @@ extern int arg_join_filesystem; // join only the mount namespace | |||
319 | extern int arg_nice; // nice value configured | 318 | extern int arg_nice; // nice value configured |
320 | extern int arg_ipc; // enable ipc namespace | 319 | extern int arg_ipc; // enable ipc namespace |
321 | extern int arg_writable_etc; // writable etc | 320 | extern int arg_writable_etc; // writable etc |
321 | extern int arg_keep_config_pulse; // disable automatic ~/.config/pulse init | ||
322 | extern int arg_writable_var; // writable var | 322 | extern int arg_writable_var; // writable var |
323 | extern int arg_keep_var_tmp; // don't overwrite /var/tmp | 323 | extern int arg_keep_var_tmp; // don't overwrite /var/tmp |
324 | extern int arg_writable_run_user; // writable /run/user | 324 | extern int arg_writable_run_user; // writable /run/user |
@@ -335,7 +335,8 @@ extern int arg_noprofile; // use default.profile if none other found/specified | |||
335 | extern int arg_memory_deny_write_execute; // block writable and executable memory | 335 | extern int arg_memory_deny_write_execute; // block writable and executable memory |
336 | extern int arg_notv; // --notv | 336 | extern int arg_notv; // --notv |
337 | extern int arg_nodvd; // --nodvd | 337 | extern int arg_nodvd; // --nodvd |
338 | extern int arg_nou2f; // --nou2f | 338 | extern int arg_nou2f; // --nou2f |
339 | extern int arg_noinput; // --noinput | ||
339 | extern int arg_deterministic_exit_code; // always exit with first child's exit status | 340 | extern int arg_deterministic_exit_code; // always exit with first child's exit status |
340 | 341 | ||
341 | typedef enum { | 342 | typedef enum { |
@@ -565,6 +566,7 @@ void fs_dev_disable_video(void); | |||
565 | void fs_dev_disable_tv(void); | 566 | void fs_dev_disable_tv(void); |
566 | void fs_dev_disable_dvd(void); | 567 | void fs_dev_disable_dvd(void); |
567 | void fs_dev_disable_u2f(void); | 568 | void fs_dev_disable_u2f(void); |
569 | void 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 | |||
393 | void 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. | ||
84 | static 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 |
80 | static int check_dir_or_file(const char *fname) { | 118 | static int check_dir_or_file(const char *fname) { |
81 | assert(fname); | 119 | assert(fname); |
@@ -103,7 +141,7 @@ errexit: | |||
103 | static void duplicate(const char *fname, const char *private_dir, const char *private_run_dir) { | 141 | static 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 | |||
116 | int arg_scan = 0; // arp-scan all interfaces | 116 | int arg_scan = 0; // arp-scan all interfaces |
117 | int arg_whitelist = 0; // whitelist command | 117 | int arg_whitelist = 0; // whitelist command |
118 | int arg_nosound = 0; // disable sound | 118 | int arg_nosound = 0; // disable sound |
119 | int arg_noautopulse = 0; // disable automatic ~/.config/pulse init | ||
120 | int arg_novideo = 0; //disable video devices in /dev | 119 | int arg_novideo = 0; //disable video devices in /dev |
121 | int arg_no3d; // disable 3d hardware acceleration | 120 | int arg_no3d; // disable 3d hardware acceleration |
122 | int arg_quiet = 0; // no output for scripting | 121 | int arg_quiet = 0; // no output for scripting |
@@ -125,6 +124,7 @@ int arg_join_filesystem = 0; // join only the mount namespace | |||
125 | int arg_nice = 0; // nice value configured | 124 | int arg_nice = 0; // nice value configured |
126 | int arg_ipc = 0; // enable ipc namespace | 125 | int arg_ipc = 0; // enable ipc namespace |
127 | int arg_writable_etc = 0; // writable etc | 126 | int arg_writable_etc = 0; // writable etc |
127 | int arg_keep_config_pulse = 0; // disable automatic ~/.config/pulse init | ||
128 | int arg_writable_var = 0; // writable var | 128 | int arg_writable_var = 0; // writable var |
129 | int arg_keep_var_tmp = 0; // don't overwrite /var/tmp | 129 | int arg_keep_var_tmp = 0; // don't overwrite /var/tmp |
130 | int arg_writable_run_user = 0; // writable /run/user | 130 | int arg_writable_run_user = 0; // writable /run/user |
@@ -143,6 +143,7 @@ int arg_memory_deny_write_execute = 0; // block writable and executable memory | |||
143 | int arg_notv = 0; // --notv | 143 | int arg_notv = 0; // --notv |
144 | int arg_nodvd = 0; // --nodvd | 144 | int arg_nodvd = 0; // --nodvd |
145 | int arg_nou2f = 0; // --nou2f | 145 | int arg_nou2f = 0; // --nou2f |
146 | int arg_noinput = 0; // --noinput | ||
146 | int arg_deterministic_exit_code = 0; // always exit with first child's exit status | 147 | int arg_deterministic_exit_code = 0; // always exit with first child's exit status |
147 | DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user | 148 | DbusPolicy arg_dbus_user = DBUS_POLICY_ALLOW; // --dbus-user |
148 | DbusPolicy arg_dbus_system = DBUS_POLICY_ALLOW; // --dbus-system | 149 | DbusPolicy 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 |
219 | uint32_t network_get_defaultgw(void) { | 219 | uint32_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 | ||
24 | void protocol_filter_save(void) { | 24 | void 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) { | |||
86 | static void seccomp_save_file_list(const char *fname) { | 86 | static 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 |
100 | static int load_file_list_flag = 0; | 100 | static int load_file_list_flag = 0; |
101 | void seccomp_load_file_list(void) { | 101 | void 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 | ||
349 | void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { | 349 | void 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 | ||
802 | void notify_other(int fd) { | 802 | void 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) { | |||
84 | static int x11_abstract_sockets_present(void) { | 84 | static 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 |
3 | profile \- Security profile file syntax for Firejail | 3 | profile \- Security profile file syntax, and information about building new application profiles. |
4 | 4 | ||
5 | .SH USAGE | 5 | .SH SYNOPSIS |
6 | |||
7 | Using a specific profile: | ||
8 | .PP | ||
9 | .RS | ||
10 | .TP | ||
11 | \fBfirejail \-\-profile=filename.profile | ||
12 | .br | ||
13 | |||
14 | .br | ||
15 | Example: | ||
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 | ||
26 | Example: | ||
27 | .br | ||
28 | $ firejail --profile=kdenlive --appimage kdenlive.appimage | ||
29 | .br | ||
30 | |||
31 | .br | ||
32 | .RE | ||
33 | .PP | ||
34 | |||
35 | |||
36 | |||
37 | Building a profile manually: | ||
38 | .PP | ||
39 | .RS | ||
40 | Start with the template in /usr/share/doc/firejail/profile.template and modify it in a text editor. | ||
41 | To integrate the program in your desktop environment copy the profile file in ~/.config/firejail | ||
42 | directory and run "sudo firecfg". | ||
43 | .RE | ||
44 | .PP | ||
45 | |||
46 | Aliases and redirections: | ||
47 | .PP | ||
48 | .RS | ||
49 | In some cases the same profile can be used for several applications. | ||
50 | One such example is LibreOffice. | ||
51 | Build 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 | |||
56 | Running the profile builder: | ||
57 | .PP | ||
58 | .RS | ||
6 | .TP | 59 | .TP |
7 | firejail \-\-profile=filename.profile | 60 | \fBfirejail \-\-build=appname.profile appname |
61 | .br | ||
62 | |||
63 | .br | ||
64 | Example: | ||
65 | .br | ||
66 | $ firejail --build=blobby.profile blobby | ||
67 | .br | ||
68 | |||
69 | .br | ||
70 | Run the program in "firejail \-\-build" and try to exercise as many program features as possible. | ||
71 | The profile is extracted and saved in the current directory. Open it in a text editor and add or remove | ||
72 | sandboxing options as necessary. Test again after modifying the profile. To integrate the program | ||
73 | in your desktop environment copy the profile file in ~/.config/firejail directory and run "sudo firecfg". | ||
8 | .RE | 74 | .RE |
9 | firejail \-\-profile=profile_name | 75 | .PP |
10 | 76 | ||
11 | .SH DESCRIPTION | 77 | .SH DESCRIPTION |
12 | Several command line options can be passed to the program using | 78 | Several 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 |
206 | Disable /mnt, /media, /run/mount and /run/media access. | 272 | Disable /mnt, /media, /run/mount and /run/media access. |
207 | .TP | 273 | .TP |
274 | \fBkeep-config-pulse | ||
275 | Disable automatic ~/.config/pulse init, for complex setups such as remote | ||
276 | pulse 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 | |||
295 | Build a new /etc in a temporary | 365 | Build a new /etc in a temporary |
296 | filesystem, and copy the files and directories in the list. | 366 | filesystem, and copy the files and directories in the list. |
297 | The files and directories in the list must be expressed as relative to | 367 | The files and directories in the list must be expressed as relative to |
298 | the /etc directory. | 368 | the /etc directory, and must not contain the / character |
369 | (e.g., /etc/foo must be expressed as foo, but /etc/foo/bar -- | ||
370 | expressed as foo/bar -- is disallowed). | ||
299 | All modifications are discarded when the sandbox is closed. | 371 | All 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 | |||
319 | Build a new /opt in a temporary | 391 | Build a new /opt in a temporary |
320 | filesystem, and copy the files and directories in the list. | 392 | filesystem, and copy the files and directories in the list. |
321 | The files and directories in the list must be expressed as relative to | 393 | The files and directories in the list must be expressed as relative to |
322 | the /opt directory. | 394 | the /opt directory, and must not contain the / character |
395 | (e.g., /opt/foo must be expressed as foo, but /opt/foo/bar -- | ||
396 | expressed as foo/bar -- is disallowed). | ||
323 | All modifications are discarded when the sandbox is closed. | 397 | All modifications are discarded when the sandbox is closed. |
324 | .TP | 398 | .TP |
325 | \fBprivate-srv file,directory | 399 | \fBprivate-srv file,directory |
326 | Build a new /srv in a temporary | 400 | Build a new /srv in a temporary |
327 | filesystem, and copy the files and directories in the list. | 401 | filesystem, and copy the files and directories in the list. |
328 | The files and directories in the list must be expressed as relative to | 402 | The files and directories in the list must be expressed as relative to |
329 | the /srv directory. | 403 | the /srv directory, and must not contain the / character |
404 | (e.g., /srv/foo must be expressed as foo, but /srv/foo/bar -- | ||
405 | expressed as foo/bar -- is disallowed). | ||
330 | All modifications are discarded when the sandbox is closed. | 406 | All 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 |
647 | Disable 3D hardware acceleration. | 723 | Disable 3D hardware acceleration. |
648 | .TP | 724 | .TP |
649 | \fBnoautopulse | 725 | \fBnoautopulse \fR(deprecated) |
650 | Disable automatic ~/.config/pulse init, for complex setups such as remote | 726 | See keep-config-pulse. |
651 | pulse servers or non-standard socket paths. | ||
652 | .TP | 727 | .TP |
653 | \fBnodvd | 728 | \fBnodvd |
654 | Disable DVD and audio CD devices. | 729 | Disable DVD and audio CD devices. |
@@ -668,6 +743,9 @@ Disable U2F devices. | |||
668 | \fBnovideo | 743 | \fBnovideo |
669 | Disable video capture devices. | 744 | Disable video capture devices. |
670 | .TP | 745 | .TP |
746 | \fBnoinput | ||
747 | Disable input devices. | ||
748 | .TP | ||
671 | \fBshell none | 749 | \fBshell none |
672 | Run the program directly, without a shell. | 750 | Run the program directly, without a shell. |
673 | 751 | ||
@@ -882,7 +960,21 @@ Join the sandbox identified by name or start a new one. | |||
882 | Same as "firejail --join=sandboxname" command if sandbox with specified name exists, otherwise same as "name sandboxname". | 960 | Same 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 | ||
965 | Global Firejail configuration consisting mainly of profiles for each application supported by default. | ||
966 | |||
967 | .TP | ||
968 | \fB$HOME/.config/firejail/appname.profile | ||
969 | User application profiles, will take precedence over the global profiles. | ||
970 | |||
971 | .TP | ||
972 | \fB/usr/share/doc/firejail/profile.template | ||
973 | Template for building new profiles. | ||
974 | |||
975 | .TP | ||
976 | \fB/usr/share/doc/firejail/redirect_alias-profile.template | ||
977 | Template for aliasing/redirecting profiles. | ||
886 | 978 | ||
887 | .SH LICENSE | 979 | .SH LICENSE |
888 | Firejail 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. | 980 | Firejail 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 | |||
1052 | Note that in contrary to other join options there is respective profile option. | 1052 | Note that in contrary to other join options there is respective profile option. |
1053 | 1053 | ||
1054 | .TP | 1054 | .TP |
1055 | \fB\-\-keep-config-pulse | ||
1056 | Disable automatic ~/.config/pulse init, for complex setups such as remote | ||
1057 | pulse servers or non-standard socket paths. | ||
1058 | .br | ||
1059 | |||
1060 | .br | ||
1061 | Example: | ||
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) |
1464 | Disable automatic ~/.config/pulse init, for complex setups such as remote | 1475 | See --keep-config-pulse. |
1465 | pulse servers or non-standard socket paths. | ||
1466 | .br | ||
1467 | |||
1468 | .br | ||
1469 | Example: | ||
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 | ||
1523 | Disable input devices. | ||
1524 | .br | ||
1525 | |||
1526 | .br | ||
1527 | Example: | ||
1528 | .br | ||
1529 | $ firejail \-\-noinput | ||
1530 | .TP | ||
1518 | \fB\-\-noexec=dirname_or_filename | 1531 | \fB\-\-noexec=dirname_or_filename |
1519 | Remount directory or file noexec, nodev and nosuid. File globbing is supported, see \fBFILE GLOBBING\fR section for more details. | 1532 | Remount 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 @@ $ | |||
1883 | Build a new /etc in a temporary | 1896 | Build a new /etc in a temporary |
1884 | filesystem, and copy the files and directories in the list. | 1897 | filesystem, and copy the files and directories in the list. |
1885 | The files and directories in the list must be expressed as relative to | 1898 | The files and directories in the list must be expressed as relative to |
1886 | the /etc directory. | 1899 | the /etc directory (e.g., /etc/foo must be expressed as foo). |
1887 | If no listed file is found, /etc directory will be empty. | 1900 | If no listed file is found, /etc directory will be empty. |
1888 | All modifications are discarded when the sandbox is closed. | 1901 | All 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 |
1896 | nsswitch.conf,passwd,resolv.conf,default/motd-news | 1909 | nsswitch.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 @@ $ | |||
1968 | Build a new /opt in a temporary | 1981 | Build a new /opt in a temporary |
1969 | filesystem, and copy the files and directories in the list. | 1982 | filesystem, and copy the files and directories in the list. |
1970 | The files and directories in the list must be expressed as relative to | 1983 | The files and directories in the list must be expressed as relative to |
1971 | the /opt directory. | 1984 | the /opt directory, and must not contain the / character |
1985 | (e.g., /opt/foo must be expressed as foo, but /opt/foo/bar -- | ||
1986 | expressed as foo/bar -- is disallowed). | ||
1972 | If no listed file is found, /opt directory will be empty. | 1987 | If no listed file is found, /opt directory will be empty. |
1973 | All modifications are discarded when the sandbox is closed. | 1988 | All modifications are discarded when the sandbox is closed. |
1974 | .br | 1989 | .br |
@@ -1983,7 +1998,9 @@ $ firejail --private-opt=firefox /opt/firefox/firefox | |||
1983 | Build a new /srv in a temporary | 1998 | Build a new /srv in a temporary |
1984 | filesystem, and copy the files and directories in the list. | 1999 | filesystem, and copy the files and directories in the list. |
1985 | The files and directories in the list must be expressed as relative to | 2000 | The files and directories in the list must be expressed as relative to |
1986 | the /srv directory. | 2001 | the /srv directory, and must not contain the / character |
2002 | (e.g., /srv/foo must be expressed as foo, but /srv/foo/bar -- | ||
2003 | expressed as srv/bar -- is disallowed). | ||
1987 | If no listed file is found, /srv directory will be empty. | 2004 | If no listed file is found, /srv directory will be empty. |
1988 | All modifications are discarded when the sandbox is closed. | 2005 | All 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 | |||
46 | static int cnt_ssh = 0; | 46 | static int cnt_ssh = 0; |
47 | static int cnt_mdwx = 0; | 47 | static int cnt_mdwx = 0; |
48 | static int cnt_whitelisthome = 0; | 48 | static int cnt_whitelisthome = 0; |
49 | static int cnt_noroot = 0; | ||
49 | 50 | ||
50 | static int level = 0; | 51 | static int level = 0; |
51 | static int arg_debug = 0; | 52 | static int arg_debug = 0; |
@@ -65,6 +66,7 @@ static int arg_mdwx = 0; | |||
65 | static int arg_dbus_system_none = 0; | 66 | static int arg_dbus_system_none = 0; |
66 | static int arg_dbus_user_none = 0; | 67 | static int arg_dbus_user_none = 0; |
67 | static int arg_whitelisthome = 0; | 68 | static int arg_whitelisthome = 0; |
69 | static int arg_noroot = 0; | ||
68 | 70 | ||
69 | 71 | ||
70 | static char *profile = NULL; | 72 | static 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]' |