aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/firecfg/firecfg.config1
-rw-r--r--src/firejail/fs.c1
-rw-r--r--src/firejail/fs_home.c7
-rw-r--r--src/firejail/fs_lib.c249
-rw-r--r--src/firejail/fs_lib2.c42
-rw-r--r--src/firejail/restrict_users.c65
-rw-r--r--src/firejail/util.c29
-rw-r--r--src/include/rundefs.h2
-rw-r--r--src/lib/ldd_utils.c4
9 files changed, 170 insertions, 230 deletions
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index 85a5b0453..3da415b70 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -875,6 +875,7 @@ yandex-browser
875yelp 875yelp
876youtube 876youtube
877youtube-dl 877youtube-dl
878youtube-dl-gui
878youtube-viewer 879youtube-viewer
879youtubemusic-nativefier 880youtubemusic-nativefier
880ytmdesktop 881ytmdesktop
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 9bc99fea5..fc67a15f3 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -170,6 +170,7 @@ static void disable_file(OPERATION op, const char *filename) {
170 } 170 }
171 } 171 }
172 fs_tmpfs(fname, getuid()); 172 fs_tmpfs(fname, getuid());
173 selinux_relabel_path(fname, fname);
173 last_disable = SUCCESSFUL; 174 last_disable = SUCCESSFUL;
174 } 175 }
175 else 176 else
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 2c5ea8be0..46f32d7ad 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -31,7 +31,7 @@
31 31
32#include <fcntl.h> 32#include <fcntl.h>
33#ifndef O_PATH 33#ifndef O_PATH
34# define O_PATH 010000000 34#define O_PATH 010000000
35#endif 35#endif
36 36
37static void skel(const char *homedir, uid_t u, gid_t g) { 37static void skel(const char *homedir, uid_t u, gid_t g) {
@@ -384,7 +384,6 @@ void fs_private(void) {
384 if (chown(homedir, u, g) < 0) 384 if (chown(homedir, u, g) < 0)
385 errExit("chown"); 385 errExit("chown");
386 386
387 selinux_relabel_path(homedir, homedir);
388 fs_logger2("mkdir", homedir); 387 fs_logger2("mkdir", homedir);
389 fs_logger2("tmpfs", homedir); 388 fs_logger2("tmpfs", homedir);
390 } 389 }
@@ -392,6 +391,8 @@ void fs_private(void) {
392 // mask user home directory 391 // mask user home directory
393 // the directory should be owned by the current user 392 // the directory should be owned by the current user
394 fs_tmpfs(homedir, 1); 393 fs_tmpfs(homedir, 1);
394
395 selinux_relabel_path(homedir, homedir);
395 } 396 }
396 397
397 skel(homedir, u, g); 398 skel(homedir, u, g);
@@ -549,7 +550,7 @@ void fs_private_home_list(void) {
549 550
550 // create /run/firejail/mnt/home directory 551 // create /run/firejail/mnt/home directory
551 mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); 552 mkdir_attr(RUN_HOME_DIR, 0755, uid, gid);
552 selinux_relabel_path(RUN_HOME_DIR, "/home"); 553 selinux_relabel_path(RUN_HOME_DIR, homedir);
553 fs_logger_print(); // save the current log 554 fs_logger_print(); // save the current log
554 555
555 if (arg_debug) 556 if (arg_debug)
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c
index 99d57fbbb..0491fd9b1 100644
--- a/src/firejail/fs_lib.c
+++ b/src/firejail/fs_lib.c
@@ -23,7 +23,8 @@
23#include <sys/stat.h> 23#include <sys/stat.h>
24#include <sys/types.h> 24#include <sys/types.h>
25#include <unistd.h> 25#include <unistd.h>
26#include <dirent.h> 26#include <fcntl.h>
27#include <errno.h>
27#include <glob.h> 28#include <glob.h>
28#define MAXBUF 4096 29#define MAXBUF 4096
29 30
@@ -34,7 +35,7 @@ extern void fslib_install_system(void);
34static int lib_cnt = 0; 35static int lib_cnt = 0;
35static int dir_cnt = 0; 36static int dir_cnt = 0;
36 37
37static const char *lib_dirs[] = { 38static const char *masked_lib_dirs[] = {
38 "/usr/lib64", 39 "/usr/lib64",
39 "/lib64", 40 "/lib64",
40 "/usr/lib", 41 "/usr/lib",
@@ -44,15 +45,15 @@ static const char *lib_dirs[] = {
44 NULL, 45 NULL,
45}; 46};
46 47
47// return 1 if the file is in lib_dirs[] 48// return 1 if the file is in masked_lib_dirs[]
48static int valid_full_path(const char *full_path) { 49static int valid_full_path(const char *full_path) {
49 if (strstr(full_path, "..")) 50 if (strstr(full_path, ".."))
50 return 0; 51 return 0;
51 52
52 int i = 0; 53 int i = 0;
53 while (lib_dirs[i]) { 54 while (masked_lib_dirs[i]) {
54 if (strncmp(full_path, lib_dirs[i], strlen(lib_dirs[i])) == 0 && 55 if (strncmp(full_path, masked_lib_dirs[i], strlen(masked_lib_dirs[i])) == 0 &&
55 full_path[strlen(lib_dirs[i])] == '/') 56 full_path[strlen(masked_lib_dirs[i])] == '/')
56 return 1; 57 return 1;
57 i++; 58 i++;
58 } 59 }
@@ -70,9 +71,10 @@ char *find_in_path(const char *program) {
70 errExit("readlink"); 71 errExit("readlink");
71 self[len] = '\0'; 72 self[len] = '\0';
72 73
73 char *path = getenv("PATH"); 74 const char *path = env_get("PATH");
74 if (!path) 75 if (!path)
75 return NULL; 76 return NULL;
77
76 char *dup = strdup(path); 78 char *dup = strdup(path);
77 if (!dup) 79 if (!dup)
78 errExit("strdup"); 80 errExit("strdup");
@@ -105,22 +107,6 @@ char *find_in_path(const char *program) {
105 return NULL; 107 return NULL;
106} 108}
107 109
108static void report_duplication(const char *full_path) {
109 char *fname = strrchr(full_path, '/');
110 if (fname && *(++fname) != '\0') {
111 // report the file on all bin paths
112 int i = 0;
113 while (default_lib_paths[i]) {
114 char *p;
115 if (asprintf(&p, "%s/%s", default_lib_paths[i], fname) == -1)
116 errExit("asprintf");
117 fs_logger2("clone", p);
118 free(p);
119 i++;
120 }
121 }
122}
123
124static char *build_dest_dir(const char *full_path) { 110static char *build_dest_dir(const char *full_path) {
125 assert(full_path); 111 assert(full_path);
126 if (strstr(full_path, "/x86_64-linux-gnu/")) 112 if (strstr(full_path, "/x86_64-linux-gnu/"))
@@ -128,57 +114,107 @@ static char *build_dest_dir(const char *full_path) {
128 return RUN_LIB_DIR; 114 return RUN_LIB_DIR;
129} 115}
130 116
131// copy fname in private_run_dir 117// return name of mount target in allocated memory
132void fslib_duplicate(const char *full_path) { 118static char *build_dest_name(const char *full_path) {
133 assert(full_path); 119 assert(full_path);
120 char *fname = strrchr(full_path, '/');
121 assert(fname);
122 fname++;
123 assert(*fname != '\0');
134 124
135 struct stat s; 125 char *dest;
136 if (stat(full_path, &s) != 0 || s.st_uid != 0 || access(full_path, R_OK) 126 if (asprintf(&dest, "%s/%s", build_dest_dir(full_path), fname) == -1)
137 || !valid_full_path(full_path)) 127 errExit("asprintf");
138 return; 128 return dest;
129}
139 130
140 char *dest_dir = build_dest_dir(full_path); 131static void fslib_mount_dir(const char *full_path) {
132 // create new directory and mount the original on top of it
133 char *dest = build_dest_name(full_path);
134 if (mkdir(dest, 0755) == -1) {
135 if (errno == EEXIST) { // directory has been mounted already, nothing to do
136 free(dest);
137 return;
138 }
139 errExit("mkdir");
140 }
141 141
142 // don't copy it if the file is already there 142 if (arg_debug || arg_debug_private_lib)
143 char *ptr = strrchr(full_path, '/'); 143 printf(" mounting %s on %s\n", full_path, dest);
144 if (!ptr) 144 // if full_path is a symbolic link, mount will follow it
145 return; 145 if (mount(full_path, dest, NULL, MS_BIND|MS_REC, NULL) < 0)
146 ptr++; 146 errExit("mount bind");
147 if (*ptr == '\0') 147 free(dest);
148 return; 148 dir_cnt++;
149}
149 150
150 char *name; 151static void fslib_mount_file(const char *full_path) {
151 if (asprintf(&name, "%s/%s", dest_dir, ptr) == -1) 152 // create new file and mount the original on top of it
152 errExit("asprintf"); 153 char *dest = build_dest_name(full_path);
153 if (stat(name, &s) == 0) { 154 int fd = open(dest, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR);
154 free(name); 155 if (fd == -1) {
155 return; 156 if (errno == EEXIST) { // file has been mounted already, nothing to do
157 free(dest);
158 return;
159 }
160 errExit("open");
156 } 161 }
157 free(name); 162 close(fd);
158 163
159 if (arg_debug || arg_debug_private_lib) 164 if (arg_debug || arg_debug_private_lib)
160 printf(" copying %s to private %s\n", full_path, dest_dir); 165 printf(" mounting %s on %s\n", full_path, dest);
161 166 // if full_path is a symbolic link, mount will follow it
162 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", full_path, dest_dir); 167 if (mount(full_path, dest, NULL, MS_BIND, NULL) < 0)
163 report_duplication(full_path); 168 errExit("mount bind");
169 free(dest);
164 lib_cnt++; 170 lib_cnt++;
165} 171}
166 172
173void fslib_mount(const char *full_path) {
174 assert(full_path);
175 struct stat s;
176
177 if (!valid_full_path(full_path) ||
178 access(full_path, F_OK) != 0 ||
179 stat(full_path, &s) != 0 ||
180 s.st_uid != 0)
181 return;
182
183 if (S_ISDIR(s.st_mode))
184 fslib_mount_dir(full_path);
185 else if (S_ISREG(s.st_mode) && is_lib_64(full_path))
186 fslib_mount_file(full_path);
187}
188
167// requires full path for lib 189// requires full path for lib
168// it could be a library or an executable 190// it could be a library or an executable
169// lib is not copied, only libraries used by it 191// lib is not copied, only libraries used by it
170static void fslib_copy_libs(const char *full_path, unsigned mask) { 192void fslib_mount_libs(const char *full_path, unsigned user) {
193 assert(full_path);
194 // if library/executable does not exist or the user does not have read access to it
195 // print a warning and exit the function.
196 if (user && access(full_path, R_OK)) {
197 if (arg_debug || arg_debug_private_lib)
198 printf("Cannot read %s, skipping...\n", full_path);
199 return;
200 }
201
202 if (arg_debug || arg_debug_private_lib)
203 printf(" fslib_mount_libs %s (parse as %s)\n", full_path, user ? "user" : "root");
171 // create an empty RUN_LIB_FILE and allow the user to write to it 204 // create an empty RUN_LIB_FILE and allow the user to write to it
172 unlink(RUN_LIB_FILE); // in case is there 205 unlink(RUN_LIB_FILE); // in case is there
173 create_empty_file_as_root(RUN_LIB_FILE, 0644); 206 create_empty_file_as_root(RUN_LIB_FILE, 0644);
174 if (mask & SBOX_USER) { 207 if (user && chown(RUN_LIB_FILE, getuid(), getgid()))
175 if (chown(RUN_LIB_FILE, getuid(), getgid())) 208 errExit("chown");
176 errExit("chown");
177 }
178 209
179 // run fldd to extract the list of files 210 // run fldd to extract the list of files
180 if (arg_debug || arg_debug_private_lib) 211 if (arg_debug || arg_debug_private_lib)
181 printf(" running fldd %s\n", full_path); 212 printf(" running fldd %s\n", full_path);
213 unsigned mask;
214 if (user)
215 mask = SBOX_USER;
216 else
217 mask = SBOX_ROOT;
182 sbox_run(mask | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE); 218 sbox_run(mask | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE);
183 219
184 // open the list of libraries and install them on by one 220 // open the list of libraries and install them on by one
@@ -192,97 +228,30 @@ static void fslib_copy_libs(const char *full_path, unsigned mask) {
192 char *ptr = strchr(buf, '\n'); 228 char *ptr = strchr(buf, '\n');
193 if (ptr) 229 if (ptr)
194 *ptr = '\0'; 230 *ptr = '\0';
195 fslib_duplicate(buf); 231
232 fslib_mount(buf);
196 } 233 }
197 fclose(fp); 234 fclose(fp);
198 unlink(RUN_LIB_FILE); 235 unlink(RUN_LIB_FILE);
199} 236}
200 237
201void fslib_copy_libs_parse_as_root(const char *full_path) { 238// fname should be a valid full path at this point
202 assert(full_path);
203 if (arg_debug || arg_debug_private_lib)
204 printf(" fslib_copy_libs_parse_as_root %s\n", full_path);
205
206 struct stat s;
207 if (stat(full_path, &s)) {
208 if (arg_debug || arg_debug_private_lib)
209 printf("cannot find %s for private-lib, skipping...\n", full_path);
210 return;
211 }
212 fslib_copy_libs(full_path, SBOX_ROOT);
213}
214
215// if library/executable does not exist or the user does not have read access to it
216// print a warning and exit the function.
217void fslib_copy_libs_parse_as_user(const char *full_path) {
218 assert(full_path);
219 if (arg_debug || arg_debug_private_lib)
220 printf(" fslib_copy_libs_parse_as_user %s\n", full_path);
221
222 if (access(full_path, R_OK)) {
223 if (arg_debug || arg_debug_private_lib)
224 printf("cannot find %s for private-lib, skipping...\n", full_path);
225 return;
226 }
227 fslib_copy_libs(full_path, SBOX_USER);
228}
229
230void fslib_copy_dir(const char *full_path) {
231 assert(full_path);
232 if (arg_debug || arg_debug_private_lib)
233 printf(" fslib_copy_dir %s\n", full_path);
234
235 // do nothing if the directory does not exist or is not owned by root
236 struct stat s;
237 if (stat(full_path, &s) != 0 || s.st_uid != 0 || !S_ISDIR(s.st_mode) || access(full_path, R_OK)
238 || !valid_full_path(full_path))
239 return;
240
241 char *dir_name = strrchr(full_path, '/');
242 assert(dir_name);
243 dir_name++;
244 assert(*dir_name != '\0');
245
246 // do nothing if the directory is already there
247 char *dest;
248 if (asprintf(&dest, "%s/%s", build_dest_dir(full_path), dir_name) == -1)
249 errExit("asprintf");
250 if (stat(dest, &s) == 0) {
251 free(dest);
252 return;
253 }
254
255 // create new directory and mount the original on top of it
256 mkdir_attr(dest, 0755, 0, 0);
257
258 if (mount(full_path, dest, NULL, MS_BIND|MS_REC, NULL) < 0 ||
259 mount(NULL, dest, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
260 errExit("mount bind");
261 fs_logger2("clone", full_path);
262 fs_logger2("mount", full_path);
263 dir_cnt++;
264 free(dest);
265}
266
267// fname should be a vallid full path at this point
268static void load_library(const char *fname) { 239static void load_library(const char *fname) {
269 assert(fname); 240 assert(fname);
270 assert(*fname == '/'); 241 assert(*fname == '/');
271 242
272 // existing file owned by root, read access 243 // existing file owned by root
273 struct stat s; 244 struct stat s;
274 if (stat(fname, &s) == 0 && s.st_uid == 0 && !access(fname, R_OK)) { 245 if (!access(fname, F_OK) && stat(fname, &s) == 0 && s.st_uid == 0) {
275 // load directories, regular 64 bit libraries, and 64 bit executables 246 // load directories, regular 64 bit libraries, and 64 bit executables
276 if (is_dir(fname) || is_lib_64(fname)) { 247 if (S_ISDIR(s.st_mode))
277 if (is_dir(fname)) 248 fslib_mount(fname);
278 fslib_copy_dir(fname); 249 else if (S_ISREG(s.st_mode) && is_lib_64(fname)) {
279 else { 250 if (strstr(fname, ".so") ||
280 if (strstr(fname, ".so") || 251 access(fname, X_OK) != 0) // don't duplicate executables, just install the libraries
281 access(fname, X_OK) != 0) // don't duplicate executables, just install the libraries 252 fslib_mount(fname);
282 fslib_duplicate(fname); 253
283 254 fslib_mount_libs(fname, 1); // parse as user
284 fslib_copy_libs_parse_as_user(fname);
285 }
286 } 255 }
287 } 256 }
288} 257}
@@ -338,7 +307,6 @@ static void install_list_entry(const char *lib) {
338 return; 307 return;
339} 308}
340 309
341
342void fslib_install_list(const char *lib_list) { 310void fslib_install_list(const char *lib_list) {
343 assert(lib_list); 311 assert(lib_list);
344 if (arg_debug || arg_debug_private_lib) 312 if (arg_debug || arg_debug_private_lib)
@@ -365,14 +333,14 @@ static void mount_directories(void) {
365 fs_remount(RUN_LIB_DIR, MOUNT_READONLY, 1); // should be redundant except for RUN_LIB_DIR itself 333 fs_remount(RUN_LIB_DIR, MOUNT_READONLY, 1); // should be redundant except for RUN_LIB_DIR itself
366 334
367 int i = 0; 335 int i = 0;
368 while (lib_dirs[i]) { 336 while (masked_lib_dirs[i]) {
369 if (is_dir(lib_dirs[i])) { 337 if (is_dir(masked_lib_dirs[i])) {
370 if (arg_debug || arg_debug_private_lib) 338 if (arg_debug || arg_debug_private_lib)
371 printf("Mount-bind %s on top of %s\n", RUN_LIB_DIR, lib_dirs[i]); 339 printf("Mount-bind %s on top of %s\n", RUN_LIB_DIR, masked_lib_dirs[i]);
372 if (mount(RUN_LIB_DIR, lib_dirs[i], NULL, MS_BIND|MS_REC, NULL) < 0) 340 if (mount(RUN_LIB_DIR, masked_lib_dirs[i], NULL, MS_BIND|MS_REC, NULL) < 0)
373 errExit("mount bind"); 341 errExit("mount bind");
374 fs_logger2("tmpfs", lib_dirs[i]); 342 fs_logger2("tmpfs", masked_lib_dirs[i]);
375 fs_logger2("mount", lib_dirs[i]); 343 fs_logger2("mount", masked_lib_dirs[i]);
376 } 344 }
377 i++; 345 i++;
378 } 346 }
@@ -444,7 +412,6 @@ void fs_private_lib(void) {
444 fslib_install_list(cfg.shell); 412 fslib_install_list(cfg.shell);
445 // a shell is useless without some basic commands 413 // a shell is useless without some basic commands
446 fslib_install_list("/bin/ls,/bin/cat,/bin/mv,/bin/rm"); 414 fslib_install_list("/bin/ls,/bin/cat,/bin/mv,/bin/rm");
447
448 } 415 }
449 416
450 // for the listed libs and directories 417 // for the listed libs and directories
diff --git a/src/firejail/fs_lib2.c b/src/firejail/fs_lib2.c
index d46cfed86..c69bf7c98 100644
--- a/src/firejail/fs_lib2.c
+++ b/src/firejail/fs_lib2.c
@@ -21,10 +21,8 @@
21#include <dirent.h> 21#include <dirent.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23 23
24extern void fslib_duplicate(const char *full_path); 24extern void fslib_mount_libs(const char *full_path, unsigned user);
25extern void fslib_copy_libs_parse_as_user(const char *full_path); 25extern void fslib_mount(const char *full_path);
26extern void fslib_copy_libs_parse_as_root(const char *full_path);
27extern void fslib_copy_dir(const char *full_path);
28 26
29//*************************************************************** 27//***************************************************************
30// Standard C library 28// Standard C library
@@ -98,7 +96,8 @@ static void stdc(const char *dirname) {
98 if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1) 96 if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1)
99 errExit("asprintf"); 97 errExit("asprintf");
100 98
101 fslib_duplicate(fname); 99 fslib_mount(fname);
100 free(fname);
102 } 101 }
103 } 102 }
104 closedir(dir); 103 closedir(dir);
@@ -119,7 +118,7 @@ void fslib_install_stdc(void) {
119 118
120 // install locale 119 // install locale
121 if (stat("/usr/lib/locale", &s) == 0) 120 if (stat("/usr/lib/locale", &s) == 0)
122 fslib_copy_dir("/usr/lib/locale"); 121 fslib_mount("/usr/lib/locale");
123 122
124 fmessage("Standard C library installed in %0.2f ms\n", timetrace_end()); 123 fmessage("Standard C library installed in %0.2f ms\n", timetrace_end());
125} 124}
@@ -129,7 +128,8 @@ void fslib_install_stdc(void) {
129//*************************************************************** 128//***************************************************************
130 129
131static void fdir(void) { 130static void fdir(void) {
132 fslib_copy_dir(LIBDIR "/firejail"); 131 // firejail directory itself
132 fslib_mount(LIBDIR "/firejail");
133 133
134 // executables and libraries from firejail directory 134 // executables and libraries from firejail directory
135 static const char * const fbin[] = { 135 static const char * const fbin[] = {
@@ -143,30 +143,28 @@ static void fdir(void) {
143 NULL, 143 NULL,
144 }; 144 };
145 145
146 // need to run fldd as root user, unprivileged users have no read permission on executables 146 // need to parse as root user, unprivileged users have no read permission on executables
147 int i; 147 int i;
148 for (i = 0; fbin[i]; i++) 148 for (i = 0; fbin[i]; i++)
149 fslib_copy_libs_parse_as_root(fbin[i]); 149 fslib_mount_libs(fbin[i], 0);
150} 150}
151 151
152void fslib_install_firejail(void) { 152void fslib_install_firejail(void) {
153 timetrace_start(); 153 timetrace_start();
154 // bring in firejail executable libraries, in case we are redirected here 154 // bring in firejail executable libraries, in case we are redirected here
155 // by a firejail symlink from /usr/local/bin/firejail 155 // by a firejail symlink from /usr/local/bin/firejail
156 fslib_copy_libs_parse_as_user(PATH_FIREJAIL); 156 fslib_mount_libs(PATH_FIREJAIL, 1); // parse as user
157 157
158 // bring in firejail directory 158 // bring in firejail directory
159 fdir(); 159 fdir();
160 160
161 // bring in dhclient libraries 161 // bring in dhclient libraries
162 if (any_dhcp()) 162 if (any_dhcp())
163 fslib_copy_libs_parse_as_user(RUN_MNT_DIR "/dhclient"); 163 fslib_mount_libs(RUN_MNT_DIR "/dhclient", 1); // parse as user
164 164
165#ifdef HAVE_X11
166 // bring in xauth libraries 165 // bring in xauth libraries
167 if (arg_x11_xorg) 166 if (arg_x11_xorg)
168 fslib_copy_libs_parse_as_user("/usr/bin/xauth"); 167 fslib_mount_libs("/usr/bin/xauth", 1); // parse as user
169#endif
170 168
171 fmessage("Firejail libraries installed in %0.2f ms\n", timetrace_end()); 169 fmessage("Firejail libraries installed in %0.2f ms\n", timetrace_end());
172} 170}
@@ -315,8 +313,8 @@ void fslib_install_system(void) {
315 if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir1) == -1) 313 if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir1) == -1)
316 errExit("asprintf"); 314 errExit("asprintf");
317 if (access(name, R_OK) == 0) { 315 if (access(name, R_OK) == 0) {
318 fslib_copy_libs_parse_as_user(name); 316 fslib_mount_libs(name, 1); // parse as user
319 fslib_copy_dir(name); 317 fslib_mount(name);
320 } 318 }
321 else { 319 else {
322 free(name); 320 free(name);
@@ -324,8 +322,8 @@ void fslib_install_system(void) {
324 if (asprintf(&name, "/usr/lib64/%s", ptr->dir1) == -1) 322 if (asprintf(&name, "/usr/lib64/%s", ptr->dir1) == -1)
325 errExit("asprintf"); 323 errExit("asprintf");
326 if (access(name, R_OK) == 0) { 324 if (access(name, R_OK) == 0) {
327 fslib_copy_libs_parse_as_user(name); 325 fslib_mount_libs(name, 1); // parse as user
328 fslib_copy_dir(name); 326 fslib_mount(name);
329 } 327 }
330 } 328 }
331 free(name); 329 free(name);
@@ -335,8 +333,8 @@ void fslib_install_system(void) {
335 if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir2) == -1) 333 if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir2) == -1)
336 errExit("asprintf"); 334 errExit("asprintf");
337 if (access(name, R_OK) == 0) { 335 if (access(name, R_OK) == 0) {
338 fslib_copy_libs_parse_as_user(name); 336 fslib_mount_libs(name, 1); // parse as user
339 fslib_copy_dir(name); 337 fslib_mount(name);
340 } 338 }
341 else { 339 else {
342 free(name); 340 free(name);
@@ -344,8 +342,8 @@ void fslib_install_system(void) {
344 if (asprintf(&name, "/usr/lib64/%s", ptr->dir2) == -1) 342 if (asprintf(&name, "/usr/lib64/%s", ptr->dir2) == -1)
345 errExit("asprintf"); 343 errExit("asprintf");
346 if (access(name, R_OK) == 0) { 344 if (access(name, R_OK) == 0) {
347 fslib_copy_libs_parse_as_user(name); 345 fslib_mount_libs(name, 1); // parse as user
348 fslib_copy_dir(name); 346 fslib_mount(name);
349 } 347 }
350 } 348 }
351 free(name); 349 free(name);
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c
index 0dfd9ca1c..a0ca4c02c 100644
--- a/src/firejail/restrict_users.c
+++ b/src/firejail/restrict_users.c
@@ -72,7 +72,7 @@ static void sanitize_home(void) {
72 72
73 if (arg_debug) 73 if (arg_debug)
74 printf("Cleaning /home directory\n"); 74 printf("Cleaning /home directory\n");
75 // keep a copy of the user home directory 75 // open user home directory in order to keep it around
76 int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 76 int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
77 if (fd == -1) 77 if (fd == -1)
78 goto errout; 78 goto errout;
@@ -82,47 +82,38 @@ static void sanitize_home(void) {
82 close(fd); 82 close(fd);
83 goto errout; 83 goto errout;
84 } 84 }
85 char *proc;
86 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
87 errExit("asprintf");
88 if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1)
89 errExit("mkdir");
90 if (mount(proc, RUN_WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
91 errExit("mount bind");
92 free(proc);
93 close(fd);
94 85
95 // mount tmpfs in the new home 86 // mount tmpfs on /home
96 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) 87 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
97 errExit("mount tmpfs"); 88 errExit("mount tmpfs");
98 selinux_relabel_path("/home", "/home"); 89 selinux_relabel_path("/home", "/home");
99 fs_logger("tmpfs /home"); 90 fs_logger("tmpfs /home");
100 91
101 // create user home directory 92 // create new user home directory
102 if (mkdir(cfg.homedir, 0755) == -1) { 93 if (mkdir(cfg.homedir, 0755) == -1) {
103 if (mkpath_as_root(cfg.homedir)) 94 if (mkpath_as_root(cfg.homedir) == -1)
104 errExit("mkpath"); 95 errExit("mkpath");
105 if (mkdir(cfg.homedir, 0755) == -1) 96 if (mkdir(cfg.homedir, 0755) == -1)
106 errExit("mkdir"); 97 errExit("mkdir");
107 selinux_relabel_path(cfg.homedir, cfg.homedir);
108 } 98 }
109 fs_logger2("mkdir", cfg.homedir); 99 fs_logger2("mkdir", cfg.homedir);
110 100
111 // set mode and ownership 101 // set mode and ownership
112 if (set_perms(cfg.homedir, s.st_uid, s.st_gid, s.st_mode)) 102 if (set_perms(cfg.homedir, s.st_uid, s.st_gid, s.st_mode))
113 errExit("set_perms"); 103 errExit("set_perms");
104 selinux_relabel_path(cfg.homedir, cfg.homedir);
114 105
115 // mount user home directory 106 // bring back real user home directory
116 if (mount(RUN_WHITELIST_HOME_DIR, cfg.homedir, NULL, MS_BIND|MS_REC, NULL) < 0) 107 char *proc;
108 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
109 errExit("asprintf");
110 if (mount(proc, cfg.homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
117 errExit("mount bind"); 111 errExit("mount bind");
112 free(proc);
113 close(fd);
118 114
119 // mask home dir under /run
120 if (mount("tmpfs", RUN_WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
121 errExit("mount tmpfs");
122 fs_logger2("tmpfs", RUN_WHITELIST_HOME_DIR);
123 if (!arg_private) 115 if (!arg_private)
124 fs_logger2("whitelist", cfg.homedir); 116 fs_logger2("whitelist", cfg.homedir);
125
126 return; 117 return;
127 118
128errout: 119errout:
@@ -137,22 +128,15 @@ static void sanitize_run(void) {
137 if (asprintf(&runuser, "/run/user/%u", getuid()) == -1) 128 if (asprintf(&runuser, "/run/user/%u", getuid()) == -1)
138 errExit("asprintf"); 129 errExit("asprintf");
139 130
140 struct stat s; 131 // open /run/user/$UID directory in order to keep it around
141 if (stat(runuser, &s) == -1) { 132 int fd = open(runuser, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
142 // cannot find /user/run/$UID directory, just return 133 if (fd == -1) {
143 if (arg_debug) 134 if (arg_debug)
144 printf("Cannot find %s directory\n", runuser); 135 printf("Cannot open %s directory\n", runuser);
145 free(runuser); 136 free(runuser);
146 return; 137 return;
147 } 138 }
148 139
149 if (mkdir(RUN_WHITELIST_RUN_DIR, 0755) == -1)
150 errExit("mkdir");
151
152 // keep a copy of the /run/user/$UID directory
153 if (mount(runuser, RUN_WHITELIST_RUN_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
154 errExit("mount bind");
155
156 // mount tmpfs on /run/user 140 // mount tmpfs on /run/user
157 if (mount("tmpfs", "/run/user", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) 141 if (mount("tmpfs", "/run/user", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
158 errExit("mount tmpfs"); 142 errExit("mount tmpfs");
@@ -162,22 +146,23 @@ static void sanitize_run(void) {
162 // create new user directory 146 // create new user directory
163 if (mkdir(runuser, 0700) == -1) 147 if (mkdir(runuser, 0700) == -1)
164 errExit("mkdir"); 148 errExit("mkdir");
165 selinux_relabel_path(runuser, runuser);
166 fs_logger2("mkdir", runuser); 149 fs_logger2("mkdir", runuser);
167 150
168 // set mode and ownership 151 // set mode and ownership
169 if (set_perms(runuser, getuid(), getgid(), 0700)) 152 if (set_perms(runuser, getuid(), getgid(), 0700))
170 errExit("set_perms"); 153 errExit("set_perms");
154 selinux_relabel_path(runuser, runuser);
171 155
172 // mount /run/user/$UID directory 156 // bring back real run/user/$UID directory
173 if (mount(RUN_WHITELIST_RUN_DIR, runuser, NULL, MS_BIND|MS_REC, NULL) < 0) 157 char *proc;
158 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
159 errExit("asprintf");
160 if (mount(proc, runuser, NULL, MS_BIND|MS_REC, NULL) < 0)
174 errExit("mount bind"); 161 errExit("mount bind");
162 free(proc);
163 close(fd);
175 164
176 // mask mirrored /run/user/$UID directory 165 fs_logger2("whitelist", runuser);
177 if (mount("tmpfs", RUN_WHITELIST_RUN_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
178 errExit("mount tmpfs");
179 fs_logger2("tmpfs", RUN_WHITELIST_RUN_DIR);
180
181 free(runuser); 166 free(runuser);
182} 167}
183 168
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 53c671794..2ad85acd6 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -441,35 +441,22 @@ int is_dir(const char *fname) {
441 return 0; 441 return 0;
442} 442}
443 443
444
445// return 1 if the file is a link 444// return 1 if the file is a link
446int is_link(const char *fname) { 445int is_link(const char *fname) {
447 assert(fname); 446 assert(fname);
448 if (*fname == '\0') 447 if (*fname == '\0')
449 return 0; 448 return 0;
450 449
451 char *dup = NULL; 450 char *dup = strdup(fname);
452 struct stat s; 451 if (!dup)
453 if (lstat(fname, &s) == 0) { 452 errExit("strdup");
454 if (S_ISLNK(s.st_mode)) 453 trim_trailing_slash_or_dot(dup);
455 return 1; 454
456 if (S_ISDIR(s.st_mode)) { 455 char c;
457 // remove trailing slashes and single dots and try again 456 ssize_t rv = readlink(dup, &c, 1);
458 dup = strdup(fname);
459 if (!dup)
460 errExit("strdup");
461 trim_trailing_slash_or_dot(dup);
462 if (lstat(dup, &s) == 0) {
463 if (S_ISLNK(s.st_mode)) {
464 free(dup);
465 return 1;
466 }
467 }
468 }
469 }
470 457
471 free(dup); 458 free(dup);
472 return 0; 459 return (rv != -1);
473} 460}
474 461
475// remove all slashes and single dots from the end of a path 462// remove all slashes and single dots from the end of a path
diff --git a/src/include/rundefs.h b/src/include/rundefs.h
index 5749c66e4..d14f6782f 100644
--- a/src/include/rundefs.h
+++ b/src/include/rundefs.h
@@ -84,8 +84,6 @@
84#define RUN_DEVLOG_FILE RUN_MNT_DIR "/devlog" 84#define RUN_DEVLOG_FILE RUN_MNT_DIR "/devlog"
85 85
86#define RUN_WHITELIST_X11_DIR RUN_MNT_DIR "/orig-x11" 86#define RUN_WHITELIST_X11_DIR RUN_MNT_DIR "/orig-x11"
87#define RUN_WHITELIST_HOME_DIR RUN_MNT_DIR "/orig-home" // default home directory masking
88#define RUN_WHITELIST_RUN_DIR RUN_MNT_DIR "/orig-run" // default run directory masking
89#define RUN_WHITELIST_HOME_USER_DIR RUN_MNT_DIR "/orig-home-user" // home directory whitelisting 87#define RUN_WHITELIST_HOME_USER_DIR RUN_MNT_DIR "/orig-home-user" // home directory whitelisting
90#define RUN_WHITELIST_RUN_USER_DIR RUN_MNT_DIR "/orig-run-user" // run directory whitelisting 88#define RUN_WHITELIST_RUN_USER_DIR RUN_MNT_DIR "/orig-run-user" // run directory whitelisting
91#define RUN_WHITELIST_TMP_DIR RUN_MNT_DIR "/orig-tmp" 89#define RUN_WHITELIST_TMP_DIR RUN_MNT_DIR "/orig-tmp"
diff --git a/src/lib/ldd_utils.c b/src/lib/ldd_utils.c
index 43fee4f21..cd60d74e4 100644
--- a/src/lib/ldd_utils.c
+++ b/src/lib/ldd_utils.c
@@ -23,12 +23,14 @@
23#include <sys/stat.h> 23#include <sys/stat.h>
24#include <fcntl.h> 24#include <fcntl.h>
25 25
26// todo: resolve overlap with masked_lib_dirs[] array from fs_lib.c
26const char * const default_lib_paths[] = { 27const char * const default_lib_paths[] = {
27 "/usr/lib/x86_64-linux-gnu", // Debian & friends 28 "/usr/lib/x86_64-linux-gnu", // Debian & friends
28 "/lib/x86_64-linux-gnu", // CentOS, Fedora 29 "/lib/x86_64-linux-gnu", // CentOS, Fedora
30 "/usr/lib64",
31 "/lib64",
29 "/usr/lib", 32 "/usr/lib",
30 "/lib", 33 "/lib",
31 "/lib64",
32 LIBDIR, 34 LIBDIR,
33 "/usr/local/lib64", 35 "/usr/local/lib64",
34 "/usr/local/lib", 36 "/usr/local/lib",