aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Simo Piiroinen <simo.piiroinen@jolla.com>2024-04-04 14:02:29 +0300
committerLibravatar Kelvin M. Klann <kmk3.code@protonmail.com>2024-04-18 13:23:37 -0300
commita7c92a322220b482eb76101d716ce9eab725dc3f (patch)
tree487de1d75e0f52e823963d09da7983bd8889ddc4
parentmodif: improve flock handling (diff)
downloadfirejail-serialize_remounts_v2.tar.gz
firejail-serialize_remounts_v2.tar.zst
firejail-serialize_remounts_v2.zip
modif: populate /run/firejail while holding flockserialize_remounts_v2
There are reports of firejail sandboxed applications occasionally taking a long time (12 seconds) to start up. When this happens, it affects all sandboxed applications until the device is rebooted. The reason for the slowdown seems to be a timing hazard in the way remounts under /run/firejail are handled. This gets triggered when multiple firejail processes are launched in parallel as part of user session bring up and results in some, dozens, hundreds, or even thousands of stray /run/firejail/xxx mounts. The amount of mount points then affects every mount operation that is done during sandbox filesystem construction. To stop this from happening, arrange it so that only one firejail process at time is inspecting and/or modifying mountpoints under /run/firejail by doing: 1. Create /run/firejail directory (without locking) 2. Create and obtain a lock for /run/firejail/firejail-run.lock 3. Setup files, directories and mounts under /run/firejail 4. Release /run/firejail/firejail-run.lock
-rw-r--r--src/firejail/chroot.c5
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/main.c10
-rw-r--r--src/firejail/preproc.c13
4 files changed, 23 insertions, 8 deletions
diff --git a/src/firejail/chroot.c b/src/firejail/chroot.c
index ffa6c8b51..67097852e 100644
--- a/src/firejail/chroot.c
+++ b/src/firejail/chroot.c
@@ -273,7 +273,10 @@ void fs_chroot(const char *rootdir) {
273 errExit("mounting /proc"); 273 errExit("mounting /proc");
274 274
275 // create all other /run/firejail files and directories 275 // create all other /run/firejail files and directories
276 preproc_build_firejail_dir(); 276 preproc_build_firejail_dir_unlocked();
277 preproc_lock_firejail_dir();
278 preproc_build_firejail_dir_locked();
279 preproc_unlock_firejail_dir();
277 280
278 // update /var directory in order to support multiple sandboxes running on the same root directory 281 // update /var directory in order to support multiple sandboxes running on the same root directory
279 // if (!arg_private_dev) 282 // if (!arg_private_dev)
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 273cebd45..736af018d 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -435,7 +435,8 @@ void preproc_lock_firejail_dir(void);
435void preproc_unlock_firejail_dir(void); 435void preproc_unlock_firejail_dir(void);
436void preproc_lock_firejail_network_dir(void); 436void preproc_lock_firejail_network_dir(void);
437void preproc_unlock_firejail_network_dir(void); 437void preproc_unlock_firejail_network_dir(void);
438void preproc_build_firejail_dir(void); 438void preproc_build_firejail_dir_unlocked(void);
439void preproc_build_firejail_dir_locked(void);
439void preproc_mount_mnt_dir(void); 440void preproc_mount_mnt_dir(void);
440void preproc_clean_run(void); 441void preproc_clean_run(void);
441 442
diff --git a/src/firejail/main.c b/src/firejail/main.c
index f00b46640..acbb4bf38 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -1166,13 +1166,13 @@ int main(int argc, char **argv, char **envp) {
1166#endif 1166#endif
1167 1167
1168 // build /run/firejail directory structure 1168 // build /run/firejail directory structure
1169 preproc_build_firejail_dir(); 1169 preproc_build_firejail_dir_unlocked();
1170 preproc_lock_firejail_dir();
1171 preproc_build_firejail_dir_locked();
1170 const char *container_name = env_get("container"); 1172 const char *container_name = env_get("container");
1171 if (!container_name || strcmp(container_name, "firejail")) { 1173 if (!container_name || strcmp(container_name, "firejail"))
1172 preproc_lock_firejail_dir();
1173 preproc_clean_run(); 1174 preproc_clean_run();
1174 preproc_unlock_firejail_dir(); 1175 preproc_unlock_firejail_dir();
1175 }
1176 1176
1177 delete_run_files(getpid()); 1177 delete_run_files(getpid());
1178 atexit(clear_atexit); 1178 atexit(clear_atexit);
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c
index 0f442a282..bec143f54 100644
--- a/src/firejail/preproc.c
+++ b/src/firejail/preproc.c
@@ -109,7 +109,10 @@ void preproc_unlock_firejail_network_dir(void) {
109} 109}
110 110
111// build /run/firejail directory 111// build /run/firejail directory
112void preproc_build_firejail_dir(void) { 112//
113// Note: This creates the base directory of the rundir lockfile;
114// it should be called before preproc_lock_firejail_dir().
115void preproc_build_firejail_dir_unlocked(void) {
113 struct stat s; 116 struct stat s;
114 117
115 // CentOS 6 doesn't have /run directory 118 // CentOS 6 doesn't have /run directory
@@ -118,6 +121,14 @@ void preproc_build_firejail_dir(void) {
118 } 121 }
119 122
120 create_empty_dir_as_root(RUN_FIREJAIL_DIR, 0755); 123 create_empty_dir_as_root(RUN_FIREJAIL_DIR, 0755);
124}
125
126// build directory hierarchy under /run/firejail
127//
128// Note: Remounts have timing hazards. This function should
129// only be called after acquiring the directory lock via
130// preproc_lock_firejail_dir().
131void preproc_build_firejail_dir_locked(void) {
121 create_empty_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755); 132 create_empty_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755);
122 create_empty_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755); 133 create_empty_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755);
123 create_empty_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755); 134 create_empty_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755);