From 8bff773d6a7bf70c97b3d5b751df9ec0dd6c8b5d Mon Sep 17 00:00:00 2001 From: smitsohu Date: Tue, 9 Jul 2019 11:59:57 +0200 Subject: add symlink resolution for home directories --- etc/firejail.config | 3 +++ src/firejail/checkcfg.c | 2 ++ src/firejail/firejail.h | 1 + src/firejail/main.c | 45 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/etc/firejail.config b/etc/firejail.config index 565796d5a..4c0cb2a41 100644 --- a/etc/firejail.config +++ b/etc/firejail.config @@ -2,6 +2,9 @@ # keyword-argument pairs, one per line. Most features are enabled by default. # Use 'yes' or 'no' as configuration values. +# Allow symbolic links in path of user home directories, default disabled. +# homedir-symlink no + # Enable AppArmor functionality, default enabled. # apparmor yes diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index f94b95d60..84054fe76 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c @@ -50,6 +50,7 @@ int checkcfg(int val) { cfg_val[CFG_DISABLE_MNT] = 0; cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; cfg_val[CFG_XPRA_ATTACH] = 0; + cfg_val[CFG_HOMEDIR_SYMLINK] = 0; // open configuration file const char *fname = SYSCONFDIR "/firejail.config"; @@ -85,6 +86,7 @@ int checkcfg(int val) { ptr = line_remove_spaces(buf); if (!ptr) continue; + PARSE_YESNO(CFG_HOMEDIR_SYMLINK, "homedir-symlink") PARSE_YESNO(CFG_FILE_TRANSFER, "file-transfer") PARSE_YESNO(CFG_DBUS, "dbus") PARSE_YESNO(CFG_JOIN, "join") diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 7664c8037..4bd70697e 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -720,6 +720,7 @@ enum { CFG_PRIVATE_CACHE, CFG_CGROUP, CFG_NAME_CHANGE, + CFG_HOMEDIR_SYMLINK, // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv CFG_MAX // this should always be the last entry }; diff --git a/src/firejail/main.c b/src/firejail/main.c index 1e2488062..03956ce4d 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -242,6 +242,41 @@ static pid_t require_pid(const char *name) { return pid; } +// return 1 if there is a link somewhere in path of directory +static int has_link(const char *dir) { + assert(dir); + int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); + if (fd == -1) { + if (errno == ENOTDIR && is_dir(dir)) + return 1; + } + else + close(fd); + return 0; +} + +static void build_cfg_homedir(const char *dir) { + EUID_ASSERT(); + assert(dir); + if (dir[0] != '/') { + fprintf(stderr, "Error: invalid user directory \"%s\"\n", dir); + exit(1); + } + // symlinks are rejected in many places, provide a solution for home directories + if (checkcfg(CFG_HOMEDIR_SYMLINK)) { + cfg.homedir = realpath(dir, NULL); + if (cfg.homedir) + return; + } + else if (has_link(dir)) { + fprintf(stderr, "Error: path of user directory contains a symbolic link. " + "Please provide resolved path in password database (/etc/passwd) " + "or enable symbolic link resolution in Firejail configuration file.\n"); + exit(1); + } + cfg.homedir = clean_pathname(dir); +} + // init configuration static void init_cfg(int argc, char **argv) { EUID_ASSERT(); @@ -265,15 +300,12 @@ static void init_cfg(int argc, char **argv) { errExit("strdup"); // build home directory name - cfg.homedir = NULL; - if (pw->pw_dir != NULL) { - cfg.homedir = clean_pathname(pw->pw_dir); - assert(cfg.homedir); - } - else { + if (pw->pw_dir == NULL) { fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); exit(1); } + build_cfg_homedir(pw->pw_dir); + assert(cfg.homedir); cfg.cwd = getcwd(NULL, 0); if (!cfg.cwd && errno != ENOENT) @@ -926,7 +958,6 @@ int main(int argc, char **argv) { // check if the user is allowed to use firejail init_cfg(argc, argv); - assert(cfg.homedir); // get starting timestamp, process --quiet start_timestamp = getticks(); -- cgit v1.2.3-70-g09d2