From 63e177af7278012d7064d4e1695d3a500f51c9eb Mon Sep 17 00:00:00 2001 From: netblue30 Date: Wed, 4 Oct 2017 08:29:31 -0400 Subject: private-lib: add std C library and locale by default --- src/firejail/fs_lib.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/fldd/main.c | 26 +++++++-------- 2 files changed, 97 insertions(+), 18 deletions(-) diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index cdfd4a6e2..abd7cee1a 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c @@ -22,6 +22,7 @@ #include #include #include +#include #define MAXBUF 4096 @@ -133,6 +134,85 @@ static char *valid_file(const char *lib) { return NULL; } +// standard libc libraries based on Debian's libc6 package +// selinux seems to be linked in most command line utilities +// locale (/usr/lib/locale) - without it, the program will default to "C" locale +typedef struct liblist_t { + const char *name; + int len; +} LibList; + +static LibList libc_list[] = { +// { "locale", 0 }, hardcoded! + { "libselinux.so.", 0 }, + { "ld-linux-x86-64.so.", 0 }, + { "libanl.so.", 0 }, + { "libc.so.", 0 }, + { "libcidn.so.", 0 }, + { "libcrypt.so.", 0 }, + { "libdl.so.", 0 }, + { "libm.so.", 0 }, + { "libmemusage.so", 0 }, + { "libmvec.so.", 0 }, + { "libnsl.so.", 0 }, + { "libnss_compat.so.", 0 }, + { "libnss_dns.so.", 0 }, + { "libnss_files.so.", 0 }, + { "libnss_hesiod.so.", 0 }, + { "libnss_nisplus.so.", 0 }, + { "libnss_nis.so.", 0 }, + { "libpthread.so.", 0 }, + { "libresolv.so.", 0 }, + { "librt.so.", 0 }, + { "libthread_db.so.", 0 }, + { "libutil.so.", 0 }, + { NULL, 0} +}; + +static int find(const char *name) { + assert(name); + + int i = 0; + while (libc_list[i].name) { + if (libc_list[i].len == 0) + libc_list[i].len = strlen(libc_list[i].name); + if (strncmp(name, libc_list[i].name, libc_list[i].len) == 0) + return 1; + i++; + } + return 0; +} + +// compare the files in dirname against liblist above +static void walk_directory(const char *dirname, const char *destdir) { + assert(dirname); + assert(destdir); + + DIR *dir = opendir(dirname); + if (dir) { + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0) + continue; + if (strcmp(entry->d_name, "..") == 0) + continue; + + if (find(entry->d_name)) { + char *fname; + if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1) + errExit("asprintf"); + + if (is_dir(fname)) + copy_directory(fname, entry->d_name, RUN_LIB_DIR); + else + duplicate(fname, destdir); + } + } + closedir(dir); + } + else + fprintf(stderr, "Error: cannot open %s in order to set --private-lib\n", dirname); +} void fs_private_lib(void) { #ifndef __x86_64__ @@ -149,14 +229,13 @@ void fs_private_lib(void) { // create /run/firejail/mnt/lib directory mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); - // fix libselinux linking problem on Debian stretch; the library is - // linked in most basic command utilities (ls, cp, find etc.), and it - // seems to have a path hardlinked under /lib/x86_64-linux-gnu directory. struct stat s; - if (stat("/lib/x86_64-linux-gnu/libselinux.so.1", &s) == 0) { + if (stat("/lib/x86_64-linux-gnu", &s) == 0) { mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); - duplicate("/lib/x86_64-linux-gnu/libselinux.so.1", RUN_LIB_DIR "/x86_64-linux-gnu"); + walk_directory("/lib/x86_64-linux-gnu", RUN_LIB_DIR "/x86_64-linux-gnu"); } + if (stat("/usr/lib/locale", &s) == 0) + copy_directory("/usr/lib/locale", "locale", RUN_LIB_DIR); // copy the libs in the new lib directory for the main exe if (cfg.original_program_index > 0) diff --git a/src/fldd/main.c b/src/fldd/main.c index 5fda45266..6127a4a87 100644 --- a/src/fldd/main.c +++ b/src/fldd/main.c @@ -94,12 +94,12 @@ static void storage_print(Storage *ptr, int fd) { } } -static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name) { +static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name, const char *exe) { bool r; r = (ptr >= base && ptr <= end); if (!r && !arg_quiet) - fprintf(stderr, "Warning: fldd: bad pointer %s\n", name); + fprintf(stderr, "Warning: fldd: bad pointer %s for %s\n", name, exe); return r; } @@ -130,11 +130,11 @@ static void copy_libs_for_exe(const char *exe) { } Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); - while (ebuf->e_phnum-- > 0 && ptr_ok(pbuf, base, end, "pbuf")) { + while (ebuf->e_phnum-- > 0 && ptr_ok(pbuf, base, end, "pbuf", exe)) { switch (pbuf->p_type) { case PT_INTERP: // dynamic loader ld-linux.so - if (!ptr_ok(base + pbuf->p_offset, base, end, "base + pbuf->p_offset")) + if (!ptr_ok(base + pbuf->p_offset, base, end, "base + pbuf->p_offset", exe)) goto close; storage_add(&libs, base + pbuf->p_offset); @@ -144,16 +144,16 @@ static void copy_libs_for_exe(const char *exe) { } Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); - if (!ptr_ok(sbuf, base, end, "sbuf")) + if (!ptr_ok(sbuf, base, end, "sbuf", exe)) goto close; // Find strings section char *strbase = NULL; int sections = ebuf->e_shnum; - while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) { + while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf", exe)) { if (sbuf->sh_type == SHT_STRTAB) { strbase = base + sbuf->sh_offset; - if (!ptr_ok(strbase, base, end, "strbase")) + if (!ptr_ok(strbase, base, end, "strbase", exe)) goto close; break; } @@ -164,7 +164,7 @@ static void copy_libs_for_exe(const char *exe) { // Find dynamic section sections = ebuf->e_shnum; - while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) { + while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf", exe)) { // TODO: running fldd on large gui programs (fldd /usr/bin/transmission-qt) // crash on accessing memory location sbuf->sh_type if sbuf->sh_type in the previous section was 0 (SHT_NULL) // for now we just exit the while loop - this is probably incorrect @@ -173,14 +173,14 @@ static void copy_libs_for_exe(const char *exe) { break; if (sbuf->sh_type == SHT_DYNAMIC) { Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); - if (!ptr_ok(dbuf, base, end, "dbuf")) + if (!ptr_ok(dbuf, base, end, "dbuf", exe)) goto close; // Find DT_RPATH/DT_RUNPATH tags first unsigned long size = sbuf->sh_size; - while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) { + while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf", exe)) { if (dbuf->d_tag == DT_RPATH || dbuf->d_tag == DT_RUNPATH) { const char *searchpath = strbase + dbuf->d_un.d_ptr; - if (!ptr_ok(searchpath, base, end, "searchpath")) + if (!ptr_ok(searchpath, base, end, "searchpath", exe)) goto close; storage_add(&lib_paths, searchpath); } @@ -190,10 +190,10 @@ static void copy_libs_for_exe(const char *exe) { // Find DT_NEEDED tags dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); size = sbuf->sh_size; - while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) { + while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf", exe)) { if (dbuf->d_tag == DT_NEEDED) { const char *lib = strbase + dbuf->d_un.d_ptr; - if (!ptr_ok(lib, base, end, "lib")) + if (!ptr_ok(lib, base, end, "lib", exe)) goto close; copy_libs_for_lib(lib); } -- cgit v1.2.3-54-g00ecf