diff options
-rw-r--r-- | etc/firejail.config | 3 | ||||
-rw-r--r-- | src/firejail/checkcfg.c | 2 | ||||
-rw-r--r-- | src/firejail/firejail.h | 1 | ||||
-rw-r--r-- | 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 @@ | |||
2 | # keyword-argument pairs, one per line. Most features are enabled by default. | 2 | # keyword-argument pairs, one per line. Most features are enabled by default. |
3 | # Use 'yes' or 'no' as configuration values. | 3 | # Use 'yes' or 'no' as configuration values. |
4 | 4 | ||
5 | # Allow symbolic links in path of user home directories, default disabled. | ||
6 | # homedir-symlink no | ||
7 | |||
5 | # Enable AppArmor functionality, default enabled. | 8 | # Enable AppArmor functionality, default enabled. |
6 | # apparmor yes | 9 | # apparmor yes |
7 | 10 | ||
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) { | |||
50 | cfg_val[CFG_DISABLE_MNT] = 0; | 50 | cfg_val[CFG_DISABLE_MNT] = 0; |
51 | cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; | 51 | cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; |
52 | cfg_val[CFG_XPRA_ATTACH] = 0; | 52 | cfg_val[CFG_XPRA_ATTACH] = 0; |
53 | cfg_val[CFG_HOMEDIR_SYMLINK] = 0; | ||
53 | 54 | ||
54 | // open configuration file | 55 | // open configuration file |
55 | const char *fname = SYSCONFDIR "/firejail.config"; | 56 | const char *fname = SYSCONFDIR "/firejail.config"; |
@@ -85,6 +86,7 @@ int checkcfg(int val) { | |||
85 | ptr = line_remove_spaces(buf); | 86 | ptr = line_remove_spaces(buf); |
86 | if (!ptr) | 87 | if (!ptr) |
87 | continue; | 88 | continue; |
89 | PARSE_YESNO(CFG_HOMEDIR_SYMLINK, "homedir-symlink") | ||
88 | PARSE_YESNO(CFG_FILE_TRANSFER, "file-transfer") | 90 | PARSE_YESNO(CFG_FILE_TRANSFER, "file-transfer") |
89 | PARSE_YESNO(CFG_DBUS, "dbus") | 91 | PARSE_YESNO(CFG_DBUS, "dbus") |
90 | PARSE_YESNO(CFG_JOIN, "join") | 92 | 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 { | |||
720 | CFG_PRIVATE_CACHE, | 720 | CFG_PRIVATE_CACHE, |
721 | CFG_CGROUP, | 721 | CFG_CGROUP, |
722 | CFG_NAME_CHANGE, | 722 | CFG_NAME_CHANGE, |
723 | CFG_HOMEDIR_SYMLINK, | ||
723 | // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv | 724 | // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv |
724 | CFG_MAX // this should always be the last entry | 725 | CFG_MAX // this should always be the last entry |
725 | }; | 726 | }; |
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) { | |||
242 | return pid; | 242 | return pid; |
243 | } | 243 | } |
244 | 244 | ||
245 | // return 1 if there is a link somewhere in path of directory | ||
246 | static int has_link(const char *dir) { | ||
247 | assert(dir); | ||
248 | int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
249 | if (fd == -1) { | ||
250 | if (errno == ENOTDIR && is_dir(dir)) | ||
251 | return 1; | ||
252 | } | ||
253 | else | ||
254 | close(fd); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static void build_cfg_homedir(const char *dir) { | ||
259 | EUID_ASSERT(); | ||
260 | assert(dir); | ||
261 | if (dir[0] != '/') { | ||
262 | fprintf(stderr, "Error: invalid user directory \"%s\"\n", dir); | ||
263 | exit(1); | ||
264 | } | ||
265 | // symlinks are rejected in many places, provide a solution for home directories | ||
266 | if (checkcfg(CFG_HOMEDIR_SYMLINK)) { | ||
267 | cfg.homedir = realpath(dir, NULL); | ||
268 | if (cfg.homedir) | ||
269 | return; | ||
270 | } | ||
271 | else if (has_link(dir)) { | ||
272 | fprintf(stderr, "Error: path of user directory contains a symbolic link. " | ||
273 | "Please provide resolved path in password database (/etc/passwd) " | ||
274 | "or enable symbolic link resolution in Firejail configuration file.\n"); | ||
275 | exit(1); | ||
276 | } | ||
277 | cfg.homedir = clean_pathname(dir); | ||
278 | } | ||
279 | |||
245 | // init configuration | 280 | // init configuration |
246 | static void init_cfg(int argc, char **argv) { | 281 | static void init_cfg(int argc, char **argv) { |
247 | EUID_ASSERT(); | 282 | EUID_ASSERT(); |
@@ -265,15 +300,12 @@ static void init_cfg(int argc, char **argv) { | |||
265 | errExit("strdup"); | 300 | errExit("strdup"); |
266 | 301 | ||
267 | // build home directory name | 302 | // build home directory name |
268 | cfg.homedir = NULL; | 303 | if (pw->pw_dir == NULL) { |
269 | if (pw->pw_dir != NULL) { | ||
270 | cfg.homedir = clean_pathname(pw->pw_dir); | ||
271 | assert(cfg.homedir); | ||
272 | } | ||
273 | else { | ||
274 | fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); | 304 | fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); |
275 | exit(1); | 305 | exit(1); |
276 | } | 306 | } |
307 | build_cfg_homedir(pw->pw_dir); | ||
308 | assert(cfg.homedir); | ||
277 | 309 | ||
278 | cfg.cwd = getcwd(NULL, 0); | 310 | cfg.cwd = getcwd(NULL, 0); |
279 | if (!cfg.cwd && errno != ENOENT) | 311 | if (!cfg.cwd && errno != ENOENT) |
@@ -926,7 +958,6 @@ int main(int argc, char **argv) { | |||
926 | 958 | ||
927 | // check if the user is allowed to use firejail | 959 | // check if the user is allowed to use firejail |
928 | init_cfg(argc, argv); | 960 | init_cfg(argc, argv); |
929 | assert(cfg.homedir); | ||
930 | 961 | ||
931 | // get starting timestamp, process --quiet | 962 | // get starting timestamp, process --quiet |
932 | start_timestamp = getticks(); | 963 | start_timestamp = getticks(); |