aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/inc/disable-common.inc2
-rw-r--r--etc/profile-a-l/ghostwriter.profile2
-rw-r--r--etc/profile-m-z/marker.profile4
-rw-r--r--etc/profile-m-z/tcpdump.profile1
-rw-r--r--src/firejail/fs_lib.c249
-rw-r--r--src/firejail/fs_lib2.c42
-rw-r--r--src/jailtest/jailtest.h4
-rw-r--r--src/jailtest/main.c29
-rw-r--r--src/jailtest/sysfiles.c88
-rw-r--r--src/lib/ldd_utils.c4
10 files changed, 257 insertions, 168 deletions
diff --git a/etc/inc/disable-common.inc b/etc/inc/disable-common.inc
index d724e3b52..52534a9e9 100644
--- a/etc/inc/disable-common.inc
+++ b/etc/inc/disable-common.inc
@@ -442,6 +442,7 @@ blacklist ${PATH}/mount
442blacklist ${PATH}/mount.ecryptfs_private 442blacklist ${PATH}/mount.ecryptfs_private
443blacklist ${PATH}/nc 443blacklist ${PATH}/nc
444blacklist ${PATH}/ncat 444blacklist ${PATH}/ncat
445blacklist ${PATH}/nmap
445blacklist ${PATH}/newgidmap 446blacklist ${PATH}/newgidmap
446blacklist ${PATH}/newgrp 447blacklist ${PATH}/newgrp
447blacklist ${PATH}/newuidmap 448blacklist ${PATH}/newuidmap
@@ -452,6 +453,7 @@ blacklist ${PATH}/sg
452blacklist ${PATH}/strace 453blacklist ${PATH}/strace
453blacklist ${PATH}/su 454blacklist ${PATH}/su
454blacklist ${PATH}/sudo 455blacklist ${PATH}/sudo
456blacklist ${PATH}/tcpdump
455blacklist ${PATH}/umount 457blacklist ${PATH}/umount
456blacklist ${PATH}/unix_chkpwd 458blacklist ${PATH}/unix_chkpwd
457blacklist ${PATH}/xev 459blacklist ${PATH}/xev
diff --git a/etc/profile-a-l/ghostwriter.profile b/etc/profile-a-l/ghostwriter.profile
index d56d6714e..820d5e694 100644
--- a/etc/profile-a-l/ghostwriter.profile
+++ b/etc/profile-a-l/ghostwriter.profile
@@ -55,5 +55,5 @@ private-dev
55private-etc alternatives,ca-certificates,crypto-policies,dbus-1,dconf,firejail,fonts,gconf,groups,gtk-2.0,gtk-3.0,host.conf,hostname,hosts,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,login.defs,machine-id,mime.types,nsswitch.conf,pango,passwd,pki,protocols,resolv.conf,rpc,services,ssl,texlive,Trolltech.conf,X11,xdg 55private-etc alternatives,ca-certificates,crypto-policies,dbus-1,dconf,firejail,fonts,gconf,groups,gtk-2.0,gtk-3.0,host.conf,hostname,hosts,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,login.defs,machine-id,mime.types,nsswitch.conf,pango,passwd,pki,protocols,resolv.conf,rpc,services,ssl,texlive,Trolltech.conf,X11,xdg
56private-tmp 56private-tmp
57 57
58dbus-user none 58dbus-user filter
59dbus-system none 59dbus-system none
diff --git a/etc/profile-m-z/marker.profile b/etc/profile-m-z/marker.profile
index 029d0183d..70e5c72cf 100644
--- a/etc/profile-m-z/marker.profile
+++ b/etc/profile-m-z/marker.profile
@@ -14,6 +14,8 @@ include globals.local
14noblacklist ${HOME}/.cache/marker 14noblacklist ${HOME}/.cache/marker
15noblacklist ${DOCUMENTS} 15noblacklist ${DOCUMENTS}
16 16
17include allow-python3.inc
18
17include disable-common.inc 19include disable-common.inc
18include disable-devel.inc 20include disable-devel.inc
19include disable-exec.inc 21include disable-exec.inc
@@ -48,7 +50,7 @@ seccomp.block-secondary
48shell none 50shell none
49tracelog 51tracelog
50 52
51private-bin marker 53private-bin marker,python3*
52private-cache 54private-cache
53private-dev 55private-dev
54private-etc alternatives,dconfgtk-3.0,fonts,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,pango,X11 56private-etc alternatives,dconfgtk-3.0,fonts,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,pango,X11
diff --git a/etc/profile-m-z/tcpdump.profile b/etc/profile-m-z/tcpdump.profile
index 7984702f3..6f863d7a1 100644
--- a/etc/profile-m-z/tcpdump.profile
+++ b/etc/profile-m-z/tcpdump.profile
@@ -8,6 +8,7 @@ include globals.local
8 8
9noblacklist /sbin 9noblacklist /sbin
10noblacklist /usr/sbin 10noblacklist /usr/sbin
11noblacklist ${PATH}/tcpdump
11 12
12include disable-common.inc 13include disable-common.inc
13include disable-devel.inc 14include disable-devel.inc
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/jailtest/jailtest.h b/src/jailtest/jailtest.h
index 10174cc9a..0c4883061 100644
--- a/src/jailtest/jailtest.h
+++ b/src/jailtest/jailtest.h
@@ -38,6 +38,10 @@ void access_destroy(void);
38void noexec_setup(void); 38void noexec_setup(void);
39void noexec_test(const char *msg); 39void noexec_test(const char *msg);
40 40
41// sysfiles.c
42void sysfiles_setup(const char *file);
43void sysfiles_test(void);
44
41// virtual.c 45// virtual.c
42void virtual_setup(const char *directory); 46void virtual_setup(const char *directory);
43void virtual_destroy(void); 47void virtual_destroy(void);
diff --git a/src/jailtest/main.c b/src/jailtest/main.c
index 850277bc5..3369dca39 100644
--- a/src/jailtest/main.c
+++ b/src/jailtest/main.c
@@ -114,8 +114,32 @@ int main(int argc, char **argv) {
114 virtual_setup("/bin"); 114 virtual_setup("/bin");
115 virtual_setup("/usr/share"); 115 virtual_setup("/usr/share");
116 virtual_setup(user_run_dir); 116 virtual_setup(user_run_dir);
117 117 // basic sysfiles
118 118 sysfiles_setup("/etc/shadow");
119 sysfiles_setup("/etc/gshadow");
120 sysfiles_setup("/usr/bin/mount");
121 sysfiles_setup("/usr/bin/su");
122 sysfiles_setup("/usr/bin/ksu");
123 sysfiles_setup("/usr/bin/sudo");
124 sysfiles_setup("/usr/bin/strace");
125 // X11
126 sysfiles_setup("/usr/bin/xev");
127 sysfiles_setup("/usr/bin/xinput");
128 // compilers
129 sysfiles_setup("/usr/bin/gcc");
130 sysfiles_setup("/usr/bin/clang");
131 // networking
132 sysfiles_setup("/usr/bin/dig");
133 sysfiles_setup("/usr/bin/nslookup");
134 sysfiles_setup("/usr/bin/resolvectl");
135 sysfiles_setup("/usr/bin/nc");
136 sysfiles_setup("/usr/bin/ncat");
137 sysfiles_setup("/usr/bin/nmap");
138 sysfiles_setup("/usr/sbin/tcpdump");
139 // terminals
140 sysfiles_setup("/usr/bin/gnome-terminal");
141 sysfiles_setup("/usr/bin/xfce4-terminal");
142 sysfiles_setup("/usr/bin/lxterminal");
119 143
120 // print processes 144 // print processes
121 pid_read(0); 145 pid_read(0);
@@ -145,6 +169,7 @@ int main(int argc, char **argv) {
145 noexec_test("/var/tmp"); 169 noexec_test("/var/tmp");
146 noexec_test(user_run_dir); 170 noexec_test(user_run_dir);
147 access_test(); 171 access_test();
172 sysfiles_test();
148 } 173 }
149 else { 174 else {
150 printf(" Error: I cannot join the process mount space\n"); 175 printf(" Error: I cannot join the process mount space\n");
diff --git a/src/jailtest/sysfiles.c b/src/jailtest/sysfiles.c
new file mode 100644
index 000000000..7e4709453
--- /dev/null
+++ b/src/jailtest/sysfiles.c
@@ -0,0 +1,88 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "jailtest.h"
21#include <dirent.h>
22#include <sys/wait.h>
23
24typedef struct {
25 char *tfile;
26} TestFile;
27
28#define MAX_TEST_FILES 32
29TestFile tf[MAX_TEST_FILES];
30static int files_cnt = 0;
31
32void sysfiles_setup(const char *file) {
33 // I am root!
34 assert(file);
35
36 if (files_cnt >= MAX_TEST_FILES) {
37 fprintf(stderr, "Error: maximum number of system test files exceded\n");
38 exit(1);
39 }
40
41 if (access(file, F_OK)) {
42 // no such file
43 return;
44 }
45
46
47 char *fname = strdup(file);
48 if (!fname)
49 errExit("strdup");
50
51 tf[files_cnt].tfile = fname;
52 files_cnt++;
53}
54
55void sysfiles_test(void) {
56 // I am root in sandbox mount namespace
57 assert(user_uid);
58 int i;
59
60 pid_t child = fork();
61 if (child == -1)
62 errExit("fork");
63
64 if (child == 0) { // child
65 // drop privileges
66 if (setgid(user_gid) != 0)
67 errExit("setgid");
68 if (setuid(user_uid) != 0)
69 errExit("setuid");
70
71 for (i = 0; i < files_cnt; i++) {
72 assert(tf[i].tfile);
73
74 // try to open the file for reading
75 FILE *fp = fopen(tf[i].tfile, "r");
76 if (fp) {
77
78 printf(" Warning: I can access %s\n", tf[i].tfile);
79 fclose(fp);
80 }
81 }
82 exit(0);
83 }
84
85 // wait for the child to finish
86 int status;
87 wait(&status);
88}
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",