aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/fs.c')
-rw-r--r--src/firejail/fs.c108
1 files changed, 53 insertions, 55 deletions
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}