aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Simo Piiroinen <simo.piiroinen@jolla.com>2020-12-16 11:18:03 +0200
committerLibravatar Tomi Leppänen <tomi.leppanen@jolla.com>2021-02-22 10:01:43 +0200
commit70cc108688f4e1f654534bf58cafe1caff3fc0e0 (patch)
treed4d9d581d7c287f3455ac42848843bfae9b293cc /src
parentfcopy: Fix memory leaks (diff)
downloadfirejail-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.h2
-rw-r--r--src/firejail/fs_etc.c9
-rw-r--r--src/firejail/sandbox.c25
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
651void fs_machineid(void); 651void fs_machineid(void);
652void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list);
653void fs_private_dir_mount(const char *private_dir, const char *private_run_dir);
652void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); 654void 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
141void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) { 141void 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
190void 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
205void 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();