diff --git a/Makefile.in b/Makefile.in index 34a9eb856..6d8bf5f72 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,6 +1,6 @@ all: apps man filters MYLIBS = src/lib -APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy +APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy src/fldd MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 SECCOMP_FILTERS = seccomp seccomp.i386 seccomp.amd64 @@ -96,6 +96,7 @@ endif install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/. install -c -m 0755 src/fcopy/fcopy $(DESTDIR)/$(libdir)/firejail/. + install -c -m 0755 src/fldd/fldd $(DESTDIR)/$(libdir)/firejail/. ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/. install -c -m 0644 seccomp $(DESTDIR)/$(libdir)/firejail/. diff --git a/README b/README index 13692aed7..45b4c1833 100644 --- a/README +++ b/README @@ -36,6 +36,7 @@ Committers - Fred-Barclay (https://github.com/Fred-Barclay) - Reiner Herrmann (https://github.com/reinerh) - startx2017 (https://github.com/startx2017) - 0.9.38-LTS and *bugfixes branches maintainer +- Topi Miettinen (https://github.com/topimiettinen) - netblue30 (netblue30@yahoo.com) @@ -462,6 +463,8 @@ Topi Miettinen (https://github.com/topimiettinen) - improve mount handling, fix /run/user handling - /proc/sys can be nosuid,noexec,nodev - seccomp default list update + - improve loading of seccomp filter and memory-deny-write-execute feature + - private-lib feature valoq (https://github.com/valoq) - lots of profile fixes - added support for /srv in --whitelist feature diff --git a/configure b/configure index f8a606f88..3dda0918e 100755 --- a/configure +++ b/configure @@ -676,6 +676,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -763,6 +764,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1015,6 +1017,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1152,7 +1163,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1305,6 +1316,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -3811,7 +3823,7 @@ if test "$prefix" = /usr; then sysconfdir="/etc" fi -ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile" +ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -4532,6 +4544,7 @@ do "src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;; "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;; "src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;; + "src/fldd/Makefile") CONFIG_FILES="$CONFIG_FILES src/fldd/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.ac b/configure.ac index 7f9b12d97..09fc3f587 100644 --- a/configure.ac +++ b/configure.ac @@ -177,7 +177,7 @@ fi AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \ src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \ -src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile) +src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile) echo echo "Configuration options:" diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index dc903962b..19edb40a0 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -49,6 +49,7 @@ #define RUN_BIN_DIR "/run/firejail/mnt/bin" #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" #define RUN_LIB_DIR "/run/firejail/mnt/lib" +#define RUN_LIB_FILE "/run/firejail/mnt/libfiles" #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter @@ -739,6 +740,7 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, #define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") #define PATH_FCOPY (LIBDIR "/firejail/fcopy") #define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" +#define PATH_FLDD (LIBDIR "/firejail/fldd") // bitmapped filters for sbox_run #define SBOX_ROOT (1 << 0) // run the sandbox as root diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index d86588792..576b4a0df 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c @@ -18,156 +18,60 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "firejail.h" -#include -#include -#include #include #include #include #include -#ifdef __LP64__ -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Phdr Elf64_Phdr -#define Elf_Shdr Elf64_Shdr -#define Elf_Dyn Elf64_Dyn -#else -#define Elf_Ehdr Elf32_Ehdr -#define Elf_Phdr Elf32_Phdr -#define Elf_Shdr Elf32_Shdr -#define Elf_Dyn Elf32_Dyn -#endif - -static const char * const lib_paths[] = { - "/lib", - "/lib/x86_64-linux-gnu", - "/lib64", - "/usr/lib", - "/usr/lib/x86_64-linux-gnu", - LIBDIR, - "/usr/local/lib", - NULL -}; - -static void copy_libs_for_lib(const char *lib, const char *private_run_dir); - static void duplicate(const char *fname, const char *private_run_dir) { if (arg_debug) printf("copying %s to private %s\n", fname, private_run_dir); sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", fname, private_run_dir); } -static void copy_libs_for_exe(const char *exe, const char *private_run_dir) { - if (arg_debug) - printf("copy libs for %s\n", exe); - int f; - f = open(exe, O_RDONLY); - if (f < 0) - return; - struct stat s; - char *base = NULL; - if (fstat(f, &s) == -1) - goto error_close; - base = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, f, 0); - if (base == MAP_FAILED) - goto error_close; +static void copy_libs(const char *exe, const char *dir, const char *file) { + // create an empty RUN_LIB_FILE and allow the user to write to it + unlink(file); // in case is there + create_empty_file_as_root(file, 0644); + if (chown(file, getuid(), getgid())) + errExit("chown"); + + // run fldd to extact the list of file + sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, exe, file); + + // open the list of libraries and install them on by one + FILE *fp = fopen(file, "r"); + if (!fp) + errExit("fopen"); - Elf_Ehdr *ebuf = (Elf_Ehdr *)base; - if (strncmp((const char *)ebuf->e_ident, ELFMAG, SELFMAG) != 0) - goto close; - - Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); - while (ebuf->e_phnum-- > 0) { - switch (pbuf->p_type) { - case PT_INTERP: - // dynamic loader ld-linux.so - duplicate(base + pbuf->p_offset, private_run_dir); - break; - } - pbuf++; +#define MAXBUF 4096 + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + // remove \n + char *ptr = strchr(buf, '\n'); + if (ptr) + *ptr = '\0'; + duplicate(buf, dir); } - - Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); - - // Find strings section - char *strbase = NULL; - int sections = ebuf->e_shnum; - while (sections-- > 0) { - if (sbuf->sh_type == SHT_STRTAB) { - strbase = base + sbuf->sh_offset; - break; - } - sbuf++; - } - if (strbase == NULL) - goto error_close; - - // Find dynamic section - sections = ebuf->e_shnum; - while (sections-- > 0) { - if (sbuf->sh_type == SHT_DYNAMIC) { - // Find DT_NEEDED tags - Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); - while (sbuf->sh_size >= sizeof(*dbuf)) { - if (dbuf->d_tag == DT_NEEDED) { - const char *lib = strbase + dbuf->d_un.d_ptr; - copy_libs_for_lib(lib, private_run_dir); - } - sbuf->sh_size -= sizeof(*dbuf); - dbuf++; - } - } - sbuf++; - } - goto close; - - error_close: - perror("copy libs"); - close: - if (base) - munmap(base, s.st_size); - close(f); + fclose(fp); } -static void copy_libs_for_lib(const char *lib, const char *private_run_dir) { - int i; - for (i = 0; lib_paths[i]; i++) { - char *fname; - if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) - errExit("asprintf"); - if (access(fname, R_OK) == 0) { - char *dst; - if (asprintf(&dst, "%s/%s", private_run_dir, lib) == -1) - errExit("asprintf"); - - if (access(dst, R_OK) != 0) { - duplicate(fname, private_run_dir); - // libs may need other libs - copy_libs_for_exe(fname, private_run_dir); - } - free(dst); - free(fname); - return; - } - free(fname); - } - errExit("library not found"); -} void fs_private_lib(void) { - char *private_list = cfg.lib_private_keep; +// char *private_list = cfg.lib_private_keep; // create /run/firejail/mnt/lib directory mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); // copy the libs in the new lib directory for the main exe if (cfg.original_program_index > 0) - copy_libs_for_exe(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR); + copy_libs(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR, RUN_LIB_FILE); // for the shell if (!arg_shell_none) - copy_libs_for_exe(cfg.shell, RUN_LIB_DIR); + copy_libs(cfg.shell, RUN_LIB_DIR, RUN_LIB_FILE); +#if 0 // TODO - work in progress // for the listed libs if (private_list && *private_list != '\0') { if (arg_debug) @@ -185,6 +89,7 @@ void fs_private_lib(void) { free(dlist); fs_logger_print(); } +#endif // for our trace and tracelog libs if (arg_trace) @@ -194,14 +99,17 @@ void fs_private_lib(void) { if (arg_debug) printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); + if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) errExit("mount bind"); fs_logger("mount /lib"); + if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 || mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) errExit("mount bind"); fs_logger("mount /lib64"); + if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) errExit("mount bind");