aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-11-26 16:00:28 +0100
committerLibravatar smitsohu <smitsohu@gmail.com>2018-11-26 16:00:28 +0100
commit697f2965ed8cd44f7a24704ec309fbdda936a168 (patch)
tree8775433dd416d9e90a2b505f82e22d8e13f088e7
parentMerge pull request #2272 from veloute/firecfg (diff)
downloadfirejail-697f2965ed8cd44f7a24704ec309fbdda936a168.tar.gz
firejail-697f2965ed8cd44f7a24704ec309fbdda936a168.tar.zst
firejail-697f2965ed8cd44f7a24704ec309fbdda936a168.zip
refactor private-cache and tmpfs
has the immediate benefit that the result of combining --noexec and --tmpfs does not depend on the sequence of the options
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/fs.c108
-rw-r--r--src/man/firejail.txt2
3 files changed, 56 insertions, 56 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index c66904c1b..a4aa20667 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -439,6 +439,8 @@ void preproc_clean_run(void);
439// fs.c 439// fs.c
440// blacklist files or directories by mounting empty files on top of them 440// blacklist files or directories by mounting empty files on top of them
441void fs_blacklist(void); 441void fs_blacklist(void);
442// mount a writable tmpfs
443void fs_tmpfs(const char *dir, unsigned check_owner);
442// remount a directory read-only 444// remount a directory read-only
443void fs_rdonly(const char *dir); 445void fs_rdonly(const char *dir);
444void fs_rdonly_rec(const char *dir); 446void fs_rdonly_rec(const char *dir);
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index ff920b913..49074f525 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -162,18 +162,8 @@ static void disable_file(OPERATION op, const char *filename) {
162 } 162 }
163 else if (op == MOUNT_TMPFS) { 163 else if (op == MOUNT_TMPFS) {
164 if (S_ISDIR(s.st_mode)) { 164 if (S_ISDIR(s.st_mode)) {
165 if (arg_debug) 165 fs_tmpfs(fname, 0);
166 printf("Mounting tmpfs on %s\n", fname);
167 // preserve owner and mode for the directory
168 if (mount("tmpfs", fname, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, 0) < 0)
169 errExit("mounting tmpfs");
170 /* coverity[toctou] */
171 if (chown(fname, s.st_uid, s.st_gid) == -1)
172 errExit("mounting tmpfs chown");
173 if (chmod(fname, s.st_mode) == -1)
174 errExit("mounting tmpfs chmod");
175 last_disable = SUCCESSFUL; 166 last_disable = SUCCESSFUL;
176 fs_logger2("tmpfs", fname);
177 } 167 }
178 else 168 else
179 fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); 169 fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname);
@@ -456,6 +446,49 @@ static int get_mount_flags(const char *path, unsigned long *flags) {
456// - functions need fully resolved paths 446// - functions need fully resolved paths
457//*********************************************** 447//***********************************************
458 448
449// mount a writable tmpfs on directory
450void fs_tmpfs(const char *dir, unsigned check_owner) {
451 assert(dir);
452 // get a file descriptor for dir, fails if there is any symlink
453 int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
454 if (fd == -1)
455 errExit("safe_fd");
456 struct stat s;
457 if (fstat(fd, &s) == -1)
458 errExit("fstat");
459 if (check_owner && s.st_uid != getuid()) {
460 fwarning("no tmpfs mounted on %s: not owned by the current user\n", dir);
461 close(fd);
462 return;
463 }
464 if (arg_debug)
465 printf("Mounting tmpfs on %s\n", dir);
466 // preserve ownership, mode
467 char *options;
468 if (asprintf(&options, "mode=%o,uid=%u,gid=%u", s.st_mode & 07777, s.st_uid, s.st_gid) == -1)
469 errExit("asprintf");
470 // preserve some mount flags
471 struct statvfs buf;
472 if (fstatvfs(fd, &buf) == -1)
473 errExit("fstatvfs");
474 unsigned long flags = buf.f_flag & // remove read-only flag
475 (MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_MANDLOCK|MS_STRICTATIME|MS_NODIRATIME|MS_RELATIME|MS_NOATIME);
476 // mount via the symbolic link in /proc/self/fd
477 char *proc;
478 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
479 errExit("asprintf");
480 if (mount("tmpfs", proc, "tmpfs", flags|MS_NOSUID|MS_NODEV, options) < 0)
481 errExit("mounting tmpfs");
482 // check the last mount operation
483 MountData *mdata = get_last_mount();
484 if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, dir) != 0)
485 errLogExit("invalid tmpfs mount");
486 fs_logger2("tmpfs", dir);
487 free(options);
488 free(proc);
489 close(fd);
490}
491
459// remount directory read-only 492// remount directory read-only
460void fs_rdonly(const char *dir) { 493void fs_rdonly(const char *dir) {
461 assert(dir); 494 assert(dir);
@@ -1584,8 +1617,6 @@ void fs_private_tmp(void) {
1584 } 1617 }
1585 } 1618 }
1586 closedir(dir); 1619 closedir(dir);
1587
1588
1589} 1620}
1590 1621
1591// this function is called from sandbox.c before blacklist/whitelist functions 1622// this function is called from sandbox.c before blacklist/whitelist functions
@@ -1595,53 +1626,20 @@ void fs_private_cache(void) {
1595 errExit("asprintf"); 1626 errExit("asprintf");
1596 // check if ~/.cache is a valid destination 1627 // check if ~/.cache is a valid destination
1597 struct stat s; 1628 struct stat s;
1598 if (is_link(cache)) { 1629 if (lstat(cache, &s) == -1) {
1599 fwarning("user .cache is a symbolic link, tmpfs not mounted\n"); 1630 fwarning("cannot find %s, tmpfs not mounted\n", cache);
1600 free(cache);
1601 return;
1602 }
1603 if (stat(cache, &s) == -1 || !S_ISDIR(s.st_mode)) {
1604 fwarning("no user .cache directory found, tmpfs not mounted\n");
1605 free(cache); 1631 free(cache);
1606 return; 1632 return;
1607 } 1633 }
1608 if (s.st_uid != getuid()) { 1634 if (!S_ISDIR(s.st_mode)) {
1609 fwarning("user .cache is not owned by current user, tmpfs not mounted\n"); 1635 if (S_ISLNK(s.st_mode))
1636 fwarning("%s is a symbolic link, tmpfs not mounted\n", cache);
1637 else
1638 fwarning("%s is not a directory; cannot mount a tmpfs on top of it\n", cache);
1610 free(cache); 1639 free(cache);
1611 return; 1640 return;
1612 } 1641 }
1613 1642 // do the mount
1614 if (arg_debug) 1643 fs_tmpfs(cache, getuid()); // check ownership of ~/.cache
1615 printf("Mounting tmpfs on %s\n", cache);
1616 // get a file descriptor for ~/.cache, fails if there is any symlink
1617 int fd = safe_fd(cache, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1618 if (fd == -1)
1619 errExit("safe_fd");
1620 // confirm that actual mount destination is owned by the user
1621 if (fstat(fd, &s) == -1 || s.st_uid != getuid())
1622 errExit("fstat");
1623
1624 // mount a tmpfs on ~/.cache via the symbolic link in /proc/self/fd
1625 char *proc;
1626 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
1627 errExit("asprintf");
1628 if (mount("tmpfs", proc, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, 0) < 0)
1629 errExit("mounting tmpfs");
1630 fs_logger2("tmpfs", cache);
1631 free(proc);
1632 close(fd);
1633 // check the last mount operation
1634 MountData *mdata = get_last_mount();
1635 assert(mdata);
1636 if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, cache) != 0)
1637 errLogExit("invalid .cache mount");
1638
1639 // get a new file descriptor for ~/.cache, the old directory is masked by the tmpfs
1640 fd = safe_fd(cache, O_RDONLY|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1641 if (fd == -1)
1642 errExit("safe_fd");
1643 free(cache); 1644 free(cache);
1644 // restore permissions
1645 SET_PERMS_FD(fd, s.st_uid, s.st_gid, s.st_mode);
1646 close(fd);
1647} 1645}
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 8898c6791..edda34a1a 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -2058,7 +2058,7 @@ Kill the sandbox automatically after the time has elapsed. The time is specified
2058$ firejail \-\-timeout=01:30:00 firefox 2058$ firejail \-\-timeout=01:30:00 firefox
2059.TP 2059.TP
2060\fB\-\-tmpfs=dirname 2060\fB\-\-tmpfs=dirname
2061Mount a tmpfs filesystem on directory dirname. This option is available only when running the sandbox as root. 2061Mount a writable tmpfs filesystem on directory dirname. This option is available only when running the sandbox as root.
2062File globbing is supported, see \fBFILE GLOBBING\fR section for more details. 2062File globbing is supported, see \fBFILE GLOBBING\fR section for more details.
2063.br 2063.br
2064 2064