aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2017-10-09 12:10:49 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2017-10-09 12:10:49 -0400
commitf451a2c426df261171ade60d12eb03a0bc140b8e (patch)
tree46916dbd49a0b28ccad9541914ca9c09a7025c85 /src
parentfixed mate-calc profile (diff)
downloadfirejail-f451a2c426df261171ade60d12eb03a0bc140b8e.tar.gz
firejail-f451a2c426df261171ade60d12eb03a0bc140b8e.tar.zst
firejail-f451a2c426df261171ade60d12eb03a0bc140b8e.zip
private-lib developments
Diffstat (limited to 'src')
-rw-r--r--src/firejail/fs_lib.c355
-rw-r--r--src/firejail/fs_lib2.c311
2 files changed, 499 insertions, 167 deletions
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c
index abd7cee1a..6826f906c 100644
--- a/src/firejail/fs_lib.c
+++ b/src/firejail/fs_lib.c
@@ -16,7 +16,7 @@
16 * You should have received a copy of the GNU General Public License along 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., 17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/ 19 */
20#include "firejail.h" 20#include "firejail.h"
21#include <sys/mount.h> 21#include <sys/mount.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
@@ -35,39 +35,79 @@ static const char * const lib_paths[] = {
35 LIBDIR, 35 LIBDIR,
36 "/usr/local/lib", 36 "/usr/local/lib",
37 NULL 37 NULL
38}; // Note: this array is duplicated in src/fldd/main.c 38}; // Note: this array is duplicated in src/fldd/main.c
39 39
40static void duplicate(const char *fname, const char *private_run_dir) { 40extern void fslib_install_stdc(void);
41 if (arg_debug) 41extern void fslib_install_system(void);
42 printf("copying %s to private %s\n", fname, private_run_dir); 42
43static int lib_cnt = 0;
44static int dir_cnt = 0;
45
46
47static char *build_dest_dir(const char *full_path) {
48 assert(full_path);
49 if (strstr(full_path, "/x86_64-linux-gnu/"))
50 return RUN_LIB_DIR "/x86_64-linux-gnu";
51 return RUN_LIB_DIR;
52}
43 53
44 // copy only root-owned files 54// copy fname in private_run_dir
55void fslib_duplicate(const char *full_path) {
56 assert(full_path);
45 struct stat s; 57 struct stat s;
46 if (stat(fname, &s) == 0 && s.st_uid == 0) 58 if (stat(full_path, &s) != 0 || s.st_uid != 0 || access(full_path, R_OK))
47 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", fname, private_run_dir); 59 return;
60
61 char *dest_dir = build_dest_dir(full_path);
62
63 // don't copy it if the file is already there
64 char *ptr = strrchr(full_path, '/');
65 if (!ptr)
66 return;
67 ptr++;
68 if (*ptr == '\0')
69 return;
70
71 char *name;
72 if (asprintf(&name, "%s/%s", dest_dir, ptr) == -1)
73 errExit("asprintf");
74 if (stat(name, &s) == 0) {
75 free(name);
76 return;
77 }
78 free(name);
79
80 if (arg_debug)
81 printf("copying %s to private %s\n", full_path, dest_dir);
82
83 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", full_path, dest_dir);
84 lib_cnt++;
48} 85}
49 86
50 87
51// requires full path for lib 88// requires full path for lib
52static void copy_libs(const char *lib, const char *private_run_dir, const char *output_file) { 89// it could be a library or an executable
90// lib is not copied, only libraries used by it
91void fslib_copy_libs(const char *full_path) {
53 // if library/executable does not exist or the user does not have read access to it 92 // if library/executable does not exist or the user does not have read access to it
54 // print a warning and exit the function. 93 // print a warning and exit the function.
55 if (access(lib, R_OK)) { 94 if (access(full_path, R_OK)) {
56 fwarning("cannot find %s for private-lib, skipping...\n", lib); 95 if (arg_debug)
96 printf("cannot find %s for private-lib, skipping...\n", full_path);
57 return; 97 return;
58 } 98 }
59 99
60 // create an empty RUN_LIB_FILE and allow the user to write to it 100 // create an empty RUN_LIB_FILE and allow the user to write to it
61 unlink(output_file); // in case is there 101 unlink(RUN_LIB_FILE); // in case is there
62 create_empty_file_as_root(output_file, 0644); 102 create_empty_file_as_root(RUN_LIB_FILE, 0644);
63 if (chown(output_file, getuid(), getgid())) 103 if (chown(RUN_LIB_FILE, getuid(), getgid()))
64 errExit("chown"); 104 errExit("chown");
65 105
66 // run fldd to extact the list of file 106 // run fldd to extact the list of files
67 sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, lib, output_file); 107 sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, full_path, RUN_LIB_FILE);
68 108
69 // open the list of libraries and install them on by one 109 // open the list of libraries and install them on by one
70 FILE *fp = fopen(output_file, "r"); 110 FILE *fp = fopen(RUN_LIB_FILE, "r");
71 if (!fp) 111 if (!fp)
72 errExit("fopen"); 112 errExit("fopen");
73 113
@@ -77,18 +117,30 @@ static void copy_libs(const char *lib, const char *private_run_dir, const char *
77 char *ptr = strchr(buf, '\n'); 117 char *ptr = strchr(buf, '\n');
78 if (ptr) 118 if (ptr)
79 *ptr = '\0'; 119 *ptr = '\0';
80 duplicate(buf, private_run_dir); 120 fslib_duplicate(buf);
81 } 121 }
82 fclose(fp); 122 fclose(fp);
83} 123}
84 124
85static void copy_directory(const char *full_path, const char *dir_name, const char *private_run_dir) {
86 char *dest;
87 if (asprintf(&dest, "%s/%s", private_run_dir, dir_name) == -1)
88 errExit("asprintf");
89 125
90 // do nothing if the directory is already there 126void fslib_copy_dir(const char *full_path) {
127 assert(full_path);
128 // do nothing if the directory does not exist or is not owned by root
91 struct stat s; 129 struct stat s;
130 if (stat(full_path, &s) != 0 || s.st_uid != 0 || !S_ISDIR(s.st_mode) || access(full_path, R_OK))
131 return;
132
133 char *dir_name = strrchr(full_path, '/');
134 assert(dir_name);
135 dir_name++;
136 assert(*dir_name != '\0');
137
138
139
140 // do nothing if the directory is already there
141 char *dest;
142 if (asprintf(&dest, "%s/%s", build_dest_dir(full_path), dir_name) == -1)
143 errExit("asprintf");
92 if (stat(dest, &s) == 0) { 144 if (stat(dest, &s) == 0) {
93 free(dest); 145 free(dest);
94 return; 146 return;
@@ -98,120 +150,84 @@ static void copy_directory(const char *full_path, const char *dir_name, const ch
98 mkdir_attr(dest, 0755, 0, 0); 150 mkdir_attr(dest, 0755, 0, 0);
99 151
100 if (mount(full_path, dest, NULL, MS_BIND|MS_REC, NULL) < 0 || 152 if (mount(full_path, dest, NULL, MS_BIND|MS_REC, NULL) < 0 ||
101 mount(NULL, dest, NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) 153 mount(NULL, dest, NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
102 errExit("mount bind"); 154 errExit("mount bind");
103 fs_logger2("clone", full_path); 155 fs_logger2("clone", full_path);
104 fs_logger2("mount", full_path); 156 fs_logger2("mount", full_path);
157 dir_cnt++;
105 free(dest); 158 free(dest);
106} 159}
107 160
161
108// return 1 if the file is valid 162// return 1 if the file is valid
109static char *valid_file(const char *lib) { 163static char *valid_file(const char *lib) {
110 // filename check 164 // filename check
111 int len = strlen(lib); 165 int len = strlen(lib);
112 if (strcspn(lib, "\\&!?\"'<>%^(){}[];,*") != (size_t)len || 166 if (strcspn(lib, "\\&!?\"'<>%^(){}[];,*") != (size_t)len ||
113 strstr(lib, "..")) { 167 strstr(lib, "..")) {
114 fprintf(stderr, "Error: \"%s\" is an invalid library\n", lib); 168 fprintf(stderr, "Error: \"%s\" is an invalid library\n", lib);
115 exit(1); 169 exit(1);
116 } 170 }
117 171
118 // find the library 172 // find the library
119 int i; 173 int i;
120 for (i = 0; lib_paths[i]; i++) { 174 for (i = 0; lib_paths[i]; i++) {
121 char *fname; 175 char *fname;
122 if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) 176 if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1)
123 errExit("asprintf"); 177 errExit("asprintf");
124 178
125 // existing file owned by root 179 // existing file owned by root, read access
126 struct stat s; 180 struct stat s;
127 if (stat(fname, &s) == 0 && s.st_uid == 0) { 181 if (stat(fname, &s) == 0 && s.st_uid == 0 && !access(fname, R_OK)) {
128 return fname; 182 return fname;
129 } 183 }
130 free(fname); 184 free(fname);
131 } 185 }
132 186
133 fwarning("%s library not found, skipping...\n", lib); 187 fwarning("%s library not found, skipping...\n", lib);
134 return NULL; 188 return NULL;
135} 189}
136 190
137// standard libc libraries based on Debian's libc6 package 191
138// selinux seems to be linked in most command line utilities 192static void mount_directories(void) {
139// locale (/usr/lib/locale) - without it, the program will default to "C" locale 193 if (arg_debug)
140typedef struct liblist_t { 194 printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR);
141 const char *name; 195
142 int len; 196 if (is_dir("/lib")) {
143} LibList; 197 if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 ||
144 198 mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
145static LibList libc_list[] = { 199 errExit("mount bind");
146// { "locale", 0 }, hardcoded! 200 fs_logger2("tmpfs", "/lib");
147 { "libselinux.so.", 0 }, 201 fs_logger("mount /lib");
148 { "ld-linux-x86-64.so.", 0 },
149 { "libanl.so.", 0 },
150 { "libc.so.", 0 },
151 { "libcidn.so.", 0 },
152 { "libcrypt.so.", 0 },
153 { "libdl.so.", 0 },
154 { "libm.so.", 0 },
155 { "libmemusage.so", 0 },
156 { "libmvec.so.", 0 },
157 { "libnsl.so.", 0 },
158 { "libnss_compat.so.", 0 },
159 { "libnss_dns.so.", 0 },
160 { "libnss_files.so.", 0 },
161 { "libnss_hesiod.so.", 0 },
162 { "libnss_nisplus.so.", 0 },
163 { "libnss_nis.so.", 0 },
164 { "libpthread.so.", 0 },
165 { "libresolv.so.", 0 },
166 { "librt.so.", 0 },
167 { "libthread_db.so.", 0 },
168 { "libutil.so.", 0 },
169 { NULL, 0}
170};
171
172static int find(const char *name) {
173 assert(name);
174
175 int i = 0;
176 while (libc_list[i].name) {
177 if (libc_list[i].len == 0)
178 libc_list[i].len = strlen(libc_list[i].name);
179 if (strncmp(name, libc_list[i].name, libc_list[i].len) == 0)
180 return 1;
181 i++;
182 } 202 }
183 return 0;
184}
185 203
186// compare the files in dirname against liblist above 204 if (is_dir("/lib64")) {
187static void walk_directory(const char *dirname, const char *destdir) { 205 if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 ||
188 assert(dirname); 206 mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
189 assert(destdir); 207 errExit("mount bind");
190 208 fs_logger2("tmpfs", "/lib64");
191 DIR *dir = opendir(dirname); 209 fs_logger("mount /lib64");
192 if (dir) { 210 }
193 struct dirent *entry; 211
194 while ((entry = readdir(dir)) != NULL) { 212 if (is_dir("/usr/lib")) {
195 if (strcmp(entry->d_name, ".") == 0) 213 if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 ||
196 continue; 214 mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
197 if (strcmp(entry->d_name, "..") == 0) 215 errExit("mount bind");
198 continue; 216 fs_logger2("tmpfs", "/usr/lib");
199 217 fs_logger("mount /usr/lib");
200 if (find(entry->d_name)) { 218 }
201 char *fname; 219
202 if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1) 220 // for amd64 only - we'll deal with i386 later
203 errExit("asprintf"); 221 if (is_dir("/lib32")) {
204 222 if (mount(RUN_RO_DIR, "/lib32", "none", MS_BIND, "mode=400,gid=0") < 0)
205 if (is_dir(fname)) 223 errExit("disable file");
206 copy_directory(fname, entry->d_name, RUN_LIB_DIR); 224 fs_logger("blacklist-nolog /lib32");
207 else 225 }
208 duplicate(fname, destdir); 226 if (is_dir("/libx32")) {
209 } 227 if (mount(RUN_RO_DIR, "/libx32", "none", MS_BIND, "mode=400,gid=0") < 0)
210 } 228 errExit("disable file");
211 closedir(dir); 229 fs_logger("blacklist-nolog /libx32");
212 } 230 }
213 else
214 fprintf(stderr, "Error: cannot open %s in order to set --private-lib\n", dirname);
215} 231}
216 232
217void fs_private_lib(void) { 233void fs_private_lib(void) {
@@ -219,39 +235,35 @@ void fs_private_lib(void) {
219 fwarning("private-lib feature is currently available only on amd64 platforms\n"); 235 fwarning("private-lib feature is currently available only on amd64 platforms\n");
220 return; 236 return;
221#endif 237#endif
222
223 char *private_list = cfg.lib_private_keep; 238 char *private_list = cfg.lib_private_keep;
224 if (arg_debug) 239 if (arg_debug)
225 printf("Starting private-lib processing: program %s, shell %s\n", 240 printf("Starting private-lib processing: program %s, shell %s\n",
226 (cfg.original_program_index > 0)? cfg.original_argv[cfg.original_program_index]: "none", 241 (cfg.original_program_index > 0)? cfg.original_argv[cfg.original_program_index]: "none",
227 (arg_shell_none)? "none": cfg.shell); 242 (arg_shell_none)? "none": cfg.shell);
228 243
229 // create /run/firejail/mnt/lib directory 244 // create /run/firejail/mnt/lib directory
230 mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); 245 mkdir_attr(RUN_LIB_DIR, 0755, 0, 0);
231 246
232 struct stat s; 247 // install standard C libraries
233 if (stat("/lib/x86_64-linux-gnu", &s) == 0) { 248 fslib_install_stdc();
234 mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); 249
235 walk_directory("/lib/x86_64-linux-gnu", RUN_LIB_DIR "/x86_64-linux-gnu"); 250 timetrace_start();
236 }
237 if (stat("/usr/lib/locale", &s) == 0)
238 copy_directory("/usr/lib/locale", "locale", RUN_LIB_DIR);
239 251
240 // copy the libs in the new lib directory for the main exe 252 // copy the libs in the new lib directory for the main exe
241 if (cfg.original_program_index > 0) 253 if (cfg.original_program_index > 0)
242 copy_libs(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR, RUN_LIB_FILE); 254 fslib_copy_libs(cfg.original_argv[cfg.original_program_index]);
243 255
244 // for the shell 256 // for the shell
245 if (!arg_shell_none) { 257 if (!arg_shell_none) {
246 copy_libs(cfg.shell, RUN_LIB_DIR, RUN_LIB_FILE); 258 fslib_copy_libs(cfg.shell);
247 // a shell is useless without ls command 259 // a shell is useless without ls command
248 copy_libs("/bin/ls", RUN_LIB_DIR, RUN_LIB_FILE); 260 fslib_copy_libs("/bin/ls");
249 } 261 }
250 262
251 // for the listed libs 263 // for the listed libs
252 if (private_list && *private_list != '\0') { 264 if (private_list && *private_list != '\0') {
253 if (arg_debug) 265 if (arg_debug)
254 printf("Copying extra files (%s) in the new lib directory:\n", private_list); 266 printf("Copying extra files (%s) in the new lib directory\n", private_list);
255 267
256 char *dlist = strdup(private_list); 268 char *dlist = strdup(private_list);
257 if (!dlist) 269 if (!dlist)
@@ -261,10 +273,10 @@ void fs_private_lib(void) {
261 char *lib = valid_file(ptr); 273 char *lib = valid_file(ptr);
262 if (lib) { 274 if (lib) {
263 if (is_dir(lib)) 275 if (is_dir(lib))
264 copy_directory(lib, ptr, RUN_LIB_DIR); 276 fslib_copy_dir(lib);
265 else { 277 else {
266 duplicate(lib, RUN_LIB_DIR); 278 fslib_duplicate(lib);
267 copy_libs(lib, RUN_LIB_DIR, RUN_LIB_FILE); 279 fslib_copy_libs(lib);
268 } 280 }
269 free(lib); 281 free(lib);
270 } 282 }
@@ -273,10 +285,10 @@ void fs_private_lib(void) {
273 lib = valid_file(ptr); 285 lib = valid_file(ptr);
274 if (lib) { 286 if (lib) {
275 if (is_dir(lib)) 287 if (is_dir(lib))
276 copy_directory(lib, ptr, RUN_LIB_DIR); 288 fslib_copy_dir(lib);
277 else { 289 else {
278 duplicate(lib, RUN_LIB_DIR); 290 fslib_duplicate(lib);
279 copy_libs(lib, RUN_LIB_DIR, RUN_LIB_FILE); 291 fslib_copy_libs(lib);
280 } 292 }
281 free(lib); 293 free(lib);
282 } 294 }
@@ -295,54 +307,63 @@ void fs_private_lib(void) {
295 char *ptr = strchr(buf, '\n'); 307 char *ptr = strchr(buf, '\n');
296 if (ptr) 308 if (ptr)
297 *ptr = '\0'; 309 *ptr = '\0';
298 copy_libs(buf, RUN_LIB_DIR, RUN_LIB_FILE); 310
311 // copy libraries for this program
312 fslib_copy_libs(buf);
313
314 // load program data from /usr/lib/program or from /usr/lib/x86_64-linux-gnu
315 ptr = strrchr(buf, '/');
316 if (ptr && *(ptr + 1) != '\0') {
317 ptr++;
318
319 // /usr/lib/program
320 char *name;
321 if (asprintf(&name, "/usr/lib/%s", ptr) == -1)
322 errExit("asprintf");
323 struct stat s;
324 if (is_dir(name)) {
325 fslib_copy_dir(name);
326 fslib_copy_libs(name);
327 }
328 free(name);
329
330 // /usr/lib/x86_linux-gnu - debian & frriends
331 if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr) == -1)
332 errExit("asprintf");
333 if (is_dir(name)) {
334 fslib_copy_dir(name);
335 fslib_copy_libs(name);
336 }
337 free(name);
338
339 // /usr/lib64 - CentOS, Fedora
340 if (asprintf(&name, "/usr/lib64/%s", ptr) == -1)
341 errExit("asprintf");
342 if (is_dir(name)) {
343 fslib_copy_dir(name);
344 fslib_copy_libs(name);
345 }
346 free(name);
347 }
299 } 348 }
300 } 349 }
301 fclose(fp); 350 fclose(fp);
302 } 351 }
352 if (!arg_quiet)
353 fprintf(stderr, "Program libraries installed in %0.2f ms\n", timetrace_end());
354
355 // install the reset of the system libraries
356 fslib_install_system();
357
358 if (!arg_quiet)
359 fprintf(stderr, "Installed %d libraries and %d directories\n", lib_cnt, dir_cnt);
303 360
304 // for our trace and tracelog libs 361 // for our trace and tracelog libs
305 if (arg_trace) 362 if (arg_trace)
306 duplicate(LIBDIR "/firejail/libtrace.so", RUN_LIB_DIR); 363 fslib_duplicate(LIBDIR "/firejail/libtrace.so");
307 else if (arg_tracelog) 364 else if (arg_tracelog)
308 duplicate(LIBDIR "/firejail/libtracelog.so", RUN_LIB_DIR); 365 fslib_duplicate(LIBDIR "/firejail/libtracelog.so");
309 366
310 if (arg_debug) 367 // mount lib filesystem
311 printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); 368 mount_directories();
312
313 if (is_dir("/lib")) {
314 if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 ||
315 mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
316 errExit("mount bind");
317 fs_logger2("tmpfs", "/lib");
318 fs_logger("mount /lib");
319 }
320
321 if (is_dir("/lib64")) {
322 if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 ||
323 mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
324 errExit("mount bind");
325 fs_logger2("tmpfs", "/lib64");
326 fs_logger("mount /lib64");
327 }
328
329 if (is_dir("/usr/lib")) {
330 if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 ||
331 mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
332 errExit("mount bind");
333 fs_logger2("tmpfs", "/usr/lib");
334 fs_logger("mount /usr/lib");
335 }
336
337 // for amd64 only - we'll deal with i386 later
338 if (is_dir("/lib32")) {
339 if (mount(RUN_RO_DIR, "/lib32", "none", MS_BIND, "mode=400,gid=0") < 0)
340 errExit("disable file");
341 fs_logger("blacklist-nolog /lib32");
342 }
343 if (is_dir("/libx32")) {
344 if (mount(RUN_RO_DIR, "/libx32", "none", MS_BIND, "mode=400,gid=0") < 0)
345 errExit("disable file");
346 fs_logger("blacklist-nolog /libx32");
347 }
348} 369}
diff --git a/src/firejail/fs_lib2.c b/src/firejail/fs_lib2.c
new file mode 100644
index 000000000..4c2c15ebd
--- /dev/null
+++ b/src/firejail/fs_lib2.c
@@ -0,0 +1,311 @@
1/*
2 * Copyright (C) 2017 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 "firejail.h"
21#include <dirent.h>
22#include <sys/stat.h>
23
24extern void fslib_duplicate(const char *full_path);
25extern void fslib_copy_libs(const char *full_path);
26extern void fslib_copy_dir(const char *full_path);
27
28//***************************************************************
29// Standard C library
30//***************************************************************
31// standard libc libraries based on Debian's libc6 package
32// selinux seems to be linked in most command line utilities
33// locale (/usr/lib/locale) - without it, the program will default to "C" locale
34typedef struct liblist_t {
35 const char *name;
36 int len;
37} LibList;
38
39static LibList libc_list[] = {
40 { "libselinux.so.", 0 },
41 { "ld-linux-x86-64.so.", 0 },
42 { "libanl.so.", 0 },
43 { "libc.so.", 0 },
44 { "libcidn.so.", 0 },
45 { "libcrypt.so.", 0 },
46 { "libdl.so.", 0 },
47 { "libm.so.", 0 },
48 { "libmemusage.so", 0 },
49 { "libmvec.so.", 0 },
50 { "libnsl.so.", 0 },
51 { "libnss_compat.so.", 0 },
52 { "libnss_dns.so.", 0 },
53 { "libnss_files.so.", 0 },
54 { "libnss_hesiod.so.", 0 },
55 { "libnss_nisplus.so.", 0 },
56 { "libnss_nis.so.", 0 },
57 { "libpthread.so.", 0 },
58 { "libresolv.so.", 0 },
59 { "librt.so.", 0 },
60 { "libthread_db.so.", 0 },
61 { "libutil.so.", 0 },
62 { NULL, 0}
63};
64
65static int find_libc_list(const char *name) {
66 assert(name);
67
68 int i = 0;
69 while (libc_list[i].name) {
70 if (libc_list[i].len == 0)
71 libc_list[i].len = strlen(libc_list[i].name);
72 if (strncmp(name, libc_list[i].name, libc_list[i].len) == 0)
73 return 1;
74 i++;
75 }
76 return 0;
77}
78
79// compare the files in dirname against liblist above
80static void stdc(const char *dirname) {
81 assert(dirname);
82
83 DIR *dir = opendir(dirname);
84 if (dir) {
85 struct dirent *entry;
86 while ((entry = readdir(dir)) != NULL) {
87 if (strcmp(entry->d_name, ".") == 0)
88 continue;
89 if (strcmp(entry->d_name, "..") == 0)
90 continue;
91
92 if (find_libc_list(entry->d_name)) {
93 char *fname;
94 if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1)
95 errExit("asprintf");
96
97 fslib_duplicate(fname);
98 }
99 }
100 closedir(dir);
101 }
102}
103
104void fslib_install_stdc(void) {
105 // install standard C libraries
106 struct stat s;
107 char *stdclib = "/lib64"; // CentOS, Fedora, Arch
108
109 if (stat("/lib/x86_64-linux-gnu", &s) == 0) { // Debian & friends
110 mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0);
111 stdclib = "/lib/x86_64-linux-gnu";
112 }
113
114 timetrace_start();
115 stdc(stdclib);
116
117 // install locale
118 if (stat("/usr/lib/locale", &s) == 0)
119 fslib_copy_dir("/usr/lib/locale");
120
121 if (!arg_quiet)
122 fprintf(stderr, "Standard C library installed in %0.2f ms\n", timetrace_end());
123}
124
125void fslib_install_locale(void);
126
127
128//***************************************************************
129// various system libraries
130//***************************************************************
131
132// look for library in the new filesystem, and install one or two more directories, dir1 and dir2
133typedef struct syslib_t {
134 const char *library; // look in the system for this library
135 int len; // length of library string, 0 by default
136 int found; // library found, 0 by default
137 const char *dir1; // directory to install
138 const char *dir2; // directory to install
139 const char *message; // message to print on the screen
140} SysLib;
141
142SysLib syslibs[] = {
143#if 0
144 {
145 "", // library
146 0, 0, // len and found flag
147 "", // dir1
148 "", // dir2
149 "" // message
150 },
151#endif
152 { // pixmaps - libraries used by GTK to display application menu icons
153 "libgdk_pixbuf-2.0", // library
154 0, 0, // len and found flag
155 "gdk-pixbuf-2.0", // dir1
156 "", // dir2
157 "GdkPixbuf" // message
158 },
159 { // GTK2
160 "libgtk-x11-2.0", // library
161 0, 0, // len and found flag
162 "gtk-2.0", // dir1
163 "libgtk2.0-0", // dir2
164 "GTK2" // message
165 },
166 { // GTK3
167 "libgtk-3", // library
168 0, 0, // len and found flag
169 "gtk-3.0", // dir1
170 "libgtk-3-0", // dir2
171 "GTK3" // message
172 },
173 { // Pango - text internationalization, found on older GTK2-based systems
174 "libpango", // library
175 0, 0, // len and found flag
176 "pango", // dir1
177 "", // dir2
178 "Pango" // message
179 },
180 { // Library for handling GObject introspection data on GTK systems
181 "libgirepository-1.0", // library
182 0, 0, // len and found flag
183 "girepository-1.0", // dir1
184 "", // dir2
185 "GIRepository" // message
186 },
187 { // Enchant speller
188 "libenchant.so.", // library
189 0, 0, // len and found flag
190 "enchant", // dir1
191 "", // dir2
192 "Enchant (speller)" // message
193 },
194 {
195 "libQt5", // library
196 0, 0, // len and found flag
197 "qt5", // dir1
198 "gdk-pixbuf-2.0", // dir2
199 "Qt5, GdkPixbuf" // message
200 },
201 {
202 "libQtCore", // library
203 0, 0, // len and found flag
204 "qt4", // dir1
205 "gdk-pixbuf-2.0", // dir2
206 "Qt4" // message
207 },
208
209 { // NULL terminated list
210 NULL, // library
211 0, 0, // len and found flag
212 "", // dir1
213 "", // dir2
214 "" // message
215 }
216};
217
218void fslib_install_system(void) {
219 // look for installed libraries
220 DIR *dir = opendir(RUN_LIB_DIR "/x86_64-linux-gnu");
221 if (!dir)
222 dir = opendir(RUN_LIB_DIR);
223
224 if (dir) {
225 struct dirent *entry;
226 while ((entry = readdir(dir)) != NULL) {
227 if (strcmp(entry->d_name, ".") == 0)
228 continue;
229 if (strcmp(entry->d_name, "..") == 0)
230 continue;
231
232 SysLib *ptr = &syslibs[0];
233 while (ptr->library) {
234 if (ptr->len == 0)
235 ptr->len = strlen(ptr->library);
236
237 if (strncmp(entry->d_name, ptr->library, ptr->len) == 0) {
238 ptr->found = 1;
239 break;
240 }
241
242 ptr++;
243 }
244
245 }
246 closedir(dir);
247 }
248 else
249 assert(0);
250
251 // install required directories
252 SysLib *ptr = &syslibs[0];
253 while (ptr->library) {
254 if (ptr->found) {
255 assert(*ptr->message != '\0');
256 timetrace_start();
257
258 // bring in all libraries
259 assert(ptr->dir1);
260 char *name;
261 // Debian & friends
262 if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir1) == -1)
263 errExit("asprintf");
264 if (access(name, R_OK) == 0) {
265 fslib_copy_libs(name);
266 fslib_copy_dir(name);
267 }
268 else {
269 free(name);
270 // CentOS, Fedora, Arch
271 if (asprintf(&name, "/usr/lib64/%s", ptr->dir1) == -1)
272 errExit("asprintf");
273 if (access(name, R_OK) == 0) {
274 fslib_copy_libs(name);
275 fslib_copy_dir(name);
276 }
277 }
278 free(name);
279
280 if (*ptr->dir2 != '\0') {
281 // Debian & friends
282 if (asprintf(&name, "/usr/lib/x86_64-linux-gnu/%s", ptr->dir2) == -1)
283 errExit("asprintf");
284 if (access(name, R_OK) == 0) {
285 fslib_copy_libs(name);
286 fslib_copy_dir(name);
287 }
288 else {
289 free(name);
290 // CentOS, Fedora, Arch
291 if (asprintf(&name, "/usr/lib64/%s", ptr->dir2) == -1)
292 errExit("asprintf");
293 if (access(name, R_OK) == 0) {
294 fslib_copy_libs(name);
295 fslib_copy_dir(name);
296 }
297 }
298 free(name);
299 }
300
301 if (!arg_quiet)
302 fprintf(stderr, "%s installed in %0.2f ms\n", ptr->message, timetrace_end());
303 }
304 ptr++;
305 }
306}
307
308
309
310
311