diff options
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | README | 3 | ||||
-rwxr-xr-x | configure | 17 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | etc/firejail.config | 3 | ||||
-rw-r--r-- | src/firejail/checkcfg.c | 8 | ||||
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/fs_lib.c | 196 | ||||
-rw-r--r-- | src/firejail/main.c | 20 | ||||
-rw-r--r-- | src/firejail/profile.c | 18 |
10 files changed, 151 insertions, 122 deletions
diff --git a/Makefile.in b/Makefile.in index 34a9eb856..6d8bf5f72 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,6 +1,6 @@ | |||
1 | all: apps man filters | 1 | all: apps man filters |
2 | MYLIBS = src/lib | 2 | MYLIBS = src/lib |
3 | APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy | 3 | APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy src/fldd |
4 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 | 4 | MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 |
5 | SECCOMP_FILTERS = seccomp seccomp.i386 seccomp.amd64 | 5 | SECCOMP_FILTERS = seccomp seccomp.i386 seccomp.amd64 |
6 | 6 | ||
@@ -96,6 +96,7 @@ endif | |||
96 | install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. | 96 | install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. |
97 | install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/. | 97 | install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/. |
98 | install -c -m 0755 src/fcopy/fcopy $(DESTDIR)/$(libdir)/firejail/. | 98 | install -c -m 0755 src/fcopy/fcopy $(DESTDIR)/$(libdir)/firejail/. |
99 | install -c -m 0755 src/fldd/fldd $(DESTDIR)/$(libdir)/firejail/. | ||
99 | ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) | 100 | ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) |
100 | install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/. | 101 | install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/. |
101 | install -c -m 0644 seccomp $(DESTDIR)/$(libdir)/firejail/. | 102 | install -c -m 0644 seccomp $(DESTDIR)/$(libdir)/firejail/. |
@@ -36,6 +36,7 @@ Committers | |||
36 | - Fred-Barclay (https://github.com/Fred-Barclay) | 36 | - Fred-Barclay (https://github.com/Fred-Barclay) |
37 | - Reiner Herrmann (https://github.com/reinerh) | 37 | - Reiner Herrmann (https://github.com/reinerh) |
38 | - startx2017 (https://github.com/startx2017) - 0.9.38-LTS and *bugfixes branches maintainer | 38 | - startx2017 (https://github.com/startx2017) - 0.9.38-LTS and *bugfixes branches maintainer |
39 | - Topi Miettinen (https://github.com/topimiettinen) | ||
39 | - netblue30 (netblue30@yahoo.com) | 40 | - netblue30 (netblue30@yahoo.com) |
40 | 41 | ||
41 | 42 | ||
@@ -462,6 +463,8 @@ Topi Miettinen (https://github.com/topimiettinen) | |||
462 | - improve mount handling, fix /run/user handling | 463 | - improve mount handling, fix /run/user handling |
463 | - /proc/sys can be nosuid,noexec,nodev | 464 | - /proc/sys can be nosuid,noexec,nodev |
464 | - seccomp default list update | 465 | - seccomp default list update |
466 | - improve loading of seccomp filter and memory-deny-write-execute feature | ||
467 | - private-lib feature | ||
465 | valoq (https://github.com/valoq) | 468 | valoq (https://github.com/valoq) |
466 | - lots of profile fixes | 469 | - lots of profile fixes |
467 | - added support for /srv in --whitelist feature | 470 | - added support for /srv in --whitelist feature |
@@ -676,6 +676,7 @@ infodir | |||
676 | docdir | 676 | docdir |
677 | oldincludedir | 677 | oldincludedir |
678 | includedir | 678 | includedir |
679 | runstatedir | ||
679 | localstatedir | 680 | localstatedir |
680 | sharedstatedir | 681 | sharedstatedir |
681 | sysconfdir | 682 | sysconfdir |
@@ -763,6 +764,7 @@ datadir='${datarootdir}' | |||
763 | sysconfdir='${prefix}/etc' | 764 | sysconfdir='${prefix}/etc' |
764 | sharedstatedir='${prefix}/com' | 765 | sharedstatedir='${prefix}/com' |
765 | localstatedir='${prefix}/var' | 766 | localstatedir='${prefix}/var' |
767 | runstatedir='${localstatedir}/run' | ||
766 | includedir='${prefix}/include' | 768 | includedir='${prefix}/include' |
767 | oldincludedir='/usr/include' | 769 | oldincludedir='/usr/include' |
768 | docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' | 770 | docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' |
@@ -1015,6 +1017,15 @@ do | |||
1015 | | -silent | --silent | --silen | --sile | --sil) | 1017 | | -silent | --silent | --silen | --sile | --sil) |
1016 | silent=yes ;; | 1018 | silent=yes ;; |
1017 | 1019 | ||
1020 | -runstatedir | --runstatedir | --runstatedi | --runstated \ | ||
1021 | | --runstate | --runstat | --runsta | --runst | --runs \ | ||
1022 | | --run | --ru | --r) | ||
1023 | ac_prev=runstatedir ;; | ||
1024 | -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | ||
1025 | | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | ||
1026 | | --run=* | --ru=* | --r=*) | ||
1027 | runstatedir=$ac_optarg ;; | ||
1028 | |||
1018 | -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) | 1029 | -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) |
1019 | ac_prev=sbindir ;; | 1030 | ac_prev=sbindir ;; |
1020 | -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | 1031 | -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ |
@@ -1152,7 +1163,7 @@ fi | |||
1152 | for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ | 1163 | for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ |
1153 | datadir sysconfdir sharedstatedir localstatedir includedir \ | 1164 | datadir sysconfdir sharedstatedir localstatedir includedir \ |
1154 | oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ | 1165 | oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ |
1155 | libdir localedir mandir | 1166 | libdir localedir mandir runstatedir |
1156 | do | 1167 | do |
1157 | eval ac_val=\$$ac_var | 1168 | eval ac_val=\$$ac_var |
1158 | # Remove trailing slashes. | 1169 | # Remove trailing slashes. |
@@ -1305,6 +1316,7 @@ Fine tuning of the installation directories: | |||
1305 | --sysconfdir=DIR read-only single-machine data [PREFIX/etc] | 1316 | --sysconfdir=DIR read-only single-machine data [PREFIX/etc] |
1306 | --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] | 1317 | --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] |
1307 | --localstatedir=DIR modifiable single-machine data [PREFIX/var] | 1318 | --localstatedir=DIR modifiable single-machine data [PREFIX/var] |
1319 | --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] | ||
1308 | --libdir=DIR object code libraries [EPREFIX/lib] | 1320 | --libdir=DIR object code libraries [EPREFIX/lib] |
1309 | --includedir=DIR C header files [PREFIX/include] | 1321 | --includedir=DIR C header files [PREFIX/include] |
1310 | --oldincludedir=DIR C header files for non-gcc [/usr/include] | 1322 | --oldincludedir=DIR C header files for non-gcc [/usr/include] |
@@ -3811,7 +3823,7 @@ if test "$prefix" = /usr; then | |||
3811 | sysconfdir="/etc" | 3823 | sysconfdir="/etc" |
3812 | fi | 3824 | fi |
3813 | 3825 | ||
3814 | 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" | 3826 | 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" |
3815 | 3827 | ||
3816 | cat >confcache <<\_ACEOF | 3828 | cat >confcache <<\_ACEOF |
3817 | # This file is a shell script that caches the results of configure | 3829 | # This file is a shell script that caches the results of configure |
@@ -4532,6 +4544,7 @@ do | |||
4532 | "src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;; | 4544 | "src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;; |
4533 | "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;; | 4545 | "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;; |
4534 | "src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;; | 4546 | "src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;; |
4547 | "src/fldd/Makefile") CONFIG_FILES="$CONFIG_FILES src/fldd/Makefile" ;; | ||
4535 | 4548 | ||
4536 | *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; | 4549 | *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; |
4537 | esac | 4550 | esac |
diff --git a/configure.ac b/configure.ac index 7f9b12d97..09fc3f587 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -177,7 +177,7 @@ fi | |||
177 | 177 | ||
178 | AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \ | 178 | AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \ |
179 | src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \ | 179 | src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \ |
180 | src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile) | 180 | src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile) |
181 | 181 | ||
182 | echo | 182 | echo |
183 | echo "Configuration options:" | 183 | echo "Configuration options:" |
diff --git a/etc/firejail.config b/etc/firejail.config index 82847ea37..b597ed603 100644 --- a/etc/firejail.config +++ b/etc/firejail.config | |||
@@ -63,6 +63,9 @@ | |||
63 | # Enable or disable private-home feature, default enabled | 63 | # Enable or disable private-home feature, default enabled |
64 | # private-home yes | 64 | # private-home yes |
65 | 65 | ||
66 | # Enable or disable private-lib feature, default enabled | ||
67 | # private-lib yes | ||
68 | |||
66 | # Enable --quiet as default every time the sandbox is started. Default disabled. | 69 | # Enable --quiet as default every time the sandbox is started. Default disabled. |
67 | # quiet-by-default no | 70 | # quiet-by-default no |
68 | 71 | ||
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index 50a96fc7a..7f371b299 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -324,6 +324,14 @@ int checkcfg(int val) { | |||
324 | else | 324 | else |
325 | goto errout; | 325 | goto errout; |
326 | } | 326 | } |
327 | else if (strncmp(ptr, "private-lib ", 12) == 0) { | ||
328 | if (strcmp(ptr + 12, "yes") == 0) | ||
329 | cfg_val[CFG_PRIVATE_LIB] = 1; | ||
330 | else if (strcmp(ptr + 12, "no") == 0) | ||
331 | cfg_val[CFG_PRIVATE_LIB] = 0; | ||
332 | else | ||
333 | goto errout; | ||
334 | } | ||
327 | else if (strncmp(ptr, "chroot-desktop ", 15) == 0) { | 335 | else if (strncmp(ptr, "chroot-desktop ", 15) == 0) { |
328 | if (strcmp(ptr + 15, "yes") == 0) | 336 | if (strcmp(ptr + 15, "yes") == 0) |
329 | cfg_val[CFG_CHROOT_DESKTOP] = 1; | 337 | cfg_val[CFG_CHROOT_DESKTOP] = 1; |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index dc903962b..8e47a72d5 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -49,6 +49,7 @@ | |||
49 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" | 49 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" |
50 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" | 50 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" |
51 | #define RUN_LIB_DIR "/run/firejail/mnt/lib" | 51 | #define RUN_LIB_DIR "/run/firejail/mnt/lib" |
52 | #define RUN_LIB_FILE "/run/firejail/mnt/libfiles" | ||
52 | 53 | ||
53 | #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter | 54 | #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter |
54 | #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter | 55 | #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter |
@@ -707,6 +708,7 @@ enum { | |||
707 | CFG_JOIN, | 708 | CFG_JOIN, |
708 | CFG_ARP_PROBES, | 709 | CFG_ARP_PROBES, |
709 | CFG_XPRA_ATTACH, | 710 | CFG_XPRA_ATTACH, |
711 | CFG_PRIVATE_LIB, | ||
710 | CFG_MAX // this should always be the last entry | 712 | CFG_MAX // this should always be the last entry |
711 | }; | 713 | }; |
712 | extern char *xephyr_screen; | 714 | extern char *xephyr_screen; |
@@ -739,6 +741,7 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, | |||
739 | #define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") | 741 | #define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") |
740 | #define PATH_FCOPY (LIBDIR "/firejail/fcopy") | 742 | #define PATH_FCOPY (LIBDIR "/firejail/fcopy") |
741 | #define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" | 743 | #define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" |
744 | #define PATH_FLDD (LIBDIR "/firejail/fldd") | ||
742 | 745 | ||
743 | // bitmapped filters for sbox_run | 746 | // bitmapped filters for sbox_run |
744 | #define SBOX_ROOT (1 << 0) // run the sandbox as root | 747 | #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..94d87a151 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c | |||
@@ -18,26 +18,11 @@ | |||
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 <elf.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <sys/mman.h> | ||
24 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
25 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
26 | #include <sys/types.h> | 23 | #include <sys/types.h> |
27 | #include <unistd.h> | 24 | #include <unistd.h> |
28 | 25 | ||
29 | #ifdef __LP64__ | ||
30 | #define Elf_Ehdr Elf64_Ehdr | ||
31 | #define Elf_Phdr Elf64_Phdr | ||
32 | #define Elf_Shdr Elf64_Shdr | ||
33 | #define Elf_Dyn Elf64_Dyn | ||
34 | #else | ||
35 | #define Elf_Ehdr Elf32_Ehdr | ||
36 | #define Elf_Phdr Elf32_Phdr | ||
37 | #define Elf_Shdr Elf32_Shdr | ||
38 | #define Elf_Dyn Elf32_Dyn | ||
39 | #endif | ||
40 | |||
41 | static const char * const lib_paths[] = { | 26 | static const char * const lib_paths[] = { |
42 | "/lib", | 27 | "/lib", |
43 | "/lib/x86_64-linux-gnu", | 28 | "/lib/x86_64-linux-gnu", |
@@ -47,9 +32,9 @@ static const char * const lib_paths[] = { | |||
47 | LIBDIR, | 32 | LIBDIR, |
48 | "/usr/local/lib", | 33 | "/usr/local/lib", |
49 | NULL | 34 | NULL |
50 | }; | 35 | }; // Note: this array is duplicated in src/fldd/main.c |
51 | 36 | ||
52 | static void copy_libs_for_lib(const char *lib, const char *private_run_dir); | 37 | static void copy_libs(const char *exe, const char *dir, const char *file); |
53 | 38 | ||
54 | static void duplicate(const char *fname, const char *private_run_dir) { | 39 | static void duplicate(const char *fname, const char *private_run_dir) { |
55 | if (arg_debug) | 40 | if (arg_debug) |
@@ -57,116 +42,107 @@ static void duplicate(const char *fname, const char *private_run_dir) { | |||
57 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", fname, private_run_dir); | 42 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", fname, private_run_dir); |
58 | } | 43 | } |
59 | 44 | ||
60 | static void copy_libs_for_exe(const char *exe, const char *private_run_dir) { | 45 | |
61 | if (arg_debug) | 46 | // requires full path for exe |
62 | printf("copy libs for %s\n", exe); | 47 | static void copy_exe(const char *exe, const char *dir, const char *file) { |
63 | int f; | 48 | // if exe does not exist or the user does not have read access to it |
64 | f = open(exe, O_RDONLY); | 49 | // print a warning and exit the function. |
65 | if (f < 0) | 50 | if (access(exe, R_OK)) { |
51 | fwarning("cannot find %s executable for private-lib, skipping...\n", exe); | ||
66 | return; | 52 | return; |
67 | struct stat s; | ||
68 | char *base = NULL; | ||
69 | if (fstat(f, &s) == -1) | ||
70 | goto error_close; | ||
71 | base = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, f, 0); | ||
72 | if (base == MAP_FAILED) | ||
73 | goto error_close; | ||
74 | |||
75 | Elf_Ehdr *ebuf = (Elf_Ehdr *)base; | ||
76 | if (strncmp((const char *)ebuf->e_ident, ELFMAG, SELFMAG) != 0) | ||
77 | goto close; | ||
78 | |||
79 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); | ||
80 | while (ebuf->e_phnum-- > 0) { | ||
81 | switch (pbuf->p_type) { | ||
82 | case PT_INTERP: | ||
83 | // dynamic loader ld-linux.so | ||
84 | duplicate(base + pbuf->p_offset, private_run_dir); | ||
85 | break; | ||
86 | } | ||
87 | pbuf++; | ||
88 | } | 53 | } |
89 | 54 | ||
90 | Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); | 55 | copy_libs(exe, dir, file); |
56 | } | ||
91 | 57 | ||
92 | // Find strings section | 58 | // requires full path for lib |
93 | char *strbase = NULL; | 59 | static void copy_libs(const char *lib, const char *dir, const char *output_file) { |
94 | int sections = ebuf->e_shnum; | 60 | // create an empty RUN_LIB_FILE and allow the user to write to it |
95 | while (sections-- > 0) { | 61 | unlink(output_file); // in case is there |
96 | if (sbuf->sh_type == SHT_STRTAB) { | 62 | create_empty_file_as_root(output_file, 0644); |
97 | strbase = base + sbuf->sh_offset; | 63 | if (chown(output_file, getuid(), getgid())) |
98 | break; | 64 | errExit("chown"); |
99 | } | 65 | |
100 | sbuf++; | 66 | // run fldd to extact the list of file |
67 | sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, lib, output_file); | ||
68 | |||
69 | // open the list of libraries and install them on by one | ||
70 | FILE *fp = fopen(output_file, "r"); | ||
71 | if (!fp) | ||
72 | errExit("fopen"); | ||
73 | |||
74 | #define MAXBUF 4096 | ||
75 | char buf[MAXBUF]; | ||
76 | while (fgets(buf, MAXBUF, fp)) { | ||
77 | // remove \n | ||
78 | char *ptr = strchr(buf, '\n'); | ||
79 | if (ptr) | ||
80 | *ptr = '\0'; | ||
81 | duplicate(buf, dir); | ||
101 | } | 82 | } |
102 | if (strbase == NULL) | 83 | fclose(fp); |
103 | goto error_close; | ||
104 | |||
105 | // Find dynamic section | ||
106 | sections = ebuf->e_shnum; | ||
107 | while (sections-- > 0) { | ||
108 | if (sbuf->sh_type == SHT_DYNAMIC) { | ||
109 | // Find DT_NEEDED tags | ||
110 | Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); | ||
111 | while (sbuf->sh_size >= sizeof(*dbuf)) { | ||
112 | if (dbuf->d_tag == DT_NEEDED) { | ||
113 | const char *lib = strbase + dbuf->d_un.d_ptr; | ||
114 | copy_libs_for_lib(lib, private_run_dir); | ||
115 | } | ||
116 | sbuf->sh_size -= sizeof(*dbuf); | ||
117 | dbuf++; | ||
118 | } | ||
119 | } | ||
120 | sbuf++; | ||
121 | } | ||
122 | goto close; | ||
123 | |||
124 | error_close: | ||
125 | perror("copy libs"); | ||
126 | close: | ||
127 | if (base) | ||
128 | munmap(base, s.st_size); | ||
129 | close(f); | ||
130 | } | 84 | } |
131 | 85 | ||
132 | static void copy_libs_for_lib(const char *lib, const char *private_run_dir) { | 86 | // return 1 if the file is valid |
87 | static char *valid_library(const char *lib) { | ||
88 | // filename check | ||
89 | int len = strlen(lib); | ||
90 | if (strcspn(lib, "\\&!?\"'<>%^(){}[];,*") != (size_t)len || | ||
91 | strstr(lib, "..")) { | ||
92 | fprintf(stderr, "Error: \"%s\" is an invalid library\n", lib); | ||
93 | exit(1); | ||
94 | } | ||
95 | |||
96 | // find the library | ||
133 | int i; | 97 | int i; |
134 | for (i = 0; lib_paths[i]; i++) { | 98 | for (i = 0; lib_paths[i]; i++) { |
135 | char *fname; | 99 | char *fname; |
136 | if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) | 100 | if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) |
137 | errExit("asprintf"); | 101 | errExit("asprintf"); |
138 | if (access(fname, R_OK) == 0) { | 102 | |
139 | char *dst; | 103 | // existing file owned by root |
140 | if (asprintf(&dst, "%s/%s", private_run_dir, lib) == -1) | 104 | struct stat s; |
141 | errExit("asprintf"); | 105 | if (stat(fname, &s) == 0 && s.st_uid == 0) { |
142 | 106 | return fname; | |
143 | if (access(dst, R_OK) != 0) { | ||
144 | duplicate(fname, private_run_dir); | ||
145 | // libs may need other libs | ||
146 | copy_libs_for_exe(fname, private_run_dir); | ||
147 | } | ||
148 | free(dst); | ||
149 | free(fname); | ||
150 | return; | ||
151 | } | 107 | } |
152 | free(fname); | 108 | free(fname); |
153 | } | 109 | } |
154 | errExit("library not found"); | 110 | |
111 | fwarning("%s library not found, skipping...\n", lib); | ||
112 | return NULL; | ||
155 | } | 113 | } |
156 | 114 | ||
115 | |||
157 | void fs_private_lib(void) { | 116 | void fs_private_lib(void) { |
158 | char *private_list = cfg.lib_private_keep; | 117 | char *private_list = cfg.lib_private_keep; |
159 | 118 | ||
119 | if (arg_debug) | ||
120 | printf("Starting private-lib processing: program %s, shell %s\n", | ||
121 | (cfg.original_program_index > 0)? cfg.original_argv[cfg.original_program_index]: "none", | ||
122 | (arg_shell_none)? "none": cfg.shell); | ||
123 | |||
160 | // create /run/firejail/mnt/lib directory | 124 | // create /run/firejail/mnt/lib directory |
161 | mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); | 125 | mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); |
162 | 126 | ||
127 | // fix libselinux linking problem on Debian stretch; the library is | ||
128 | // linked in most basic command utilities (ls, cp, find etc.), and it | ||
129 | // seems to have a path hardlinked under /lib/x86_64-linux-gnu directory. | ||
130 | struct stat s; | ||
131 | if (stat("/lib/x86_64-linux-gnu/libselinux.so.1", &s) == 0) { | ||
132 | mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); | ||
133 | duplicate("/lib/x86_64-linux-gnu/libselinux.so.1", RUN_LIB_DIR "/x86_64-linux-gnu"); | ||
134 | } | ||
135 | |||
163 | // copy the libs in the new lib directory for the main exe | 136 | // copy the libs in the new lib directory for the main exe |
164 | if (cfg.original_program_index > 0) | 137 | if (cfg.original_program_index > 0) |
165 | copy_libs_for_exe(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR); | 138 | copy_exe(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR, RUN_LIB_FILE); |
166 | 139 | ||
167 | // for the shell | 140 | // for the shell |
168 | if (!arg_shell_none) | 141 | if (!arg_shell_none) { |
169 | copy_libs_for_exe(cfg.shell, RUN_LIB_DIR); | 142 | copy_exe(cfg.shell, RUN_LIB_DIR, RUN_LIB_FILE); |
143 | // a shell is useless without ls command | ||
144 | copy_libs("/bin/ls", RUN_LIB_DIR, RUN_LIB_FILE); | ||
145 | } | ||
170 | 146 | ||
171 | // for the listed libs | 147 | // for the listed libs |
172 | if (private_list && *private_list != '\0') { | 148 | if (private_list && *private_list != '\0') { |
@@ -178,10 +154,21 @@ void fs_private_lib(void) { | |||
178 | errExit("strdup"); | 154 | errExit("strdup"); |
179 | 155 | ||
180 | char *ptr = strtok(dlist, ","); | 156 | char *ptr = strtok(dlist, ","); |
181 | copy_libs_for_lib(ptr, RUN_LIB_DIR); | 157 | char *lib = valid_library(ptr); |
158 | if (lib) { | ||
159 | duplicate(lib, RUN_LIB_DIR); | ||
160 | copy_libs(lib, RUN_LIB_DIR, RUN_LIB_FILE); | ||
161 | free(lib); | ||
162 | } | ||
182 | 163 | ||
183 | while ((ptr = strtok(NULL, ",")) != NULL) | 164 | while ((ptr = strtok(NULL, ",")) != NULL) { |
184 | copy_libs_for_lib(ptr, RUN_LIB_DIR); | 165 | lib = valid_library(ptr); |
166 | if (lib) { | ||
167 | duplicate(lib, RUN_LIB_DIR); | ||
168 | copy_libs(lib, RUN_LIB_DIR, RUN_LIB_FILE); | ||
169 | free(lib); | ||
170 | } | ||
171 | } | ||
185 | free(dlist); | 172 | free(dlist); |
186 | fs_logger_print(); | 173 | fs_logger_print(); |
187 | } | 174 | } |
@@ -194,14 +181,17 @@ void fs_private_lib(void) { | |||
194 | 181 | ||
195 | if (arg_debug) | 182 | if (arg_debug) |
196 | printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); | 183 | printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); |
184 | |||
197 | if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || | 185 | if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || |
198 | mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | 186 | mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) |
199 | errExit("mount bind"); | 187 | errExit("mount bind"); |
200 | fs_logger("mount /lib"); | 188 | fs_logger("mount /lib"); |
189 | |||
201 | if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 || | 190 | if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 || |
202 | mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | 191 | mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) |
203 | errExit("mount bind"); | 192 | errExit("mount bind"); |
204 | fs_logger("mount /lib64"); | 193 | fs_logger("mount /lib64"); |
194 | |||
205 | if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || | 195 | if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || |
206 | mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | 196 | mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) |
207 | errExit("mount bind"); | 197 | errExit("mount bind"); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index ff57a5693..9cff080a0 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -1631,15 +1631,19 @@ int main(int argc, char **argv) { | |||
1631 | arg_private_bin = 1; | 1631 | arg_private_bin = 1; |
1632 | } | 1632 | } |
1633 | else if (strncmp(argv[i], "--private-lib", 13) == 0) { | 1633 | else if (strncmp(argv[i], "--private-lib", 13) == 0) { |
1634 | // extract private lib list (if any) | 1634 | if (checkcfg(CFG_PRIVATE_LIB)) { |
1635 | if (argv[i][13] == '=') { | 1635 | // extract private lib list (if any) |
1636 | if (cfg.lib_private_keep) { | 1636 | if (argv[i][13] == '=') { |
1637 | if (argv[i][14] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, argv[i] + 14) < 0) | 1637 | if (cfg.lib_private_keep) { |
1638 | errExit("asprintf"); | 1638 | if (argv[i][14] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, argv[i] + 14) < 0) |
1639 | } else | 1639 | errExit("asprintf"); |
1640 | cfg.lib_private_keep = argv[i] + 14; | 1640 | } else |
1641 | cfg.lib_private_keep = argv[i] + 14; | ||
1642 | } | ||
1643 | arg_private_lib = 1; | ||
1641 | } | 1644 | } |
1642 | arg_private_lib = 1; | 1645 | else |
1646 | exit_err_feature("private-lib"); | ||
1643 | } | 1647 | } |
1644 | else if (strcmp(argv[i], "--private-tmp") == 0) { | 1648 | else if (strcmp(argv[i], "--private-tmp") == 0) { |
1645 | arg_private_tmp = 1; | 1649 | arg_private_tmp = 1; |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 972f5932d..708251b0b 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -862,15 +862,19 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
862 | 862 | ||
863 | // private /lib list of files | 863 | // private /lib list of files |
864 | if (strncmp(ptr, "private-lib", 11) == 0) { | 864 | if (strncmp(ptr, "private-lib", 11) == 0) { |
865 | if (ptr[11] == ' ') { | 865 | if (checkcfg(CFG_PRIVATE_LIB)) { |
866 | if (cfg.lib_private_keep) { | 866 | if (ptr[11] == ' ') { |
867 | if (ptr[12] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, ptr + 12) < 0) | 867 | if (cfg.lib_private_keep) { |
868 | errExit("asprintf"); | 868 | if (ptr[12] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, ptr + 12) < 0) |
869 | } else { | 869 | errExit("asprintf"); |
870 | cfg.lib_private_keep = ptr + 12; | 870 | } else { |
871 | cfg.lib_private_keep = ptr + 12; | ||
872 | } | ||
871 | } | 873 | } |
874 | arg_private_lib = 1; | ||
872 | } | 875 | } |
873 | arg_private_lib = 1; | 876 | else |
877 | warning_feature_disabled("private-lib"); | ||
874 | return 0; | 878 | return 0; |
875 | } | 879 | } |
876 | 880 | ||