aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2021-02-12 16:20:43 +0100
committerLibravatar smitsohu <smitsohu@gmail.com>2021-02-12 16:20:43 +0100
commit105946495fb744558a4830591b857cdb6fc0111d (patch)
tree9875700956b790c44ea61545045bd2143cf6a5ff /src
parentchroot hardening (diff)
downloadfirejail-105946495fb744558a4830591b857cdb6fc0111d.tar.gz
firejail-105946495fb744558a4830591b857cdb6fc0111d.tar.zst
firejail-105946495fb744558a4830591b857cdb6fc0111d.zip
remount hardening
Diffstat (limited to 'src')
-rw-r--r--src/firejail/fs.c48
1 files changed, 26 insertions, 22 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index b1c509b30..972ee8def 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -487,27 +487,26 @@ void fs_tmpfs(const char *dir, unsigned check_owner) {
487 close(fd); 487 close(fd);
488} 488}
489 489
490// remount path, but preserve existing mount flags; requires a resolved path 490// remount path, preserving other mount flags; requires a resolved path
491static void fs_remount_simple(const char *path, OPERATION op) { 491static void fs_remount_simple(const char *path, OPERATION op) {
492 struct stat s1, s2;
492 assert(path); 493 assert(path);
493 494
494 // open path without following symbolic links 495 // open path without following symbolic links
495 int fd = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); 496 int fd1 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
496 if (fd == -1) 497 if (fd1 == -1)
497 goto out; 498 goto out;
498 // identify file owner 499 if (fstat(fd1, &s1) == -1) {
499 struct stat s;
500 if (fstat(fd, &s) == -1) {
501 // fstat can fail with EACCES if path is a FUSE mount, 500 // fstat can fail with EACCES if path is a FUSE mount,
502 // mounted without 'allow_root' or 'allow_other' 501 // mounted without 'allow_root' or 'allow_other'
503 if (errno != EACCES) 502 if (errno != EACCES)
504 errExit("fstat"); 503 errExit("fstat");
505 close(fd); 504 close(fd1);
506 goto out; 505 goto out;
507 } 506 }
508 // get mount flags 507 // get mount flags
509 struct statvfs buf; 508 struct statvfs buf;
510 if (fstatvfs(fd, &buf) == -1) 509 if (fstatvfs(fd1, &buf) == -1)
511 errExit("fstatvfs"); 510 errExit("fstatvfs");
512 unsigned long flags = buf.f_flag; 511 unsigned long flags = buf.f_flag;
513 512
@@ -515,13 +514,13 @@ static void fs_remount_simple(const char *path, OPERATION op) {
515 if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) { 514 if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) {
516 // nothing to do if there is no read-only flag 515 // nothing to do if there is no read-only flag
517 if ((flags & MS_RDONLY) == 0) { 516 if ((flags & MS_RDONLY) == 0) {
518 close(fd); 517 close(fd1);
519 return; 518 return;
520 } 519 }
521 // allow only user owned directories, except the user is root 520 // allow only user owned directories, except the user is root
522 if (op == MOUNT_RDWR && getuid() != 0 && s.st_uid != getuid()) { 521 if (op != MOUNT_RDWR_NOCHECK && getuid() != 0 && s1.st_uid != getuid()) {
523 fwarning("you are not allowed to change %s to read-write\n", path); 522 fwarning("you are not allowed to change %s to read-write\n", path);
524 close(fd); 523 close(fd1);
525 return; 524 return;
526 } 525 }
527 flags &= ~MS_RDONLY; 526 flags &= ~MS_RDONLY;
@@ -530,7 +529,7 @@ static void fs_remount_simple(const char *path, OPERATION op) {
530 else if (op == MOUNT_NOEXEC) { 529 else if (op == MOUNT_NOEXEC) {
531 // nothing to do if path is mounted noexec already 530 // nothing to do if path is mounted noexec already
532 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) { 531 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) {
533 close(fd); 532 close(fd1);
534 return; 533 return;
535 } 534 }
536 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; 535 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID;
@@ -539,7 +538,7 @@ static void fs_remount_simple(const char *path, OPERATION op) {
539 else if (op == MOUNT_READONLY) { 538 else if (op == MOUNT_READONLY) {
540 // nothing to do if path is mounted read-only already 539 // nothing to do if path is mounted read-only already
541 if ((flags & MS_RDONLY) == MS_RDONLY) { 540 if ((flags & MS_RDONLY) == MS_RDONLY) {
542 close(fd); 541 close(fd1);
543 return; 542 return;
544 } 543 }
545 flags |= MS_RDONLY; 544 flags |= MS_RDONLY;
@@ -549,21 +548,25 @@ static void fs_remount_simple(const char *path, OPERATION op) {
549 548
550 if (arg_debug) 549 if (arg_debug)
551 printf("Mounting %s %s\n", opstr[op], path); 550 printf("Mounting %s %s\n", opstr[op], path);
552 // mount --bind /bin /bin 551 // mount --bind path path
553 char *proc; 552 char *proc;
554 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 553 if (asprintf(&proc, "/proc/self/fd/%d", fd1) == -1)
555 errExit("asprintf"); 554 errExit("asprintf");
556 if (mount(proc, proc, NULL, MS_BIND|MS_REC, NULL) < 0) 555 if (mount(proc, proc, NULL, MS_BIND|MS_REC, NULL) < 0)
557 errExit("mount"); 556 errExit("mount");
558 free(proc); 557 free(proc);
559 close(fd);
560 558
561 // mount --bind -o remount,ro /bin 559 // mount --bind -o remount,ro path
562 // we need to open path again 560 // need to open path again without following symbolic links
563 fd = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); 561 int fd2 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
564 if (fd == -1) 562 if (fd2 == -1)
565 errExit("open"); 563 errExit("open");
566 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 564 if (fstat(fd2, &s2) == -1)
565 errExit("fstat");
566 // device and inode number should be the same
567 if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
568 errLogExit("invalid %s mount", opstr[op]);
569 if (asprintf(&proc, "/proc/self/fd/%d", fd2) == -1)
567 errExit("asprintf"); 570 errExit("asprintf");
568 if (mount(NULL, proc, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0) 571 if (mount(NULL, proc, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
569 errExit("mount"); 572 errExit("mount");
@@ -579,7 +582,8 @@ static void fs_remount_simple(const char *path, OPERATION op) {
579 errLogExit("invalid %s mount", opstr[op]); 582 errLogExit("invalid %s mount", opstr[op]);
580 fs_logger2(opstr[op], path); 583 fs_logger2(opstr[op], path);
581 free(proc); 584 free(proc);
582 close(fd); 585 close(fd1);
586 close(fd2);
583 return; 587 return;
584 588
585out: 589out: