diff options
Diffstat (limited to 'src/firejail/fs.c')
-rw-r--r-- | src/firejail/fs.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 0562c7424..8db45f967 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1340,3 +1340,56 @@ void fs_private_tmp(void) { | |||
1340 | 1340 | ||
1341 | 1341 | ||
1342 | } | 1342 | } |
1343 | |||
1344 | // this function is called from sandbox.c before blacklist/whitelist functions | ||
1345 | void fs_private_cache(void) { | ||
1346 | char *cache; | ||
1347 | if (asprintf(&cache, "%s/.cache", cfg.homedir) == -1) | ||
1348 | errExit("asprintf"); | ||
1349 | // check if ~/.cache is a valid destination | ||
1350 | struct stat s; | ||
1351 | if (is_link(cache)) { | ||
1352 | fwarning("~/.cache is a symbolic link, tmpfs not mounted\n"); | ||
1353 | return; | ||
1354 | } | ||
1355 | if (stat(cache, &s) == -1 || !S_ISDIR(s.st_mode)) { | ||
1356 | fwarning("no ~/.cache directory found, tmpfs not mounted\n"); | ||
1357 | return; | ||
1358 | } | ||
1359 | if (s.st_uid != getuid()) { | ||
1360 | fwarning("~/.cache is not owned by user, tmpfs not mounted\n"); | ||
1361 | return; | ||
1362 | } | ||
1363 | |||
1364 | // get a file descriptor for ~/.cache, fails if there is any symlink | ||
1365 | int fd = safe_fd(cache, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1366 | if (fd == -1) | ||
1367 | errExit("safe_fd"); | ||
1368 | // confirm that actual mount destination is owned by the user | ||
1369 | if (fstat(fd, &s) == -1 || s.st_uid != getuid()) | ||
1370 | errExit("fstat"); | ||
1371 | |||
1372 | // mount a tmpfs on ~/.cache via the symbolic link in /proc/self/fd | ||
1373 | char *proc; | ||
1374 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
1375 | errExit("asprintf"); | ||
1376 | if (mount("tmpfs", proc, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, 0) < 0) | ||
1377 | errExit("mounting tmpfs"); | ||
1378 | fs_logger2("tmpfs", cache); | ||
1379 | free(proc); | ||
1380 | close(fd); | ||
1381 | // check the last mount operation | ||
1382 | MountData *mdata = get_last_mount(); | ||
1383 | assert(mdata); | ||
1384 | if (strcmp(mdata->fstype, "tmpfs") != 0 || strcmp(mdata->dir, cache) != 0) | ||
1385 | errLogExit("invalid .cache mount"); | ||
1386 | |||
1387 | // get a new file descriptor for ~/.cache, the old directory is masked by the tmpfs | ||
1388 | fd = safe_fd(cache, O_RDONLY|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1389 | if (fd == -1) | ||
1390 | errExit("safe_fd"); | ||
1391 | free(cache); | ||
1392 | // restore permissions | ||
1393 | SET_PERMS_FD(fd, s.st_uid, s.st_gid, s.st_mode); | ||
1394 | close(fd); | ||
1395 | } | ||