diff options
Diffstat (limited to 'src/firejail/fs_home.c')
-rw-r--r-- | src/firejail/fs_home.c | 63 |
1 files changed, 28 insertions, 35 deletions
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 4bcefa443..eab952eb8 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -42,15 +42,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
42 | // copy skel files | 42 | // copy skel files |
43 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) | 43 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) |
44 | errExit("asprintf"); | 44 | errExit("asprintf"); |
45 | struct stat s; | ||
46 | // don't copy it if we already have the file | 45 | // don't copy it if we already have the file |
47 | if (stat(fname, &s) == 0) | 46 | if (access(fname, F_OK) == 0) |
48 | return; | 47 | return; |
49 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 48 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
50 | fprintf(stderr, "Error: invalid %s file\n", fname); | 49 | fprintf(stderr, "Error: invalid %s file\n", fname); |
51 | exit(1); | 50 | exit(1); |
52 | } | 51 | } |
53 | if (stat("/etc/skel/.zshrc", &s) == 0) { | 52 | if (access("/etc/skel/.zshrc", R_OK) == 0) { |
54 | copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user | 53 | copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user |
55 | fs_logger("clone /etc/skel/.zshrc"); | 54 | fs_logger("clone /etc/skel/.zshrc"); |
56 | fs_logger2("clone", fname); | 55 | fs_logger2("clone", fname); |
@@ -67,16 +66,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
67 | // copy skel files | 66 | // copy skel files |
68 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) | 67 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) |
69 | errExit("asprintf"); | 68 | errExit("asprintf"); |
70 | struct stat s; | ||
71 | |||
72 | // don't copy it if we already have the file | 69 | // don't copy it if we already have the file |
73 | if (stat(fname, &s) == 0) | 70 | if (access(fname, F_OK) == 0) |
74 | return; | 71 | return; |
75 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 72 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
76 | fprintf(stderr, "Error: invalid %s file\n", fname); | 73 | fprintf(stderr, "Error: invalid %s file\n", fname); |
77 | exit(1); | 74 | exit(1); |
78 | } | 75 | } |
79 | if (stat("/etc/skel/.cshrc", &s) == 0) { | 76 | if (access("/etc/skel/.cshrc", R_OK) == 0) { |
80 | copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user | 77 | copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user |
81 | fs_logger("clone /etc/skel/.cshrc"); | 78 | fs_logger("clone /etc/skel/.cshrc"); |
82 | fs_logger2("clone", fname); | 79 | fs_logger2("clone", fname); |
@@ -93,15 +90,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
93 | // copy skel files | 90 | // copy skel files |
94 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) | 91 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) |
95 | errExit("asprintf"); | 92 | errExit("asprintf"); |
96 | struct stat s; | ||
97 | // don't copy it if we already have the file | 93 | // don't copy it if we already have the file |
98 | if (stat(fname, &s) == 0) | 94 | if (access(fname, F_OK) == 0) |
99 | return; | 95 | return; |
100 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 96 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
101 | fprintf(stderr, "Error: invalid %s file\n", fname); | 97 | fprintf(stderr, "Error: invalid %s file\n", fname); |
102 | exit(1); | 98 | exit(1); |
103 | } | 99 | } |
104 | if (stat("/etc/skel/.bashrc", &s) == 0) { | 100 | if (access("/etc/skel/.bashrc", R_OK) == 0) { |
105 | copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user | 101 | copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user |
106 | fs_logger("clone /etc/skel/.bashrc"); | 102 | fs_logger("clone /etc/skel/.bashrc"); |
107 | fs_logger2("clone", fname); | 103 | fs_logger2("clone", fname); |
@@ -122,8 +118,8 @@ static int store_xauthority(void) { | |||
122 | errExit("asprintf"); | 118 | errExit("asprintf"); |
123 | 119 | ||
124 | struct stat s; | 120 | struct stat s; |
125 | if (stat(src, &s) == 0) { | 121 | if (lstat_as_user(src, &s) == 0) { |
126 | if (is_link(src)) { | 122 | if (S_ISLNK(s.st_mode)) { |
127 | fwarning("invalid .Xauthority file\n"); | 123 | fwarning("invalid .Xauthority file\n"); |
128 | free(src); | 124 | free(src); |
129 | return 0; | 125 | return 0; |
@@ -161,11 +157,11 @@ static int store_asoundrc(void) { | |||
161 | errExit("asprintf"); | 157 | errExit("asprintf"); |
162 | 158 | ||
163 | struct stat s; | 159 | struct stat s; |
164 | if (stat(src, &s) == 0) { | 160 | if (lstat_as_user(src, &s) == 0) { |
165 | if (is_link(src)) { | 161 | if (S_ISLNK(s.st_mode)) { |
166 | // make sure the real path of the file is inside the home directory | 162 | // make sure the real path of the file is inside the home directory |
167 | /* coverity[toctou] */ | 163 | /* coverity[toctou] */ |
168 | char* rp = realpath(src, NULL); | 164 | char *rp = realpath_as_user(src); |
169 | if (!rp) { | 165 | if (!rp) { |
170 | fprintf(stderr, "Error: Cannot access %s\n", src); | 166 | fprintf(stderr, "Error: Cannot access %s\n", src); |
171 | exit(1); | 167 | exit(1); |
@@ -234,6 +230,7 @@ static void copy_asoundrc(void) { | |||
234 | } | 230 | } |
235 | 231 | ||
236 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user | 232 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user |
233 | selinux_relabel_path(dest, src); | ||
237 | fs_logger2("clone", dest); | 234 | fs_logger2("clone", dest); |
238 | free(dest); | 235 | free(dest); |
239 | 236 | ||
@@ -262,6 +259,7 @@ void fs_private_homedir(void) { | |||
262 | if (arg_debug) | 259 | if (arg_debug) |
263 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); | 260 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); |
264 | // get file descriptors for homedir and private_homedir, fails if there is any symlink | 261 | // get file descriptors for homedir and private_homedir, fails if there is any symlink |
262 | EUID_USER(); | ||
265 | int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 263 | int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
266 | if (src == -1) | 264 | if (src == -1) |
267 | errExit("opening private directory"); | 265 | errExit("opening private directory"); |
@@ -286,17 +284,10 @@ void fs_private_homedir(void) { | |||
286 | exit(1); | 284 | exit(1); |
287 | } | 285 | } |
288 | // mount via the links in /proc/self/fd | 286 | // mount via the links in /proc/self/fd |
289 | char *proc_src, *proc_dst; | 287 | EUID_ROOT(); |
290 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) | 288 | if (bind_mount_by_fd(src, dst)) |
291 | errExit("asprintf"); | ||
292 | if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1) | ||
293 | errExit("asprintf"); | ||
294 | if (mount(proc_src, proc_dst, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0) | ||
295 | errExit("mount bind"); | 289 | errExit("mount bind"); |
296 | free(proc_src); | 290 | |
297 | free(proc_dst); | ||
298 | close(src); | ||
299 | close(dst); | ||
300 | // check /proc/self/mountinfo to confirm the mount is ok | 291 | // check /proc/self/mountinfo to confirm the mount is ok |
301 | MountData *mptr = get_last_mount(); | 292 | MountData *mptr = get_last_mount(); |
302 | size_t len = strlen(homedir); | 293 | size_t len = strlen(homedir); |
@@ -304,6 +295,8 @@ void fs_private_homedir(void) { | |||
304 | (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) | 295 | (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) |
305 | errLogExit("invalid private mount"); | 296 | errLogExit("invalid private mount"); |
306 | 297 | ||
298 | close(src); | ||
299 | close(dst); | ||
307 | fs_logger3("mount-bind", private_homedir, homedir); | 300 | fs_logger3("mount-bind", private_homedir, homedir); |
308 | fs_logger2("whitelist", homedir); | 301 | fs_logger2("whitelist", homedir); |
309 | // preserve mode and ownership | 302 | // preserve mode and ownership |
@@ -438,6 +431,7 @@ void fs_check_private_cwd(const char *dir) { | |||
438 | // --private-home | 431 | // --private-home |
439 | //*********************************************************************************** | 432 | //*********************************************************************************** |
440 | static char *check_dir_or_file(const char *name) { | 433 | static char *check_dir_or_file(const char *name) { |
434 | EUID_ASSERT(); | ||
441 | assert(name); | 435 | assert(name); |
442 | 436 | ||
443 | // basic checks | 437 | // basic checks |
@@ -498,6 +492,7 @@ errexit: | |||
498 | } | 492 | } |
499 | 493 | ||
500 | static void duplicate(char *name) { | 494 | static void duplicate(char *name) { |
495 | EUID_ASSERT(); | ||
501 | char *fname = check_dir_or_file(name); | 496 | char *fname = check_dir_or_file(name); |
502 | 497 | ||
503 | if (arg_debug) | 498 | if (arg_debug) |
@@ -553,10 +548,10 @@ void fs_private_home_list(void) { | |||
553 | selinux_relabel_path(RUN_HOME_DIR, homedir); | 548 | selinux_relabel_path(RUN_HOME_DIR, homedir); |
554 | fs_logger_print(); // save the current log | 549 | fs_logger_print(); // save the current log |
555 | 550 | ||
551 | // copy the list of files in the new home directory | ||
552 | EUID_USER(); | ||
556 | if (arg_debug) | 553 | if (arg_debug) |
557 | printf("Copying files in the new home:\n"); | 554 | printf("Copying files in the new home:\n"); |
558 | |||
559 | // copy the list of files in the new home directory | ||
560 | char *dlist = strdup(cfg.home_private_keep); | 555 | char *dlist = strdup(cfg.home_private_keep); |
561 | if (!dlist) | 556 | if (!dlist) |
562 | errExit("strdup"); | 557 | errExit("strdup"); |
@@ -589,13 +584,11 @@ void fs_private_home_list(void) { | |||
589 | exit(1); | 584 | exit(1); |
590 | } | 585 | } |
591 | // mount using the file descriptor | 586 | // mount using the file descriptor |
592 | char *proc; | 587 | EUID_ROOT(); |
593 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 588 | if (bind_mount_path_to_fd(RUN_HOME_DIR, fd)) |
594 | errExit("asprintf"); | ||
595 | if (mount(RUN_HOME_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
596 | errExit("mount bind"); | 589 | errExit("mount bind"); |
597 | free(proc); | ||
598 | close(fd); | 590 | close(fd); |
591 | |||
599 | // check /proc/self/mountinfo to confirm the mount is ok | 592 | // check /proc/self/mountinfo to confirm the mount is ok |
600 | MountData *mptr = get_last_mount(); | 593 | MountData *mptr = get_last_mount(); |
601 | if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) | 594 | if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) |