aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in4
-rw-r--r--README4
-rw-r--r--README.md3
-rw-r--r--RELNOTES4
-rw-r--r--etc/Telegram.profile2
-rw-r--r--etc/telegram-desktop.profile9
-rw-r--r--etc/telegram.profile2
-rw-r--r--platform/debian/conffiles2
-rw-r--r--src/firecfg/firecfg.config1
-rw-r--r--src/firejail/firejail.h9
-rw-r--r--src/firejail/fs_lib.c202
-rw-r--r--src/firejail/main.c19
-rw-r--r--src/firejail/preproc.c2
-rw-r--r--src/firejail/profile.c25
-rw-r--r--src/firejail/sandbox.c15
-rw-r--r--src/firejail/seccomp.c23
-rw-r--r--src/fseccomp/fseccomp.h3
-rw-r--r--src/fseccomp/main.c3
-rw-r--r--src/fseccomp/seccomp.c54
-rw-r--r--src/fseccomp/seccomp_file.c2
-rw-r--r--src/man/firejail.txt34
21 files changed, 399 insertions, 23 deletions
diff --git a/Makefile.in b/Makefile.in
index 0b2455292..dabd9aa15 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -45,6 +45,7 @@ ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP)
45 src/fseccomp/fseccomp default seccomp.debug allow-debuggers 45 src/fseccomp/fseccomp default seccomp.debug allow-debuggers
46 src/fseccomp/fseccomp secondary 32 seccomp.i386 46 src/fseccomp/fseccomp secondary 32 seccomp.i386
47 src/fseccomp/fseccomp secondary 64 seccomp.amd64 47 src/fseccomp/fseccomp secondary 64 seccomp.amd64
48 src/fseccomp/fseccomp memory-deny-write-execute seccomp.mdwx
48endif 49endif
49 50
50clean: 51clean:
@@ -52,7 +53,7 @@ clean:
52 $(MAKE) -C $$dir clean; \ 53 $(MAKE) -C $$dir clean; \
53 done 54 done
54 rm -f $(MANPAGES) $(MANPAGES:%=%.gz) firejail*.rpm 55 rm -f $(MANPAGES) $(MANPAGES:%=%.gz) firejail*.rpm
55 rm -f seccomp seccomp.debug seccomp.i386 seccomp.amd64 56 rm -f seccomp seccomp.debug seccomp.i386 seccomp.amd64 seccomp.mdwx
56 rm -f test/utils/index.html* 57 rm -f test/utils/index.html*
57 rm -f test/utils/wget-log 58 rm -f test/utils/wget-log
58 rm -f test/utils/lstesting 59 rm -f test/utils/lstesting
@@ -101,6 +102,7 @@ ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP)
101 install -c -m 0644 seccomp.debug $(DESTDIR)/$(libdir)/firejail/. 102 install -c -m 0644 seccomp.debug $(DESTDIR)/$(libdir)/firejail/.
102 install -c -m 0644 seccomp.i386 $(DESTDIR)/$(libdir)/firejail/. 103 install -c -m 0644 seccomp.i386 $(DESTDIR)/$(libdir)/firejail/.
103 install -c -m 0644 seccomp.amd64 $(DESTDIR)/$(libdir)/firejail/. 104 install -c -m 0644 seccomp.amd64 $(DESTDIR)/$(libdir)/firejail/.
105 install -c -m 0644 seccomp.mdwx $(DESTDIR)/$(libdir)/firejail/.
104endif 106endif
105ifeq ($(HAVE_CONTRIB_INSTALL),yes) 107ifeq ($(HAVE_CONTRIB_INSTALL),yes)
106 install -c -m 0755 contrib/fix_private-bin.py $(DESTDIR)/$(libdir)/firejail/. 108 install -c -m 0755 contrib/fix_private-bin.py $(DESTDIR)/$(libdir)/firejail/.
diff --git a/README b/README
index 33ccd9ef9..8fec5c83f 100644
--- a/README
+++ b/README
@@ -345,6 +345,7 @@ Rahiel Kasim (https://github.com/rahiel)
345 - Mathematica profile 345 - Mathematica profile
346 - whitelisted Dropbox profile 346 - whitelisted Dropbox profile
347 - whitelisted keysnail config for firefox 347 - whitelisted keysnail config for firefox
348 - added telegram-desktop profile
348Rahul Golam (https://github.com/technoLord) 349Rahul Golam (https://github.com/technoLord)
349 - strings profile 350 - strings profile
350Raphaël Droz (https://github.com/drzraf) 351Raphaël Droz (https://github.com/drzraf)
@@ -397,8 +398,9 @@ SpotComms (https://github.com/SpotComms)
397 - fixed wget profile 398 - fixed wget profile
398 - fixed firecfg.config file 399 - fixed firecfg.config file
399 - added novideo and disable-mnt support in all profile files 400 - added novideo and disable-mnt support in all profile files
400 - added Peek and silent profiles 401 - added Peek and silent profiles
401 - added IntelliJ IDEA and Android Studio profiles 402 - added IntelliJ IDEA and Android Studio profiles
403 - added arm profile
402SYN-cook (https://github.com/SYN-cook) 404SYN-cook (https://github.com/SYN-cook)
403 - keepass/keepassx browser fixes 405 - keepass/keepassx browser fixes
404 - disable-common.inc fixes 406 - disable-common.inc fixes
diff --git a/README.md b/README.md
index 765c746ed..61279e14a 100644
--- a/README.md
+++ b/README.md
@@ -128,5 +128,6 @@ ulimit, vhangup, vserver. This brings us to a total of 91 syscalls blacklisted b
128 128
129curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite, Geary, Liferea, peek, silentarmy, 129curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite, Geary, Liferea, peek, silentarmy,
130IntelliJ IDEA, Android Studio, electron, riot-web, 130IntelliJ IDEA, Android Studio, electron, riot-web,
131Extreme Tux Racer, Frozen Bubble, Open Invaders, Pingus, Simutrans, SuperTux 131Extreme Tux Racer, Frozen Bubble, Open Invaders, Pingus, Simutrans, SuperTux,
132telegram-desktop, arm
132 133
diff --git a/RELNOTES b/RELNOTES
index 9cdd71e8d..d1f28ac17 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -7,9 +7,9 @@ firejail (0.9.49) baseline; urgency=low
7 * enhancement: rework IP address assingment for --net options 7 * enhancement: rework IP address assingment for --net options
8 * new profiles: curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite, 8 * new profiles: curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite,
9 * new profiles: Geary, Liferea, peek, silentarmy, IntelliJ IDEA, 9 * new profiles: Geary, Liferea, peek, silentarmy, IntelliJ IDEA,
10 * new profiles: Android Studio, electron, riot-web, Extreme Tux Racer, 10 * new profiles: Android Studio, electron, riot-web, Extreme Tux Racer,
11 * new profiles: Frozen Bubble, Open Invaders, Pingus, Simutrans, SuperTux 11 * new profiles: Frozen Bubble, Open Invaders, Pingus, Simutrans, SuperTux
12 12 * new profiles: telegram-desktop, arm
13 * bugfixes 13 * bugfixes
14 -- netblue30 <netblue30@yahoo.com> Mon, 12 Jun 2017 20:00:00 -0500 14 -- netblue30 <netblue30@yahoo.com> Mon, 12 Jun 2017 20:00:00 -0500
15 15
diff --git a/etc/Telegram.profile b/etc/Telegram.profile
index a8841eb8c..7b44a62f1 100644
--- a/etc/Telegram.profile
+++ b/etc/Telegram.profile
@@ -5,5 +5,5 @@ include /etc/firejail/globals.local
5# Persistent customizations should go in a .local file. 5# Persistent customizations should go in a .local file.
6include /etc/firejail/Telegram.local 6include /etc/firejail/Telegram.local
7 7
8# Telegram IRC profile 8# Telegram profile
9include /etc/firejail/telegram.profile 9include /etc/firejail/telegram.profile
diff --git a/etc/telegram-desktop.profile b/etc/telegram-desktop.profile
new file mode 100644
index 000000000..db5c2bdbb
--- /dev/null
+++ b/etc/telegram-desktop.profile
@@ -0,0 +1,9 @@
1# Persistent global definitions go here
2include /etc/firejail/globals.local
3
4# This file is overwritten during software install.
5# Persistent customizations should go in a .local file.
6include /etc/firejail/telegram-desktop.local
7
8# Telegram profile
9include /etc/firejail/telegram.profile
diff --git a/etc/telegram.profile b/etc/telegram.profile
index 5282789ce..db00e8082 100644
--- a/etc/telegram.profile
+++ b/etc/telegram.profile
@@ -5,7 +5,7 @@ include /etc/firejail/globals.local
5# Persistent customizations should go in a .local file. 5# Persistent customizations should go in a .local file.
6include /etc/firejail/telegram.local 6include /etc/firejail/telegram.local
7 7
8# Telegram IRC profile 8# Telegram profile
9noblacklist ${HOME}/.TelegramDesktop 9noblacklist ${HOME}/.TelegramDesktop
10include /etc/firejail/disable-common.inc 10include /etc/firejail/disable-common.inc
11include /etc/firejail/disable-programs.inc 11include /etc/firejail/disable-programs.inc
diff --git a/platform/debian/conffiles b/platform/debian/conffiles
index a60bf92c3..54bd2f697 100644
--- a/platform/debian/conffiles
+++ b/platform/debian/conffiles
@@ -16,6 +16,7 @@
16/etc/firejail/amarok.profile 16/etc/firejail/amarok.profile
17/etc/firejail/android-studio.profile 17/etc/firejail/android-studio.profile
18/etc/firejail/arduino.profile 18/etc/firejail/arduino.profile
19/etc/firejail/arm.profile
19/etc/firejail/ark.profile 20/etc/firejail/ark.profile
20/etc/firejail/atom-beta.profile 21/etc/firejail/atom-beta.profile
21/etc/firejail/atom.profile 22/etc/firejail/atom.profile
@@ -330,3 +331,4 @@
330/etc/firejail/pingus.profile 331/etc/firejail/pingus.profile
331/etc/firejail/simutrans.profile 332/etc/firejail/simutrans.profile
332/etc/firejail/supertux2.profile 333/etc/firejail/supertux2.profile
334/etc/firejail/telegram-desktop.profile
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index eb611034f..a6472a604 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -239,6 +239,7 @@ supertux2
239synfigstudio 239synfigstudio
240telegram 240telegram
241Telegram 241Telegram
242telegram-desktop
242thunderbird 243thunderbird
243totem 244totem
244tracker 245tracker
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index b90c8d8ed..1a26396a7 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -48,15 +48,18 @@
48#define RUN_SRV_DIR "/run/firejail/mnt/srv" 48#define RUN_SRV_DIR "/run/firejail/mnt/srv"
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 52
52#define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter 53#define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter
53#define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter 54#define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter
54#define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures 55#define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures
55#define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures 56#define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures
57#define RUN_SECCOMP_MDWX "/run/firejail/mnt/seccomp.mdwx" // filter for memory-deny-write-execute
56#define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make 58#define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make
57#define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make 59#define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make
58#define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make 60#define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make
59#define PATH_SECCOMP_I386 (LIBDIR "/firejail/seccomp.i386") // i386 filter built during make 61#define PATH_SECCOMP_I386 (LIBDIR "/firejail/seccomp.i386") // i386 filter built during make
62#define PATH_SECCOMP_MDWX (LIBDIR "/firejail/seccomp.mdwx") // filter for memory-deny-write-execute built during make
60 63
61 64
62#define RUN_DEV_DIR "/run/firejail/mnt/dev" 65#define RUN_DEV_DIR "/run/firejail/mnt/dev"
@@ -207,6 +210,7 @@ typedef struct config_t {
207 char *opt_private_keep; // keep list for private opt directory 210 char *opt_private_keep; // keep list for private opt directory
208 char *srv_private_keep; // keep list for private srv directory 211 char *srv_private_keep; // keep list for private srv directory
209 char *bin_private_keep; // keep list for private bin directory 212 char *bin_private_keep; // keep list for private bin directory
213 char *lib_private_keep; // keep list for private bin directory
210 char *cwd; // current working directory 214 char *cwd; // current working directory
211 char *overlay_dir; 215 char *overlay_dir;
212 char *private_template; // template dir for tmpfs home 216 char *private_template; // template dir for tmpfs home
@@ -328,6 +332,7 @@ extern int arg_private_opt; // private opt directory
328extern int arg_private_srv; // private srv directory 332extern int arg_private_srv; // private srv directory
329extern int arg_private_bin; // private bin directory 333extern int arg_private_bin; // private bin directory
330extern int arg_private_tmp; // private tmp directory 334extern int arg_private_tmp; // private tmp directory
335extern int arg_private_lib; // private lib directory
331extern int arg_scan; // arp-scan all interfaces 336extern int arg_scan; // arp-scan all interfaces
332extern int arg_whitelist; // whitelist commad 337extern int arg_whitelist; // whitelist commad
333extern int arg_nosound; // disable sound 338extern int arg_nosound; // disable sound
@@ -352,6 +357,7 @@ extern int arg_allusers; // all user home directories visible
352extern int arg_machineid; // preserve /etc/machine-id 357extern int arg_machineid; // preserve /etc/machine-id
353extern int arg_disable_mnt; // disable /mnt and /media 358extern int arg_disable_mnt; // disable /mnt and /media
354extern int arg_noprofile; // use default.profile if none other found/specified 359extern int arg_noprofile; // use default.profile if none other found/specified
360extern int arg_memory_deny_write_execute; // block writable and executable memory
355 361
356extern int login_shell; 362extern int login_shell;
357extern int parent_to_child_fds[2]; 363extern int parent_to_child_fds[2];
@@ -625,6 +631,9 @@ void pulseaudio_disable(void);
625// fs_bin.c 631// fs_bin.c
626void fs_private_bin_list(void); 632void fs_private_bin_list(void);
627 633
634// fs_lib.c
635void fs_private_lib(void);
636
628// protocol.c 637// protocol.c
629void protocol_filter_save(void); 638void protocol_filter_save(void);
630void protocol_filter_load(const char *fname); 639void protocol_filter_load(const char *fname);
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c
new file mode 100644
index 000000000..cc60a330f
--- /dev/null
+++ b/src/firejail/fs_lib.c
@@ -0,0 +1,202 @@
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 <elf.h>
22#include <fcntl.h>
23#include <sys/mman.h>
24#include <sys/mount.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
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[] = {
42 "/lib",
43 "/lib/x86_64-linux-gnu",
44 "/lib64",
45 "/usr/lib",
46 "/usr/lib/x86_64-linux-gnu",
47 LIBDIR,
48 "/usr/local/lib",
49 NULL
50};
51
52static void copy_libs_for_lib(const char *lib, const char *private_run_dir);
53
54static void duplicate(const char *fname, const char *private_run_dir) {
55 if (arg_debug)
56 printf("copying %s to private %s\n", fname, private_run_dir);
57 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", fname, private_run_dir);
58}
59
60static void copy_libs_for_exe(const char *exe, const char *private_run_dir) {
61 if (arg_debug)
62 printf("copy libs for %s\n", exe);
63 int f;
64 f = open(exe, O_RDONLY);
65 if (f < 0)
66 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 }
89
90 Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff);
91
92 // Find strings section
93 char *strbase = NULL;
94 int sections = ebuf->e_shnum;
95 while (sections-- > 0) {
96 if (sbuf->sh_type == SHT_STRTAB) {
97 strbase = base + sbuf->sh_offset;
98 break;
99 }
100 sbuf++;
101 }
102 if (strbase == NULL)
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}
131
132static void copy_libs_for_lib(const char *lib, const char *private_run_dir) {
133 for (int i = 0; lib_paths[i]; i++) {
134 char *fname;
135 if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1)
136 errExit("asprintf");
137 if (access(fname, R_OK) == 0) {
138 char *dst;
139 if (asprintf(&dst, "%s/%s", private_run_dir, lib) == -1)
140 errExit("asprintf");
141
142 if (access(dst, R_OK) != 0) {
143 duplicate(fname, private_run_dir);
144 // libs may need other libs
145 copy_libs_for_exe(fname, private_run_dir);
146 }
147 free(dst);
148 free(fname);
149 return;
150 }
151 free(fname);
152 }
153 errExit("library not found");
154}
155
156void fs_private_lib(void) {
157 char *private_list = cfg.lib_private_keep;
158
159 // create /run/firejail/mnt/lib directory
160 mkdir_attr(RUN_LIB_DIR, 0755, 0, 0);
161
162 // copy the libs in the new lib directory for the main exe
163 if (cfg.original_program_index > 0)
164 copy_libs_for_exe(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR);
165
166 // for the shell
167 if (!arg_shell_none)
168 copy_libs_for_exe(cfg.shell, RUN_LIB_DIR);
169
170 // for the listed libs
171 if (private_list && *private_list != '\0') {
172 if (arg_debug)
173 printf("Copying extra files (%s) in the new lib directory:\n", private_list);
174
175 char *dlist = strdup(private_list);
176 if (!dlist)
177 errExit("strdup");
178
179 char *ptr = strtok(dlist, ",");
180 copy_libs_for_lib(ptr, RUN_LIB_DIR);
181
182 while ((ptr = strtok(NULL, ",")) != NULL)
183 copy_libs_for_lib(ptr, RUN_LIB_DIR);
184 free(dlist);
185 fs_logger_print();
186 }
187
188 if (arg_debug)
189 printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR);
190 if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 ||
191 mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
192 errExit("mount bind");
193 fs_logger("mount /lib");
194 if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 ||
195 mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
196 errExit("mount bind");
197 fs_logger("mount /lib64");
198 if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 ||
199 mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0)
200 errExit("mount bind");
201 fs_logger("mount /usr/lib");
202}
diff --git a/src/firejail/main.c b/src/firejail/main.c
index c055a1537..ff57a5693 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -85,6 +85,7 @@ int arg_private_opt = 0; // private opt directory
85int arg_private_srv = 0; // private srv directory 85int arg_private_srv = 0; // private srv directory
86int arg_private_bin = 0; // private bin directory 86int arg_private_bin = 0; // private bin directory
87int arg_private_tmp = 0; // private tmp directory 87int arg_private_tmp = 0; // private tmp directory
88int arg_private_lib = 0; // private lib directory
88int arg_scan = 0; // arp-scan all interfaces 89int arg_scan = 0; // arp-scan all interfaces
89int arg_whitelist = 0; // whitelist commad 90int arg_whitelist = 0; // whitelist commad
90int arg_nosound = 0; // disable sound 91int arg_nosound = 0; // disable sound
@@ -110,6 +111,7 @@ int arg_allow_private_blacklist = 0; // blacklist things in private directorie
110int arg_writable_var_log = 0; // writable /var/log 111int arg_writable_var_log = 0; // writable /var/log
111int arg_disable_mnt = 0; // disable /mnt and /media 112int arg_disable_mnt = 0; // disable /mnt and /media
112int arg_noprofile = 0; // use default.profile if none other found/specified 113int arg_noprofile = 0; // use default.profile if none other found/specified
114int arg_memory_deny_write_execute = 0; // block writable and executable memory
113 115
114int login_shell = 0; 116int login_shell = 0;
115 117
@@ -1144,6 +1146,12 @@ int main(int argc, char **argv) {
1144 else 1146 else
1145 exit_err_feature("seccomp"); 1147 exit_err_feature("seccomp");
1146 } 1148 }
1149 else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) {
1150 if (checkcfg(CFG_SECCOMP))
1151 arg_memory_deny_write_execute = 1;
1152 else
1153 exit_err_feature("seccomp");
1154 }
1147#endif 1155#endif
1148 else if (strcmp(argv[i], "--caps") == 0) 1156 else if (strcmp(argv[i], "--caps") == 0)
1149 arg_caps_default_filter = 1; 1157 arg_caps_default_filter = 1;
@@ -1622,6 +1630,17 @@ int main(int argc, char **argv) {
1622 cfg.bin_private_keep = argv[i] + 14; 1630 cfg.bin_private_keep = argv[i] + 14;
1623 arg_private_bin = 1; 1631 arg_private_bin = 1;
1624 } 1632 }
1633 else if (strncmp(argv[i], "--private-lib", 13) == 0) {
1634 // extract private lib list (if any)
1635 if (argv[i][13] == '=') {
1636 if (cfg.lib_private_keep) {
1637 if (argv[i][14] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, argv[i] + 14) < 0)
1638 errExit("asprintf");
1639 } else
1640 cfg.lib_private_keep = argv[i] + 14;
1641 }
1642 arg_private_lib = 1;
1643 }
1625 else if (strcmp(argv[i], "--private-tmp") == 0) { 1644 else if (strcmp(argv[i], "--private-tmp") == 0) {
1626 arg_private_tmp = 1; 1645 arg_private_tmp = 1;
1627 } 1646 }
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c
index ef93368bf..9c474415d 100644
--- a/src/firejail/preproc.c
+++ b/src/firejail/preproc.c
@@ -83,6 +83,8 @@ void preproc_mount_mnt_dir(void) {
83 else 83 else
84 copy_file(PATH_SECCOMP_DEFAULT, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed 84 copy_file(PATH_SECCOMP_DEFAULT, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed
85 85
86 if (arg_memory_deny_write_execute)
87 copy_file(PATH_SECCOMP_MDWX, RUN_SECCOMP_MDWX, getuid(), getgid(), 0644); // root needed
86 // as root, create an empty RUN_SECCOMP_PROTOCOL file 88 // as root, create an empty RUN_SECCOMP_PROTOCOL file
87 create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644); 89 create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644);
88 if (set_perms(RUN_SECCOMP_PROTOCOL, getuid(), getgid(), 0644)) 90 if (set_perms(RUN_SECCOMP_PROTOCOL, getuid(), getgid(), 0644))
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 18891ac58..972f5932d 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -595,6 +595,17 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
595 return 0; 595 return 0;
596 } 596 }
597 597
598 // memory deny write&execute
599 if (strcmp(ptr, "memory-deny-write-execute") == 0) {
600#ifdef HAVE_SECCOMP
601 if (checkcfg(CFG_SECCOMP))
602 arg_memory_deny_write_execute = 1;
603 else
604 warning_feature_disabled("seccomp");
605#endif
606 return 0;
607 }
608
598 // caps drop list 609 // caps drop list
599 if (strncmp(ptr, "caps.drop ", 10) == 0) { 610 if (strncmp(ptr, "caps.drop ", 10) == 0) {
600 arg_caps_drop = 1; 611 arg_caps_drop = 1;
@@ -849,6 +860,20 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
849 return 0; 860 return 0;
850 } 861 }
851 862
863 // private /lib list of files
864 if (strncmp(ptr, "private-lib", 11) == 0) {
865 if (ptr[11] == ' ') {
866 if (cfg.lib_private_keep) {
867 if (ptr[12] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, ptr + 12) < 0)
868 errExit("asprintf");
869 } else {
870 cfg.lib_private_keep = ptr + 12;
871 }
872 }
873 arg_private_lib = 1;
874 return 0;
875 }
876
852 877
853#ifdef HAVE_OVERLAYFS 878#ifdef HAVE_OVERLAYFS
854 if (strncmp(ptr, "overlay-named ", 14) == 0) { 879 if (strncmp(ptr, "overlay-named ", 14) == 0) {
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 55733d5d7..6c0fdebe3 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -811,6 +811,16 @@ int sandbox(void* sandbox_arg) {
811 } 811 }
812 } 812 }
813 813
814 if (arg_private_lib) {
815 if (cfg.chrootdir)
816 fwarning("private-lib feature is disabled in chroot\n");
817 else if (arg_overlay)
818 fwarning("private-lib feature is disabled in overlay\n");
819 else {
820 fs_private_lib();
821 }
822 }
823
814 if (arg_private_tmp) { 824 if (arg_private_tmp) {
815 if (cfg.chrootdir) 825 if (cfg.chrootdir)
816 fwarning("private-tmp feature is disabled in chroot\n"); 826 fwarning("private-tmp feature is disabled in chroot\n");
@@ -991,6 +1001,11 @@ int sandbox(void* sandbox_arg) {
991 else 1001 else
992 seccomp_filter_drop(enforce_seccomp); 1002 seccomp_filter_drop(enforce_seccomp);
993 } 1003 }
1004 if (arg_memory_deny_write_execute) {
1005 if (arg_debug)
1006 printf("Install memory write&execute filter\n");
1007 seccomp_load(RUN_SECCOMP_MDWX); // install filter
1008 }
994#endif 1009#endif
995 1010
996 //**************************************** 1011 //****************************************
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index 29f928ee7..6e0fc0919 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -19,6 +19,7 @@
19*/ 19*/
20 20
21#ifdef HAVE_SECCOMP 21#ifdef HAVE_SECCOMP
22#include <sys/mman.h>
22#include "firejail.h" 23#include "firejail.h"
23#include "../include/seccomp.h" 24#include "../include/seccomp.h"
24 25
@@ -64,24 +65,14 @@ int seccomp_load(const char *fname) {
64 int size = lseek(fd, 0, SEEK_END); 65 int size = lseek(fd, 0, SEEK_END);
65 if (size == -1) 66 if (size == -1)
66 goto errexit; 67 goto errexit;
67 if (lseek(fd, 0 , SEEK_SET) == -1)
68 goto errexit;
69 unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); 68 unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter);
70 if (arg_debug) 69 if (arg_debug)
71 printf("configuring %d seccomp entries from %s\n", entries, fname); 70 printf("configuring %d seccomp entries from %s\n", entries, fname);
72 71
73 // read filter 72 // read filter
74 struct sock_filter *filter = malloc(size); 73 struct sock_filter *filter = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
75 if (filter == NULL) 74 if (filter == MAP_FAILED)
76 goto errexit; 75 goto errexit;
77 memset(filter, 0, size);
78 int rd = 0;
79 while (rd < size) {
80 int rv = read(fd, (unsigned char *) filter + rd, size - rd);
81 if (rv == -1)
82 goto errexit;
83 rd += rv;
84 }
85 76
86 // close file 77 // close file
87 close(fd); 78 close(fd);
@@ -91,14 +82,16 @@ int seccomp_load(const char *fname) {
91 .len = entries, 82 .len = entries,
92 .filter = filter, 83 .filter = filter,
93 }; 84 };
85 int r = 0;
94 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 86 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
95 if (!err_printed) 87 if (!err_printed)
96 fwarning("seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); 88 fwarning("seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
97 err_printed = 1; 89 err_printed = 1;
98 return 1; 90 r = 1;
99 } 91 }
100 92
101 return 0; 93 munmap(filter, size);
94 return r;
102 95
103errexit: 96errexit:
104 fprintf(stderr, "Error: cannot read %s\n", fname); 97 fprintf(stderr, "Error: cannot read %s\n", fname);
@@ -194,7 +187,7 @@ int seccomp_filter_drop(int enforce_seccomp) {
194 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, 187 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3,
195 PATH_FSECCOMP, "print", RUN_SECCOMP_CFG); 188 PATH_FSECCOMP, "print", RUN_SECCOMP_CFG);
196 189
197 return seccomp_load(RUN_SECCOMP_CFG); 190 return 0;
198} 191}
199 192
200// keep filter for seccomp option 193// keep filter for seccomp option
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h
index 1e4881e9c..157b71011 100644
--- a/src/fseccomp/fseccomp.h
+++ b/src/fseccomp/fseccomp.h
@@ -48,6 +48,7 @@ void seccomp_secondary_64(const char *fname);
48void seccomp_secondary_32(const char *fname); 48void seccomp_secondary_32(const char *fname);
49 49
50// seccomp_file.c 50// seccomp_file.c
51void write_to_file(int fd, const void *data, int size);
51void filter_init(int fd); 52void filter_init(int fd);
52void filter_add_whitelist(int fd, int syscall, int arg); 53void filter_add_whitelist(int fd, int syscall, int arg);
53void filter_add_blacklist(int fd, int syscall, int arg); 54void filter_add_blacklist(int fd, int syscall, int arg);
@@ -64,6 +65,8 @@ void seccomp_drop(const char *fname, char *list, int allow_debuggers);
64void seccomp_default_drop(const char *fname, char *list, int allow_debuggers); 65void seccomp_default_drop(const char *fname, char *list, int allow_debuggers);
65// whitelisted filter 66// whitelisted filter
66void seccomp_keep(const char *fname, char *list); 67void seccomp_keep(const char *fname, char *list);
68// block writable and executable memory
69void memory_deny_write_execute(const char *fname);
67 70
68// seccomp_print 71// seccomp_print
69void filter_print(const char *fname); 72void filter_print(const char *fname);
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c
index e322b5bbb..3d95d5bb2 100644
--- a/src/fseccomp/main.c
+++ b/src/fseccomp/main.c
@@ -35,6 +35,7 @@ static void usage(void) {
35 printf("\tfseccomp default drop file list\n"); 35 printf("\tfseccomp default drop file list\n");
36 printf("\tfseccomp default drop file list allow-debuggers\n"); 36 printf("\tfseccomp default drop file list allow-debuggers\n");
37 printf("\tfseccomp keep file list\n"); 37 printf("\tfseccomp keep file list\n");
38 printf("\tfseccomp memory-deny-write-execute file\n");
38 printf("\tfseccomp print file\n"); 39 printf("\tfseccomp print file\n");
39} 40}
40 41
@@ -87,6 +88,8 @@ printf("\n");
87 seccomp_default_drop(argv[3], argv[4], 1); 88 seccomp_default_drop(argv[3], argv[4], 1);
88 else if (argc == 4 && strcmp(argv[1], "keep") == 0) 89 else if (argc == 4 && strcmp(argv[1], "keep") == 0)
89 seccomp_keep(argv[2], argv[3]); 90 seccomp_keep(argv[2], argv[3]);
91 else if (argc == 3 && strcmp(argv[1], "memory-deny-write-execute") == 0)
92 memory_deny_write_execute(argv[2]);
90 else if (argc == 3 && strcmp(argv[1], "print") == 0) 93 else if (argc == 3 && strcmp(argv[1], "print") == 0)
91 filter_print(argv[2]); 94 filter_print(argv[2]);
92 else { 95 else {
diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c
index 4f8de8c5e..7d2ccbbce 100644
--- a/src/fseccomp/seccomp.c
+++ b/src/fseccomp/seccomp.c
@@ -19,7 +19,10 @@
19*/ 19*/
20#include "fseccomp.h" 20#include "fseccomp.h"
21#include "../include/seccomp.h" 21#include "../include/seccomp.h"
22#include <sys/mman.h>
23#include <sys/shm.h>
22#include <sys/syscall.h> 24#include <sys/syscall.h>
25#include <sys/types.h>
23 26
24static void add_default_list(int fd, int allow_debuggers) { 27static void add_default_list(int fd, int allow_debuggers) {
25#ifdef SYS_mount 28#ifdef SYS_mount
@@ -428,3 +431,54 @@ void seccomp_keep(const char *fname, char *list) {
428 // close file 431 // close file
429 close(fd); 432 close(fd);
430} 433}
434
435void memory_deny_write_execute(const char *fname) {
436 // open file
437 int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
438 if (fd < 0) {
439 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
440 exit(1);
441 }
442
443 filter_init(fd);
444
445 // build filter
446 static const struct sock_filter filter[] = {
447#ifndef __x86_64__
448 // block old multiplexing mmap syscall for i386
449 BLACKLIST(SYS_mmap),
450#endif
451 // block mmap(,,x|PROT_WRITE|PROT_EXEC) so W&X memory can't be created
452#ifndef __x86_64__
453 // mmap2 is used for mmap on i386 these days
454 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_mmap2, 0, 5),
455#else
456 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_mmap, 0, 5),
457#endif
458 EXAMINE_ARGUMENT(2),
459 BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC),
460 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1),
461 KILL_PROCESS,
462 RETURN_ALLOW,
463 // block mprotect(,,PROT_EXEC) so writable memory can't be turned into executable
464 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_mprotect, 0, 5),
465 EXAMINE_ARGUMENT(2),
466 BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC),
467 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1),
468 KILL_PROCESS,
469 RETURN_ALLOW,
470 // block shmat(,,x|SHM_EXEC) so W&X shared memory can't be created
471 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_shmat, 0, 5),
472 EXAMINE_ARGUMENT(2),
473 BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC),
474 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1),
475 KILL_PROCESS,
476 RETURN_ALLOW
477 };
478 write_to_file(fd, filter, sizeof(filter));
479
480 filter_end_blacklist(fd);
481
482 // close file
483 close(fd);
484}
diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c
index c74de9faf..16ffd5302 100644
--- a/src/fseccomp/seccomp_file.c
+++ b/src/fseccomp/seccomp_file.c
@@ -21,7 +21,7 @@
21#include "../include/seccomp.h" 21#include "../include/seccomp.h"
22#include <sys/syscall.h> 22#include <sys/syscall.h>
23 23
24static void write_to_file(int fd, void *data, int size) { 24void write_to_file(int fd, const void *data, int size) {
25 assert(data); 25 assert(data);
26 assert(size); 26 assert(size);
27 27
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index cd47800c5..3a5e8560c 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -740,6 +740,12 @@ Example:
740$ firejail \-\-machine-id 740$ firejail \-\-machine-id
741 741
742.TP 742.TP
743\fB\-\-memory-deny-write-execute
744Install a seccomp filter to block attempts to create memory mappings
745that are both writable and executable, to change mappings to be
746executable or to create executable shared memory.
747
748.TP
743\fB\-\-mtu=number 749\fB\-\-mtu=number
744Assign a MTU value to the last network interface defined by a \-\-net option. 750Assign a MTU value to the last network interface defined by a \-\-net option.
745.br 751.br
@@ -1232,6 +1238,34 @@ $ ls /bin
1232bash cat ls sed 1238bash cat ls sed
1233 1239
1234.TP 1240.TP
1241\fB\-\-private-lib=file,file
1242Build a new /lib in a temporary filesystem. For command to be executed,
1243the shell (if \-\-shell=none is not used), and the listed libraries
1244find out dynamic libraries and copy them to the /lib directory.
1245If no listed file is found, /lib directory will be empty and no programs will be able to execute.
1246The same directory is also bind-mounted over /lib64 and /usr/lib.
1247All modifications are discarded when the sandbox is closed.
1248.br
1249
1250.br
1251Example:
1252.br
1253$ firejail \-\-noprofile \-\-shell=none \-\-private-lib= \-\-private-bin=ls /bin/ls /lib /bin
1254.br
1255Parent pid 15733, child pid 15734
1256.br
1257Child process initialized in 69.61 ms
1258.br
1259/bin:
1260.br
1261ls
1262.br
1263.br
1264/lib:
1265.br
1266ld-linux-x86-64.so.2 libc.so.6 libdl.so.2 libpcre.so.3 libpthread.so.0 libselinux.so.1
1267
1268.TP
1235\fB\-\-private-dev 1269\fB\-\-private-dev
1236Create a new /dev directory. Only dri, null, full, zero, tty, pts, ptmx, random, snd, urandom, video, log and shm devices are available. 1270Create a new /dev directory. Only dri, null, full, zero, tty, pts, ptmx, random, snd, urandom, video, log and shm devices are available.
1237.br 1271.br