From b6e77213ebbb04e322ab860cd7a141e0d544cc7e Mon Sep 17 00:00:00 2001 From: smitsohu Date: Tue, 12 Nov 2019 15:11:17 +0100 Subject: private-options: add homedir ownership check --- src/firejail/fs_home.c | 63 ++++++++++++++++++++++++++++++++++++-------------- src/firejail/main.c | 2 +- 2 files changed, 47 insertions(+), 18 deletions(-) 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) { int xflag = store_xauthority(); int aflag = store_asoundrc(); + // home directory outside /home? + int oflag = (strncmp(homedir, "/home/", 6) != 0); + uid_t u = getuid(); gid_t g = getgid(); @@ -259,20 +262,33 @@ void fs_private_homedir(void) { // get file descriptors for homedir and private_homedir, fails if there is any symlink int src = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); if (src == -1) - errExit("safe_fd"); + errExit("opening private directory"); int dst = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); if (dst == -1) - errExit("safe_fd"); - // check if new home directory is owned by the user - struct stat s; - if (fstat(src, &s) == -1) - errExit("fstat"); - if (s.st_uid != getuid()) { - fprintf(stderr, "Error: private directory is not owned by the current user\n"); - exit(1); + errExit("opening home directory"); + if (u != 0) { + struct stat s; + // sometimes system users are assigned home directories like /, /proc, ... + // require that a home directory outside /home is owned by the user + if (oflag) { + if (fstat(dst, &s) == -1) + errExit("fstat"); + if (s.st_uid != u) { + fprintf(stderr, "Error: cannot mount private directory:\n" + "Home directory is not owned by the current user\n"); + exit(1); + } + } + // check if new home directory is owned by the user + if (fstat(src, &s) == -1) + errExit("fstat"); + if (s.st_uid != u) { + fprintf(stderr, "Error: private directory is not owned by the current user\n"); + exit(1); + } + if ((S_IRWXU & s.st_mode) != S_IRWXU) + fwarning("no full permissions on private directory\n"); } - if ((S_IRWXU & s.st_mode) != S_IRWXU) - fwarning("no full permissions on private directory\n"); // mount via the links in /proc/self/fd char *proc_src, *proc_dst; if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) @@ -308,7 +324,7 @@ void fs_private_homedir(void) { errExit("mounting home directory"); fs_logger("tmpfs /root"); } - if (u == 0 || strncmp(homedir, "/home/", 6) != 0) { + if (oflag) { // mask /home if (arg_debug) printf("Mounting a new /home directory\n"); @@ -317,7 +333,6 @@ void fs_private_homedir(void) { fs_logger("tmpfs /home"); } - skel(homedir, u, g); if (xflag) copy_xauthority(); @@ -377,6 +392,7 @@ void fs_private(void) { } else // user directory is outside /home, mask it as well + // check if directory is owned by the current user fs_tmpfs(homedir, 1); } @@ -385,7 +401,6 @@ void fs_private(void) { copy_xauthority(); if (aflag) copy_asoundrc(); - } // check new private home directory (--private= option) - exit if it fails @@ -531,6 +546,9 @@ void fs_private_home_list(void) { int xflag = store_xauthority(); int aflag = store_asoundrc(); + // home directory outside /home? + int oflag = (strncmp(homedir, "/home/", 6) != 0); + uid_t uid = getuid(); gid_t gid = getgid(); @@ -563,7 +581,19 @@ void fs_private_home_list(void) { int fd = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); if (fd == -1) - errExit("safe_fd"); + errExit("opening home directory"); + if (uid != 0 && oflag) { + // home directory outside /home should be owned by the user + struct stat s; + if (fstat(fd, &s) == -1) + errExit("fstat"); + if (s.st_uid != uid) { + fprintf(stderr, "Error: cannot mount private directory:\n" + "Home directory is not owned by the current user\n"); + exit(1); + } + } + // mount using the file descriptor char *proc; if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) errExit("asprintf"); @@ -584,7 +614,7 @@ void fs_private_home_list(void) { if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=700,gid=0") < 0) errExit("mounting home directory"); } - if (uid == 0 || strncmp(homedir, "/home/", 6) != 0) { + if (oflag) { // mask /home if (arg_debug) printf("Mounting a new /home directory\n"); @@ -600,5 +630,4 @@ void fs_private_home_list(void) { if (!arg_quiet) fprintf(stderr, "Home directory installed in %0.2f ms\n", timetrace_end()); - } 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) { static void check_homedir(void) { assert(cfg.homedir); - if (cfg.homedir[0] != '/' || cfg.homedir[1] == '\0') { // system users sometimes have root directory as home + if (cfg.homedir[0] != '/') { fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); exit(1); } -- cgit v1.2.3-70-g09d2