aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/firejail/fs_whitelist.c47
1 files changed, 27 insertions, 20 deletions
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index 9bedcc708..531cc4e48 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -41,8 +41,10 @@ static int mkpath(const char* path, mode_t mode) {
41 mode |= 0111; 41 mode |= 0111;
42 42
43 // create directories with uid/gid as root or as current user if inside home directory 43 // create directories with uid/gid as root or as current user if inside home directory
44 int userhome = 0;
44 if (strncmp(path, cfg.homedir, strlen(cfg.homedir)) == 0) { 45 if (strncmp(path, cfg.homedir, strlen(cfg.homedir)) == 0) {
45 EUID_USER(); 46 EUID_USER();
47 userhome = 1;
46 } 48 }
47 49
48 // work on a copy of the path 50 // work on a copy of the path
@@ -77,7 +79,9 @@ static int mkpath(const char* path, mode_t mode) {
77 perror("mkdir"); 79 perror("mkdir");
78 close(parentfd); 80 close(parentfd);
79 free(dup); 81 free(dup);
80 EUID_ROOT(); 82 if (userhome) {
83 EUID_ROOT();
84 }
81 return -1; 85 return -1;
82 } 86 }
83 } 87 }
@@ -90,7 +94,9 @@ static int mkpath(const char* path, mode_t mode) {
90 perror("open"); 94 perror("open");
91 close(parentfd); 95 close(parentfd);
92 free(dup); 96 free(dup);
93 EUID_ROOT(); 97 if (userhome) {
98 EUID_ROOT();
99 }
94 return -1; 100 return -1;
95 } 101 }
96 // move on to next path segment 102 // move on to next path segment
@@ -103,7 +109,9 @@ static int mkpath(const char* path, mode_t mode) {
103 fs_logger2("mkpath", path); 109 fs_logger2("mkpath", path);
104 110
105 free(dup); 111 free(dup);
106 EUID_ROOT(); 112 if (userhome) {
113 EUID_ROOT();
114 }
107 return fd; 115 return fd;
108} 116}
109 117
@@ -115,11 +123,12 @@ static void whitelist_path(ProfileEntry *entry) {
115 char *wfile = NULL; 123 char *wfile = NULL;
116 124
117 if (entry->home_dir) { 125 if (entry->home_dir) {
118 if (strncmp(path, cfg.homedir, strlen(cfg.homedir)) != 0) 126 if (strncmp(path, cfg.homedir, strlen(cfg.homedir)) != 0 || path[strlen(cfg.homedir)] != '/')
119 // symlink pointing outside /home, skip the mount 127 // either symlink pointing outside home directory
128 // or entire home directory, skip the mount
120 return; 129 return;
121 130
122 fname = path + strlen(cfg.homedir); 131 fname = path + strlen(cfg.homedir) + 1; // strlen("/home/user/")
123 132
124 if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_HOME_USER_DIR, fname) == -1) 133 if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_HOME_USER_DIR, fname) == -1)
125 errExit("asprintf"); 134 errExit("asprintf");
@@ -291,13 +300,15 @@ static void whitelist_path(ProfileEntry *entry) {
291 // check the last mount operation 300 // check the last mount operation
292 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found 301 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found
293 302
303 // confirm the file was mounted on the right target
304 // strcmp does not work here, because mptr->dir can be a child mount
294 if (strncmp(mptr->dir, path, strlen(path)) != 0) 305 if (strncmp(mptr->dir, path, strlen(path)) != 0)
295 errLogExit("invalid whitelist mount"); 306 errLogExit("invalid whitelist mount");
296 // No mounts are allowed on top level directories. A destination such as "/etc" is very bad! 307 // No mounts are allowed on top level directories. A destination such as "/etc" is very bad!
297 // - there should be more than one '/' char in dest string 308 // - there should be more than one '/' char in dest string
298 if (mptr->dir == strrchr(mptr->dir, '/')) 309 if (mptr->dir == strrchr(mptr->dir, '/'))
299 errLogExit("invalid whitelist mount"); 310 errLogExit("invalid whitelist mount");
300 // confirm the correct file is mounted on path 311 // confirm the right file was mounted
301 int fd4 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); 312 int fd4 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
302 if (fd4 == -1) 313 if (fd4 == -1)
303 errExit("safe_fd"); 314 errExit("safe_fd");
@@ -374,7 +385,8 @@ void fs_whitelist(void) {
374 } 385 }
375 386
376 // remove trailing slashes and single dots 387 // remove trailing slashes and single dots
377 trim_trailing_slash_or_dot(new_name); 388 if (!nowhitelist_flag)
389 trim_trailing_slash_or_dot(new_name);
378 390
379 if (arg_debug || arg_debug_whitelists) 391 if (arg_debug || arg_debug_whitelists)
380 fprintf(stderr, "Debug %d: new_name #%s#, %s\n", __LINE__, new_name, (nowhitelist_flag)? "nowhitelist": "whitelist"); 392 fprintf(stderr, "Debug %d: new_name #%s#, %s\n", __LINE__, new_name, (nowhitelist_flag)? "nowhitelist": "whitelist");
@@ -387,7 +399,7 @@ void fs_whitelist(void) {
387 } 399 }
388 400
389 // extract the absolute path of the file 401 // extract the absolute path of the file
390 // realpath function will fail with ENOENT if the file is not found 402 // realpath function will fail with ENOENT if the file is not found or with EACCES if user has no permission
391 // special processing for /dev/fd, /dev/stdin, /dev/stdout and /dev/stderr 403 // special processing for /dev/fd, /dev/stdin, /dev/stdout and /dev/stderr
392 char *fname; 404 char *fname;
393 if (strcmp(new_name, "/dev/fd") == 0) 405 if (strcmp(new_name, "/dev/fd") == 0)
@@ -462,7 +474,7 @@ void fs_whitelist(void) {
462 } 474 }
463 475
464 // check for supported directories 476 // check for supported directories
465 if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) { 477 if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0 && new_name[strlen(cfg.homedir)] == '/') {
466 // whitelisting home directory is disabled if --private option is present 478 // whitelisting home directory is disabled if --private option is present
467 if (arg_private) { 479 if (arg_private) {
468 if (arg_debug || arg_debug_whitelists) 480 if (arg_debug || arg_debug_whitelists)
@@ -479,17 +491,10 @@ void fs_whitelist(void) {
479 fprintf(stderr, "Debug %d: fname #%s#, cfg.homedir #%s#\n", 491 fprintf(stderr, "Debug %d: fname #%s#, cfg.homedir #%s#\n",
480 __LINE__, fname, cfg.homedir); 492 __LINE__, fname, cfg.homedir);
481 493
482 // both path and absolute path are under /home 494 // both path and absolute path are in user home,
483 if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0) { 495 // if not check if the symlink destination is owned by the user
484 // entire home directory is not allowed 496 if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) != 0 || fname[strlen(cfg.homedir)] != '/') {
485 if (*(fname + strlen(cfg.homedir)) != '/') {
486 free(fname);
487 goto errexit;
488 }
489 }
490 else {
491 if (checkcfg(CFG_FOLLOW_SYMLINK_AS_USER)) { 497 if (checkcfg(CFG_FOLLOW_SYMLINK_AS_USER)) {
492 // check if the file is owned by the user
493 if (stat(fname, &s) == 0 && s.st_uid != getuid()) { 498 if (stat(fname, &s) == 0 && s.st_uid != getuid()) {
494 free(fname); 499 free(fname);
495 goto errexit; 500 goto errexit;
@@ -891,6 +896,7 @@ void fs_whitelist(void) {
891 if (arg_debug || arg_debug_whitelists) 896 if (arg_debug || arg_debug_whitelists)
892 printf("Debug %d: cannot create symbolic link %s\n", __LINE__, entry->link); 897 printf("Debug %d: cannot create symbolic link %s\n", __LINE__, entry->link);
893 free(entry->link); 898 free(entry->link);
899 entry->link = NULL;
894 entry = entry->next; 900 entry = entry->next;
895 continue; 901 continue;
896 } 902 }
@@ -909,6 +915,7 @@ void fs_whitelist(void) {
909 close(fd); 915 close(fd);
910 } 916 }
911 free(entry->link); 917 free(entry->link);
918 entry->link = NULL;
912 } 919 }
913 920
914 entry = entry->next; 921 entry = entry->next;