diff options
author | Simo Piiroinen <simo.piiroinen@jolla.com> | 2020-12-16 11:18:03 +0200 |
---|---|---|
committer | Tomi Leppänen <tomi.leppanen@jolla.com> | 2021-02-22 10:01:43 +0200 |
commit | 70cc108688f4e1f654534bf58cafe1caff3fc0e0 (patch) | |
tree | d4d9d581d7c287f3455ac42848843bfae9b293cc /src | |
parent | fcopy: Fix memory leaks (diff) | |
download | firejail-70cc108688f4e1f654534bf58cafe1caff3fc0e0.tar.gz firejail-70cc108688f4e1f654534bf58cafe1caff3fc0e0.tar.zst firejail-70cc108688f4e1f654534bf58cafe1caff3fc0e0.zip |
sandbox: Do not leave file mounts underneath private-etc
Firejail uses file bind-mounts to filter /etc/passwd and /etc/group
content. If private-etc is used, these mounts are left underneath
the /etc directory mount and this seems to be causing problems in
devices with older kernels: attempts to modify passwd or group
data fails with EBUSY.
Make it possible to perform fs_private_dir_list() actions in two
separate phases.
Undo the file mounts in /etc before mounting private-etc content.
Signed-off-by: Simo Piiroinen <simo.piiroinen@jolla.com>
Signed-off-by: Tomi Leppänen <tomi.leppanen@jolla.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs_etc.c | 9 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 25 |
3 files changed, 33 insertions, 3 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 719cd74ae..36340ff2c 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -649,6 +649,8 @@ void network_set_run_file(pid_t pid); | |||
649 | 649 | ||
650 | // fs_etc.c | 650 | // fs_etc.c |
651 | void fs_machineid(void); | 651 | void fs_machineid(void); |
652 | void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list); | ||
653 | void fs_private_dir_mount(const char *private_dir, const char *private_run_dir); | ||
652 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); | 654 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); |
653 | 655 | ||
654 | // no_sandbox.c | 656 | // no_sandbox.c |
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index d152ed2f6..60008f442 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c | |||
@@ -138,7 +138,7 @@ static void duplicate(const char *fname, const char *private_dir, const char *pr | |||
138 | } | 138 | } |
139 | 139 | ||
140 | 140 | ||
141 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) { | 141 | void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list) { |
142 | assert(private_dir); | 142 | assert(private_dir); |
143 | assert(private_run_dir); | 143 | assert(private_run_dir); |
144 | assert(private_list); | 144 | assert(private_list); |
@@ -185,7 +185,9 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c | |||
185 | free(dlist); | 185 | free(dlist); |
186 | fs_logger_print(); | 186 | fs_logger_print(); |
187 | } | 187 | } |
188 | } | ||
188 | 189 | ||
190 | void fs_private_dir_mount(const char *private_dir, const char *private_run_dir) { | ||
189 | if (arg_debug) | 191 | if (arg_debug) |
190 | printf("Mount-bind %s on top of %s\n", private_run_dir, private_dir); | 192 | printf("Mount-bind %s on top of %s\n", private_run_dir, private_dir); |
191 | if (mount(private_run_dir, private_dir, NULL, MS_BIND|MS_REC, NULL) < 0) | 193 | if (mount(private_run_dir, private_dir, NULL, MS_BIND|MS_REC, NULL) < 0) |
@@ -199,3 +201,8 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c | |||
199 | 201 | ||
200 | fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end()); | 202 | fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end()); |
201 | } | 203 | } |
204 | |||
205 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) { | ||
206 | fs_private_dir_copy(private_dir, private_run_dir, private_list); | ||
207 | fs_private_dir_mount(private_dir, private_run_dir); | ||
208 | } | ||
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 9a4be5cc0..ff5f4cb1e 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -969,8 +969,29 @@ int sandbox(void* sandbox_arg) { | |||
969 | else if (arg_overlay) | 969 | else if (arg_overlay) |
970 | fwarning("private-etc feature is disabled in overlay\n"); | 970 | fwarning("private-etc feature is disabled in overlay\n"); |
971 | else { | 971 | else { |
972 | fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep); | 972 | /* Current /etc/passwd and /etc/group files are bind |
973 | fs_private_dir_list("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE | 973 | * mounted filtered versions of originals. Leaving |
974 | * them underneath private-etc mount causes problems | ||
975 | * in devices with older kernels, e.g. attempts to | ||
976 | * update the real /etc/passwd file yield EBUSY. | ||
977 | * | ||
978 | * As we do want to retain filtered /etc content: | ||
979 | * 1. duplicate /etc content to RUN_ETC_DIR | ||
980 | * 2. unmount bind mounts from /etc | ||
981 | * 3. mount RUN_ETC_DIR at /etc | ||
982 | */ | ||
983 | fs_private_dir_copy("/etc", RUN_ETC_DIR, cfg.etc_private_keep); | ||
984 | fs_private_dir_copy("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE | ||
985 | |||
986 | if (umount2("/etc/group", MNT_DETACH) == -1) | ||
987 | fprintf(stderr, "/etc/group: unmount: %m\n"); | ||
988 | |||
989 | if (umount2("/etc/passwd", MNT_DETACH) == -1) | ||
990 | fprintf(stderr, "/etc/passwd: unmount: %m\n"); | ||
991 | |||
992 | fs_private_dir_mount("/etc", RUN_ETC_DIR); | ||
993 | fs_private_dir_mount("/usr/etc", RUN_USR_ETC_DIR); | ||
994 | |||
974 | // create /etc/ld.so.preload file again | 995 | // create /etc/ld.so.preload file again |
975 | if (need_preload) | 996 | if (need_preload) |
976 | fs_trace_preload(); | 997 | fs_trace_preload(); |