diff options
author | smitsohu <smitsohu@gmail.com> | 2019-07-09 14:13:58 +0200 |
---|---|---|
committer | smitsohu <smitsohu@gmail.com> | 2019-07-09 14:13:58 +0200 |
commit | 74e5911806d6f456819c65db37b0e29bc1f402d7 (patch) | |
tree | 9641cdbd1900edcf5b8947f181331aac7df421e0 /src/firejail/fs_home.c | |
parent | add symlink resolution for home directories (diff) | |
download | firejail-74e5911806d6f456819c65db37b0e29bc1f402d7.tar.gz firejail-74e5911806d6f456819c65db37b0e29bc1f402d7.tar.zst firejail-74e5911806d6f456819c65db37b0e29bc1f402d7.zip |
move to fd based homedir mounts
Diffstat (limited to 'src/firejail/fs_home.c')
-rw-r--r-- | src/firejail/fs_home.c | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 3f6d78db4..69ad5e2c8 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -239,13 +239,16 @@ void fs_private_homedir(void) { | |||
239 | // mount bind private_homedir on top of homedir | 239 | // mount bind private_homedir on top of homedir |
240 | if (arg_debug) | 240 | if (arg_debug) |
241 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); | 241 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); |
242 | // get a file descriptor for private_homedir, fails if there is any symlink | 242 | // get file descriptors for homedir and private_homedir, fails if there is any symlink |
243 | int fd = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 243 | int src = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
244 | if (fd == -1) | 244 | if (src == -1) |
245 | errExit("safe_fd"); | ||
246 | int dst = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
247 | if (dst == -1) | ||
245 | errExit("safe_fd"); | 248 | errExit("safe_fd"); |
246 | // check if new home directory is owned by the user | 249 | // check if new home directory is owned by the user |
247 | struct stat s; | 250 | struct stat s; |
248 | if (fstat(fd, &s) == -1) | 251 | if (fstat(src, &s) == -1) |
249 | errExit("fstat"); | 252 | errExit("fstat"); |
250 | if (s.st_uid != getuid()) { | 253 | if (s.st_uid != getuid()) { |
251 | fprintf(stderr, "Error: private directory is not owned by the current user\n"); | 254 | fprintf(stderr, "Error: private directory is not owned by the current user\n"); |
@@ -253,17 +256,27 @@ void fs_private_homedir(void) { | |||
253 | } | 256 | } |
254 | if ((S_IRWXU & s.st_mode) != S_IRWXU) | 257 | if ((S_IRWXU & s.st_mode) != S_IRWXU) |
255 | fwarning("no full permissions on private directory\n"); | 258 | fwarning("no full permissions on private directory\n"); |
256 | // mount via the link in /proc/self/fd | 259 | // mount via the links in /proc/self/fd |
257 | char *proc; | 260 | char *proc_src, *proc_dst; |
258 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 261 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) |
262 | errExit("asprintf"); | ||
263 | if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1) | ||
259 | errExit("asprintf"); | 264 | errExit("asprintf"); |
260 | if (mount(proc, homedir, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0) | 265 | if (mount(proc_src, proc_dst, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0) |
261 | errExit("mount bind"); | 266 | errExit("mount bind"); |
262 | free(proc); | 267 | free(proc_src); |
263 | close(fd); | 268 | free(proc_dst); |
264 | 269 | close(src); | |
265 | fs_logger3("mount-bind", private_homedir, cfg.homedir); | 270 | close(dst); |
266 | fs_logger2("whitelist", cfg.homedir); | 271 | // check /proc/self/mountinfo to confirm the mount is ok |
272 | MountData *mptr = get_last_mount(); | ||
273 | size_t len = strlen(homedir); | ||
274 | if (strncmp(mptr->dir, homedir, len) != 0 || | ||
275 | (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) | ||
276 | errLogExit("invalid private mount"); | ||
277 | |||
278 | fs_logger3("mount-bind", private_homedir, homedir); | ||
279 | fs_logger2("whitelist", homedir); | ||
267 | // preserve mode and ownership | 280 | // preserve mode and ownership |
268 | // if (chown(homedir, s.st_uid, s.st_gid) == -1) | 281 | // if (chown(homedir, s.st_uid, s.st_gid) == -1) |
269 | // errExit("mount-bind chown"); | 282 | // errExit("mount-bind chown"); |
@@ -310,13 +323,13 @@ void fs_private(void) { | |||
310 | int aflag = store_asoundrc(); | 323 | int aflag = store_asoundrc(); |
311 | 324 | ||
312 | // mask /home | 325 | // mask /home |
313 | if (arg_debug) | ||
314 | printf("Mounting a new /home directory\n"); | ||
315 | if (u == 0 && arg_allusers) // allow --allusers when starting the sandbox as root | 326 | if (u == 0 && arg_allusers) // allow --allusers when starting the sandbox as root |
316 | ; | 327 | ; |
317 | else { | 328 | else { |
329 | if (arg_debug) | ||
330 | printf("Mounting a new /home directory\n"); | ||
318 | if (arg_allusers) | 331 | if (arg_allusers) |
319 | fwarning("--allusers disabled by --private or --whitelist\n"); | 332 | fwarning("allusers option disabled by private or whitelist option\n"); |
320 | if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME, "mode=755,gid=0") < 0) | 333 | if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME, "mode=755,gid=0") < 0) |
321 | errExit("mounting home directory"); | 334 | errExit("mounting home directory"); |
322 | fs_logger("tmpfs /home"); | 335 | fs_logger("tmpfs /home"); |
@@ -330,19 +343,24 @@ void fs_private(void) { | |||
330 | fs_logger("tmpfs /root"); | 343 | fs_logger("tmpfs /root"); |
331 | 344 | ||
332 | if (u != 0) { | 345 | if (u != 0) { |
333 | // create /home/user | 346 | if (strncmp(homedir, "/home/", 6) == 0) { |
334 | if (arg_debug) | 347 | // create /home/user |
335 | printf("Create a new user directory\n"); | 348 | if (arg_debug) |
336 | if (mkdir(homedir, S_IRWXU) == -1) { | 349 | printf("Create a new user directory\n"); |
337 | if (mkpath_as_root(homedir) == -1) | 350 | if (mkdir(homedir, S_IRWXU) == -1) { |
338 | errExit("mkpath"); | 351 | if (mkpath_as_root(homedir) == -1) |
339 | if (mkdir(homedir, S_IRWXU) == -1 && errno != EEXIST) | 352 | errExit("mkpath"); |
340 | errExit("mkdir"); | 353 | if (mkdir(homedir, S_IRWXU) == -1 && errno != EEXIST) |
354 | errExit("mkdir"); | ||
355 | } | ||
356 | if (chown(homedir, u, g) < 0) | ||
357 | errExit("chown"); | ||
358 | fs_logger2("mkdir", homedir); | ||
359 | fs_logger2("tmpfs", homedir); | ||
341 | } | 360 | } |
342 | if (chown(homedir, u, g) < 0) | 361 | else |
343 | errExit("chown"); | 362 | // user directory is outside /home, mask it as well |
344 | fs_logger2("mkdir", homedir); | 363 | fs_tmpfs(homedir, 1); |
345 | fs_logger2("tmpfs", homedir); | ||
346 | } | 364 | } |
347 | 365 | ||
348 | skel(homedir, u, g); | 366 | skel(homedir, u, g); |
@@ -528,8 +546,20 @@ void fs_private_home_list(void) { | |||
528 | if (arg_debug) | 546 | if (arg_debug) |
529 | printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); | 547 | printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); |
530 | 548 | ||
531 | if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) | 549 | int fd = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
550 | if (fd == -1) | ||
551 | errExit("safe_fd"); | ||
552 | char *proc; | ||
553 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
554 | errExit("asprintf"); | ||
555 | if (mount(RUN_HOME_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
532 | errExit("mount bind"); | 556 | errExit("mount bind"); |
557 | free(proc); | ||
558 | close(fd); | ||
559 | // check /proc/self/mountinfo to confirm the mount is ok | ||
560 | MountData *mptr = get_last_mount(); | ||
561 | if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) | ||
562 | errLogExit("invalid private-home mount"); | ||
533 | fs_logger2("tmpfs", homedir); | 563 | fs_logger2("tmpfs", homedir); |
534 | 564 | ||
535 | if (uid != 0) { | 565 | if (uid != 0) { |