aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in3
-rw-r--r--README3
-rwxr-xr-xconfigure17
-rw-r--r--configure.ac2
-rw-r--r--etc/firejail.config3
-rw-r--r--src/firejail/checkcfg.c8
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/fs_lib.c196
-rw-r--r--src/firejail/main.c20
-rw-r--r--src/firejail/profile.c18
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 @@
1all: apps man filters 1all: apps man filters
2MYLIBS = src/lib 2MYLIBS = src/lib
3APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy 3APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy src/fldd
4MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 4MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5
5SECCOMP_FILTERS = seccomp seccomp.i386 seccomp.amd64 5SECCOMP_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/.
99ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP) 100ifeq ($(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/.
diff --git a/README b/README
index 13692aed7..45b4c1833 100644
--- a/README
+++ b/README
@@ -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
465valoq (https://github.com/valoq) 468valoq (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
diff --git a/configure b/configure
index f8a606f88..3dda0918e 100755
--- a/configure
+++ b/configure
@@ -676,6 +676,7 @@ infodir
676docdir 676docdir
677oldincludedir 677oldincludedir
678includedir 678includedir
679runstatedir
679localstatedir 680localstatedir
680sharedstatedir 681sharedstatedir
681sysconfdir 682sysconfdir
@@ -763,6 +764,7 @@ datadir='${datarootdir}'
763sysconfdir='${prefix}/etc' 764sysconfdir='${prefix}/etc'
764sharedstatedir='${prefix}/com' 765sharedstatedir='${prefix}/com'
765localstatedir='${prefix}/var' 766localstatedir='${prefix}/var'
767runstatedir='${localstatedir}/run'
766includedir='${prefix}/include' 768includedir='${prefix}/include'
767oldincludedir='/usr/include' 769oldincludedir='/usr/include'
768docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' 770docdir='${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
1152for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ 1163for 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
1156do 1167do
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"
3812fi 3824fi
3813 3825
3814ac_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" 3826ac_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
3816cat >confcache <<\_ACEOF 3828cat >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
178AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \ 178AC_OUTPUT(Makefile src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile \
179src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \ 179src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile \
180src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile) 180src/ftee/Makefile src/faudit/Makefile src/fseccomp/Makefile src/fldd/Makefile)
181 181
182echo 182echo
183echo "Configuration options:" 183echo "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};
712extern char *xephyr_screen; 714extern 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
41static const char * const lib_paths[] = { 26static 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
52static void copy_libs_for_lib(const char *lib, const char *private_run_dir); 37static void copy_libs(const char *exe, const char *dir, const char *file);
53 38
54static void duplicate(const char *fname, const char *private_run_dir) { 39static 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
60static 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); 47static 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; 59static 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
132static void copy_libs_for_lib(const char *lib, const char *private_run_dir) { 86// return 1 if the file is valid
87static 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
157void fs_private_lib(void) { 116void 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