diff options
-rw-r--r-- | etc/disable-common.inc | 3 | ||||
-rw-r--r-- | etc/firejail-default | 3 | ||||
-rw-r--r-- | src/firejail/fs.c | 6 | ||||
-rw-r--r-- | src/firejail/fs_home.c | 63 | ||||
-rw-r--r-- | src/firejail/main.c | 2 |
5 files changed, 56 insertions, 21 deletions
diff --git a/etc/disable-common.inc b/etc/disable-common.inc index 96957eeaf..b2837b443 100644 --- a/etc/disable-common.inc +++ b/etc/disable-common.inc | |||
@@ -315,6 +315,7 @@ blacklist ${HOME}/.config/keybase | |||
315 | blacklist ${HOME}/.davfs2/secrets | 315 | blacklist ${HOME}/.davfs2/secrets |
316 | blacklist ${HOME}/.ecryptfs | 316 | blacklist ${HOME}/.ecryptfs |
317 | blacklist ${HOME}/.fetchmailrc | 317 | blacklist ${HOME}/.fetchmailrc |
318 | blacklist ${HOME}/.fscrypt | ||
318 | blacklist ${HOME}/.git-credential-cache | 319 | blacklist ${HOME}/.git-credential-cache |
319 | blacklist ${HOME}/.git-credentials | 320 | blacklist ${HOME}/.git-credentials |
320 | blacklist ${HOME}/.gnome2/keyrings | 321 | blacklist ${HOME}/.gnome2/keyrings |
@@ -335,6 +336,7 @@ blacklist ${HOME}/.local/share/pki | |||
335 | blacklist ${HOME}/.smbcredentials | 336 | blacklist ${HOME}/.smbcredentials |
336 | blacklist ${HOME}/.ssh | 337 | blacklist ${HOME}/.ssh |
337 | blacklist ${HOME}/.vaults | 338 | blacklist ${HOME}/.vaults |
339 | blacklist /.fscrypt | ||
338 | blacklist /etc/davfs2/secrets | 340 | blacklist /etc/davfs2/secrets |
339 | blacklist /etc/group+ | 341 | blacklist /etc/group+ |
340 | blacklist /etc/group- | 342 | blacklist /etc/group- |
@@ -348,6 +350,7 @@ blacklist /etc/shadow+ | |||
348 | blacklist /etc/shadow- | 350 | blacklist /etc/shadow- |
349 | blacklist /etc/ssh | 351 | blacklist /etc/ssh |
350 | blacklist /home/.ecryptfs | 352 | blacklist /home/.ecryptfs |
353 | blacklist /home/.fscrypt | ||
351 | blacklist /var/backup | 354 | blacklist /var/backup |
352 | 355 | ||
353 | # cloud provider configuration | 356 | # cloud provider configuration |
diff --git a/etc/firejail-default b/etc/firejail-default index e7831e145..56fce654c 100644 --- a/etc/firejail-default +++ b/etc/firejail-default | |||
@@ -97,6 +97,9 @@ deny /proc/@{PID}/oom_score_adj w, | |||
97 | # Common backup directory | 97 | # Common backup directory |
98 | deny /**/.snapshots/ rwx, | 98 | deny /**/.snapshots/ rwx, |
99 | 99 | ||
100 | # fscrypt | ||
101 | deny /**/.fscrypt/ rwx, | ||
102 | |||
100 | ########## | 103 | ########## |
101 | # Allow all networking functionality, and control it from Firejail. | 104 | # Allow all networking functionality, and control it from Firejail. |
102 | ########## | 105 | ########## |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 3df551d4c..3e802efb5 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1191,15 +1191,15 @@ void fs_private_cache(void) { | |||
1191 | // check if ~/.cache is a valid destination | 1191 | // check if ~/.cache is a valid destination |
1192 | struct stat s; | 1192 | struct stat s; |
1193 | if (lstat(cache, &s) == -1) { | 1193 | if (lstat(cache, &s) == -1) { |
1194 | fwarning("cannot find %s, tmpfs not mounted\n", cache); | 1194 | fwarning("skipping private-cache: cannot find %s\n", cache); |
1195 | free(cache); | 1195 | free(cache); |
1196 | return; | 1196 | return; |
1197 | } | 1197 | } |
1198 | if (!S_ISDIR(s.st_mode)) { | 1198 | if (!S_ISDIR(s.st_mode)) { |
1199 | if (S_ISLNK(s.st_mode)) | 1199 | if (S_ISLNK(s.st_mode)) |
1200 | fwarning("%s is a symbolic link, tmpfs not mounted\n", cache); | 1200 | fwarning("skipping private-cache: %s is a symbolic link\n", cache); |
1201 | else | 1201 | else |
1202 | fwarning("%s is not a directory; cannot mount a tmpfs on top of it\n", cache); | 1202 | fwarning("skipping private-cache: %s is not a directory\n", cache); |
1203 | free(cache); | 1203 | free(cache); |
1204 | return; | 1204 | return; |
1205 | } | 1205 | } |
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 25c167af1..2e8a8ad96 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -250,6 +250,9 @@ void fs_private_homedir(void) { | |||
250 | int xflag = store_xauthority(); | 250 | int xflag = store_xauthority(); |
251 | int aflag = store_asoundrc(); | 251 | int aflag = store_asoundrc(); |
252 | 252 | ||
253 | // home directory outside /home? | ||
254 | int oflag = (strncmp(homedir, "/home/", 6) != 0); | ||
255 | |||
253 | uid_t u = getuid(); | 256 | uid_t u = getuid(); |
254 | gid_t g = getgid(); | 257 | gid_t g = getgid(); |
255 | 258 | ||
@@ -259,20 +262,33 @@ void fs_private_homedir(void) { | |||
259 | // get file descriptors for homedir and private_homedir, fails if there is any symlink | 262 | // get file descriptors for homedir and private_homedir, fails if there is any symlink |
260 | int src = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 263 | int src = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
261 | if (src == -1) | 264 | if (src == -1) |
262 | errExit("safe_fd"); | 265 | errExit("opening private directory"); |
263 | int dst = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 266 | int dst = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
264 | if (dst == -1) | 267 | if (dst == -1) |
265 | errExit("safe_fd"); | 268 | errExit("opening home directory"); |
266 | // check if new home directory is owned by the user | 269 | if (u != 0) { |
267 | struct stat s; | 270 | struct stat s; |
268 | if (fstat(src, &s) == -1) | 271 | // sometimes system users are assigned home directories like /, /proc, ... |
269 | errExit("fstat"); | 272 | // require that a home directory outside /home is owned by the user |
270 | if (s.st_uid != getuid()) { | 273 | if (oflag) { |
271 | fprintf(stderr, "Error: private directory is not owned by the current user\n"); | 274 | if (fstat(dst, &s) == -1) |
272 | exit(1); | 275 | errExit("fstat"); |
276 | if (s.st_uid != u) { | ||
277 | fprintf(stderr, "Error: cannot mount private directory:\n" | ||
278 | "Home directory is not owned by the current user\n"); | ||
279 | exit(1); | ||
280 | } | ||
281 | } | ||
282 | // check if new home directory is owned by the user | ||
283 | if (fstat(src, &s) == -1) | ||
284 | errExit("fstat"); | ||
285 | if (s.st_uid != u) { | ||
286 | fprintf(stderr, "Error: private directory is not owned by the current user\n"); | ||
287 | exit(1); | ||
288 | } | ||
289 | if ((S_IRWXU & s.st_mode) != S_IRWXU) | ||
290 | fwarning("no full permissions on private directory\n"); | ||
273 | } | 291 | } |
274 | if ((S_IRWXU & s.st_mode) != S_IRWXU) | ||
275 | fwarning("no full permissions on private directory\n"); | ||
276 | // mount via the links in /proc/self/fd | 292 | // mount via the links in /proc/self/fd |
277 | char *proc_src, *proc_dst; | 293 | char *proc_src, *proc_dst; |
278 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) | 294 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) |
@@ -308,7 +324,7 @@ void fs_private_homedir(void) { | |||
308 | errExit("mounting home directory"); | 324 | errExit("mounting home directory"); |
309 | fs_logger("tmpfs /root"); | 325 | fs_logger("tmpfs /root"); |
310 | } | 326 | } |
311 | if (u == 0 || strncmp(homedir, "/home/", 6) != 0) { | 327 | if (oflag) { |
312 | // mask /home | 328 | // mask /home |
313 | if (arg_debug) | 329 | if (arg_debug) |
314 | printf("Mounting a new /home directory\n"); | 330 | printf("Mounting a new /home directory\n"); |
@@ -317,7 +333,6 @@ void fs_private_homedir(void) { | |||
317 | fs_logger("tmpfs /home"); | 333 | fs_logger("tmpfs /home"); |
318 | } | 334 | } |
319 | 335 | ||
320 | |||
321 | skel(homedir, u, g); | 336 | skel(homedir, u, g); |
322 | if (xflag) | 337 | if (xflag) |
323 | copy_xauthority(); | 338 | copy_xauthority(); |
@@ -377,6 +392,7 @@ void fs_private(void) { | |||
377 | } | 392 | } |
378 | else | 393 | else |
379 | // user directory is outside /home, mask it as well | 394 | // user directory is outside /home, mask it as well |
395 | // check if directory is owned by the current user | ||
380 | fs_tmpfs(homedir, 1); | 396 | fs_tmpfs(homedir, 1); |
381 | } | 397 | } |
382 | 398 | ||
@@ -385,7 +401,6 @@ void fs_private(void) { | |||
385 | copy_xauthority(); | 401 | copy_xauthority(); |
386 | if (aflag) | 402 | if (aflag) |
387 | copy_asoundrc(); | 403 | copy_asoundrc(); |
388 | |||
389 | } | 404 | } |
390 | 405 | ||
391 | // check new private home directory (--private= option) - exit if it fails | 406 | // check new private home directory (--private= option) - exit if it fails |
@@ -531,6 +546,9 @@ void fs_private_home_list(void) { | |||
531 | int xflag = store_xauthority(); | 546 | int xflag = store_xauthority(); |
532 | int aflag = store_asoundrc(); | 547 | int aflag = store_asoundrc(); |
533 | 548 | ||
549 | // home directory outside /home? | ||
550 | int oflag = (strncmp(homedir, "/home/", 6) != 0); | ||
551 | |||
534 | uid_t uid = getuid(); | 552 | uid_t uid = getuid(); |
535 | gid_t gid = getgid(); | 553 | gid_t gid = getgid(); |
536 | 554 | ||
@@ -563,7 +581,19 @@ void fs_private_home_list(void) { | |||
563 | 581 | ||
564 | int fd = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 582 | int fd = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
565 | if (fd == -1) | 583 | if (fd == -1) |
566 | errExit("safe_fd"); | 584 | errExit("opening home directory"); |
585 | if (uid != 0 && oflag) { | ||
586 | // home directory outside /home should be owned by the user | ||
587 | struct stat s; | ||
588 | if (fstat(fd, &s) == -1) | ||
589 | errExit("fstat"); | ||
590 | if (s.st_uid != uid) { | ||
591 | fprintf(stderr, "Error: cannot mount private directory:\n" | ||
592 | "Home directory is not owned by the current user\n"); | ||
593 | exit(1); | ||
594 | } | ||
595 | } | ||
596 | // mount using the file descriptor | ||
567 | char *proc; | 597 | char *proc; |
568 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 598 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) |
569 | errExit("asprintf"); | 599 | errExit("asprintf"); |
@@ -584,7 +614,7 @@ void fs_private_home_list(void) { | |||
584 | if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=700,gid=0") < 0) | 614 | if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=700,gid=0") < 0) |
585 | errExit("mounting home directory"); | 615 | errExit("mounting home directory"); |
586 | } | 616 | } |
587 | if (uid == 0 || strncmp(homedir, "/home/", 6) != 0) { | 617 | if (oflag) { |
588 | // mask /home | 618 | // mask /home |
589 | if (arg_debug) | 619 | if (arg_debug) |
590 | printf("Mounting a new /home directory\n"); | 620 | printf("Mounting a new /home directory\n"); |
@@ -600,5 +630,4 @@ void fs_private_home_list(void) { | |||
600 | 630 | ||
601 | if (!arg_quiet) | 631 | if (!arg_quiet) |
602 | fprintf(stderr, "Home directory installed in %0.2f ms\n", timetrace_end()); | 632 | fprintf(stderr, "Home directory installed in %0.2f ms\n", timetrace_end()); |
603 | |||
604 | } | 633 | } |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 5b39dd491..1786cfac2 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -262,7 +262,7 @@ static int has_link(const char *dir) { | |||
262 | 262 | ||
263 | static void check_homedir(void) { | 263 | static void check_homedir(void) { |
264 | assert(cfg.homedir); | 264 | assert(cfg.homedir); |
265 | if (cfg.homedir[0] != '/' || cfg.homedir[1] == '\0') { // system users sometimes have root directory as home | 265 | if (cfg.homedir[0] != '/') { |
266 | fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); | 266 | fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); |
267 | exit(1); | 267 | exit(1); |
268 | } | 268 | } |