aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar valoq <valoq@mailbox.org>2016-10-29 19:20:40 +0200
committerLibravatar valoq <valoq@mailbox.org>2016-10-29 19:20:40 +0200
commit4109b0dc8c13eace4d143a4a5f59018f9e29785d (patch)
tree1b3d6f85fa6f6de4ab3f5b78815de9a3c00437e6
parentadded profile for wire (diff)
parentMerge pull request #878 from msva/patch-1 (diff)
downloadfirejail-4109b0dc8c13eace4d143a4a5f59018f9e29785d.tar.gz
firejail-4109b0dc8c13eace4d143a4a5f59018f9e29785d.tar.zst
firejail-4109b0dc8c13eace4d143a4a5f59018f9e29785d.zip
Merge remote-tracking branch 'upstream/master'
-rw-r--r--.gitignore1
-rw-r--r--Makefile.in6
-rw-r--r--RELNOTES6
-rwxr-xr-xconfigure4
-rw-r--r--configure.ac3
-rw-r--r--etc/whitelist-common.inc1
-rw-r--r--src/firejail/Makefile.in4
-rw-r--r--src/firejail/appimage_size.c25
-rw-r--r--src/firejail/errno.c11
-rw-r--r--src/firejail/firejail.h25
-rw-r--r--src/firejail/fs.c12
-rw-r--r--src/firejail/fs_dev.c2
-rw-r--r--src/firejail/join.c2
-rw-r--r--src/firejail/list.c101
-rw-r--r--src/firejail/main.c57
-rw-r--r--src/firejail/network.c46
-rw-r--r--src/firejail/network_main.c44
-rw-r--r--src/firejail/profile.c14
-rw-r--r--src/firejail/protocol.c249
-rw-r--r--src/firejail/sandbox.c20
-rw-r--r--src/firejail/sbox.c181
-rw-r--r--src/firejail/seccomp.c2
-rw-r--r--src/firejail/syscall.c13
-rw-r--r--src/firejail/util.c8
-rw-r--r--src/fnet/Makefile.in43
-rw-r--r--src/fnet/fnet.h40
-rw-r--r--src/fnet/interface.c183
-rw-r--r--src/fnet/main.c70
-rw-r--r--src/fnet/veth.c (renamed from src/firejail/veth.c)8
-rw-r--r--src/fseccomp/Makefile.in43
-rw-r--r--src/fseccomp/errno.c161
-rw-r--r--src/fseccomp/fseccomp.h18
-rw-r--r--src/fseccomp/main.c42
-rw-r--r--src/fseccomp/protocol.c219
-rw-r--r--src/fseccomp/syscall.c26
-rw-r--r--src/include/seccomp.h (renamed from src/firejail/seccomp.h)0
-rw-r--r--src/include/syscall.h (renamed from src/firejail/syscall.h)1
37 files changed, 1226 insertions, 465 deletions
diff --git a/.gitignore b/.gitignore
index 0d5979c8b..6acb6775c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,4 +18,5 @@ src/firecfg/firecfg
18src/ftee/ftee 18src/ftee/ftee
19src/tags 19src/tags
20src/faudit/faudit 20src/faudit/faudit
21src/fnet/fnet
21uids.h 22uids.h
diff --git a/Makefile.in b/Makefile.in
index dbf53e2cb..86acc206c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,6 +1,6 @@
1all: apps man 1all: apps man
2MYLIBS = src/lib 2MYLIBS = src/lib
3APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect 3APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect src/fnet src/fseccomp
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
5 5
6prefix=@prefix@ 6prefix=@prefix@
@@ -76,6 +76,8 @@ realinstall:
76 install -c -m 0755 src/fshaper/fshaper.sh $(DESTDIR)/$(libdir)/firejail/. 76 install -c -m 0755 src/fshaper/fshaper.sh $(DESTDIR)/$(libdir)/firejail/.
77 install -c -m 0644 src/firecfg/firecfg.config $(DESTDIR)/$(libdir)/firejail/. 77 install -c -m 0644 src/firecfg/firecfg.config $(DESTDIR)/$(libdir)/firejail/.
78 install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. 78 install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/.
79 install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/.
80 install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/.
79 # documents 81 # documents
80 install -m 0755 -d $(DESTDIR)/$(DOCDIR) 82 install -m 0755 -d $(DESTDIR)/$(DOCDIR)
81 install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/. 83 install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/.
@@ -124,6 +126,8 @@ install-strip: all
124 strip src/libconnect/libconnect.so 126 strip src/libconnect/libconnect.so
125 strip src/ftee/ftee 127 strip src/ftee/ftee
126 strip src/faudit/faudit 128 strip src/faudit/faudit
129 strip src/fnet/fnet
130 strip src/fseccomp/fseccomp
127 $(MAKE) realinstall 131 $(MAKE) realinstall
128 132
129uninstall: 133uninstall:
diff --git a/RELNOTES b/RELNOTES
index c0fb8b20b..16c03fc23 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,7 +1,11 @@
1firejail (0.9.45) baseline; urgency=low 1firejail (0.9.45) baseline; urgency=low
2 * development version, work in progress 2 * development version, work in progress
3 -- netblue30 <netblue30@yahoo.com> Sun, 23 Oct 2016 08:00:00 -0500 3 * security: overwrite /etc/resolv.conf found by Martin Carpenter
4 * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm)
5 * feature: split most of networking code in a separate executable
4 * new profiles: xiphos, Tor Browser Bundle 6 * new profiles: xiphos, Tor Browser Bundle
7 * bugfixes
8 -- netblue30 <netblue30@yahoo.com> Sun, 23 Oct 2016 08:00:00 -0500
5 9
6firejail (0.9.44) baseline; urgency=low 10firejail (0.9.44) baseline; urgency=low
7 * CVE-2016-7545 submitted by Aleksey Manevich 11 * CVE-2016-7545 submitted by Aleksey Manevich
diff --git a/configure b/configure
index a470dffba..a89fddbef 100755
--- a/configure
+++ b/configure
@@ -3759,7 +3759,7 @@ if test "$prefix" = /usr; then
3759 sysconfdir="/etc" 3759 sysconfdir="/etc"
3760fi 3760fi
3761 3761
3762ac_config_files="$ac_config_files Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile" 3762ac_config_files="$ac_config_files Makefile src/lib/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/libconnect/Makefile src/fseccomp/Makefile"
3763 3763
3764cat >confcache <<\_ACEOF 3764cat >confcache <<\_ACEOF
3765# This file is a shell script that caches the results of configure 3765# This file is a shell script that caches the results of configure
@@ -4470,6 +4470,7 @@ do
4470 case $ac_config_target in 4470 case $ac_config_target in
4471 "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; 4471 "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
4472 "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;; 4472 "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;;
4473 "src/fnet/Makefile") CONFIG_FILES="$CONFIG_FILES src/fnet/Makefile" ;;
4473 "src/firejail/Makefile") CONFIG_FILES="$CONFIG_FILES src/firejail/Makefile" ;; 4474 "src/firejail/Makefile") CONFIG_FILES="$CONFIG_FILES src/firejail/Makefile" ;;
4474 "src/firemon/Makefile") CONFIG_FILES="$CONFIG_FILES src/firemon/Makefile" ;; 4475 "src/firemon/Makefile") CONFIG_FILES="$CONFIG_FILES src/firemon/Makefile" ;;
4475 "src/libtrace/Makefile") CONFIG_FILES="$CONFIG_FILES src/libtrace/Makefile" ;; 4476 "src/libtrace/Makefile") CONFIG_FILES="$CONFIG_FILES src/libtrace/Makefile" ;;
@@ -4478,6 +4479,7 @@ do
4478 "src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;; 4479 "src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;;
4479 "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;; 4480 "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;;
4480 "src/libconnect/Makefile") CONFIG_FILES="$CONFIG_FILES src/libconnect/Makefile" ;; 4481 "src/libconnect/Makefile") CONFIG_FILES="$CONFIG_FILES src/libconnect/Makefile" ;;
4482 "src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;;
4481 4483
4482 *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; 4484 *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
4483 esac 4485 esac
diff --git a/configure.ac b/configure.ac
index 95947a8e3..9e7680d7d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -148,7 +148,8 @@ if test "$prefix" = /usr; then
148 sysconfdir="/etc" 148 sysconfdir="/etc"
149fi 149fi
150 150
151AC_OUTPUT(Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile) 151AC_OUTPUT(Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile \
152src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile)
152 153
153echo 154echo
154echo "Configuration options:" 155echo "Configuration options:"
diff --git a/etc/whitelist-common.inc b/etc/whitelist-common.inc
index fd44c2528..e533fe596 100644
--- a/etc/whitelist-common.inc
+++ b/etc/whitelist-common.inc
@@ -14,6 +14,7 @@ whitelist ~/.fonts.d
14whitelist ~/.fontconfig 14whitelist ~/.fontconfig
15whitelist ~/.fonts.conf 15whitelist ~/.fonts.conf
16whitelist ~/.fonts.conf.d 16whitelist ~/.fonts.conf.d
17whitelist ~/.local/share/fonts
17whitelist ~/.config/fontconfig 18whitelist ~/.config/fontconfig
18whitelist ~/.cache/fontconfig 19whitelist ~/.cache/fontconfig
19 20
diff --git a/src/firejail/Makefile.in b/src/firejail/Makefile.in
index fce460906..c99b6c30c 100644
--- a/src/firejail/Makefile.in
+++ b/src/firejail/Makefile.in
@@ -30,11 +30,11 @@ BINOBJS = $(foreach file, $(OBJS), $file)
30CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security 30CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
31LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread 31LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
32 32
33%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h 33%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/pid.h ../include/seccomp.h ../include/syscall.h
34 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 34 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
35 35
36firejail: $(OBJS) ../lib/libnetlink.o ../lib/common.o 36firejail: $(OBJS) ../lib/libnetlink.o ../lib/common.o
37 $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) 37 $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS)
38 38
39clean:; rm -f *.o firejail firejail.1 firejail.1.gz 39clean:; rm -f *.o firejail firejail.1 firejail.1.gz
40 40
diff --git a/src/firejail/appimage_size.c b/src/firejail/appimage_size.c
index c8b3d28c5..3f5c3150c 100644
--- a/src/firejail/appimage_size.c
+++ b/src/firejail/appimage_size.c
@@ -1,4 +1,23 @@
1/* 1/*
2 * Copyright (C) 2014-2016 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/*
2Compile with: 21Compile with:
3gcc elfsize.c -o elfsize 22gcc elfsize.c -o elfsize
4Example: 23Example:
@@ -9,7 +28,6 @@ Size of section headers e_shentsize 64
9Number of section headers e_shnum 29 28Number of section headers e_shnum 29
10e_shoff + ( e_shentsize * e_shnum ) = 126584 29e_shoff + ( e_shentsize * e_shnum ) = 126584
11*/ 30*/
12
13#include <elf.h> 31#include <elf.h>
14#include <byteswap.h> 32#include <byteswap.h>
15#include <stdio.h> 33#include <stdio.h>
@@ -23,7 +41,6 @@ e_shoff + ( e_shentsize * e_shnum ) = 126584
23typedef Elf32_Nhdr Elf_Nhdr; 41typedef Elf32_Nhdr Elf_Nhdr;
24 42
25static Elf64_Ehdr ehdr; 43static Elf64_Ehdr ehdr;
26static Elf64_Phdr *phdr;
27 44
28#if __BYTE_ORDER == __LITTLE_ENDIAN 45#if __BYTE_ORDER == __LITTLE_ENDIAN
29#define ELFDATANATIVE ELFDATA2LSB 46#define ELFDATANATIVE ELFDATA2LSB
@@ -57,7 +74,7 @@ static uint64_t file64_to_cpu(uint64_t val) {
57// return 0 if error 74// return 0 if error
58static long unsigned int read_elf32(int fd) { 75static long unsigned int read_elf32(int fd) {
59 Elf32_Ehdr ehdr32; 76 Elf32_Ehdr ehdr32;
60 ssize_t ret, i; 77 ssize_t ret;
61 78
62 ret = pread(fd, &ehdr32, sizeof(ehdr32), 0); 79 ret = pread(fd, &ehdr32, sizeof(ehdr32), 0);
63 if (ret < 0 || (size_t)ret != sizeof(ehdr)) 80 if (ret < 0 || (size_t)ret != sizeof(ehdr))
@@ -74,7 +91,7 @@ static long unsigned int read_elf32(int fd) {
74// return 0 if error 91// return 0 if error
75static long unsigned int read_elf64(int fd) { 92static long unsigned int read_elf64(int fd) {
76 Elf64_Ehdr ehdr64; 93 Elf64_Ehdr ehdr64;
77 ssize_t ret, i; 94 ssize_t ret;
78 95
79 ret = pread(fd, &ehdr64, sizeof(ehdr64), 0); 96 ret = pread(fd, &ehdr64, sizeof(ehdr64), 0);
80 if (ret < 0 || (size_t)ret != sizeof(ehdr)) 97 if (ret < 0 || (size_t)ret != sizeof(ehdr))
diff --git a/src/firejail/errno.c b/src/firejail/errno.c
index c493dfa09..03f10bb14 100644
--- a/src/firejail/errno.c
+++ b/src/firejail/errno.c
@@ -206,15 +206,4 @@ char *errno_find_nr(int nr) {
206 return "unknown"; 206 return "unknown";
207} 207}
208 208
209void errno_print(void) {
210 EUID_ASSERT();
211
212 int i;
213 int elems = sizeof(errnolist) / sizeof(errnolist[0]);
214 for (i = 0; i < elems; i++) {
215 printf("%d\t- %s\n", errnolist[i].nr, errnolist[i].name);
216 }
217 printf("\n");
218}
219
220#endif // HAVE_SECCOMP 209#endif // HAVE_SECCOMP
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 9a9bb1ae7..749656f8b 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -25,6 +25,7 @@
25// debug restricted shell 25// debug restricted shell
26//#define DEBUG_RESTRICTED_SHELL 26//#define DEBUG_RESTRICTED_SHELL
27 27
28
28// filesystem 29// filesystem
29#define RUN_FIREJAIL_BASEDIR "/run" 30#define RUN_FIREJAIL_BASEDIR "/run"
30#define RUN_FIREJAIL_DIR "/run/firejail" 31#define RUN_FIREJAIL_DIR "/run/firejail"
@@ -38,6 +39,7 @@
38#define RUN_RO_FILE "/run/firejail/firejail.ro.file" 39#define RUN_RO_FILE "/run/firejail/firejail.ro.file"
39#define RUN_MNT_DIR "/run/firejail/mnt" // a tmpfs is mounted on this directory before any of the files below are created 40#define RUN_MNT_DIR "/run/firejail/mnt" // a tmpfs is mounted on this directory before any of the files below are created
40#define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" 41#define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp"
42#define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol"
41#define RUN_CGROUP_CFG "/run/firejail/mnt/cgroup" 43#define RUN_CGROUP_CFG "/run/firejail/mnt/cgroup"
42#define RUN_CPU_CFG "/run/firejail/mnt/cpu" 44#define RUN_CPU_CFG "/run/firejail/mnt/cpu"
43#define RUN_GROUPS_CFG "/run/firejail/mnt/groups" 45#define RUN_GROUPS_CFG "/run/firejail/mnt/groups"
@@ -362,7 +364,6 @@ void net_if_ip6(const char *ifname, const char *addr6);
362int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu); 364int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu);
363int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw); 365int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw);
364void net_ifprint(void); 366void net_ifprint(void);
365void net_bridge_add_interface(const char *bridge, const char *dev);
366uint32_t network_get_defaultgw(void); 367uint32_t network_get_defaultgw(void);
367int net_config_mac(const char *ifname, const unsigned char mac[6]); 368int net_config_mac(const char *ifname, const unsigned char mac[6]);
368int net_get_mac(const char *ifname, unsigned char mac[6]); 369int net_get_mac(const char *ifname, unsigned char mac[6]);
@@ -432,11 +433,6 @@ uint32_t arp_assign(const char *dev, Bridge *br);
432// scan interface (--scan option) 433// scan interface (--scan option)
433void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask); 434void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask);
434 435
435// veth.c
436int net_create_veth(const char *dev, const char *nsdev, unsigned pid);
437int net_create_macvlan(const char *dev, const char *parent, unsigned pid);
438int net_move_interface(const char *dev, unsigned pid);
439
440// util.c 436// util.c
441void drop_privs(int nogroups); 437void drop_privs(int nogroups);
442int mkpath_as_root(const char* path); 438int mkpath_as_root(const char* path);
@@ -519,8 +515,6 @@ void caps_print_filter_name(const char *name);
519const char *syscall_find_nr(int nr); 515const char *syscall_find_nr(int nr);
520// return -1 if error, 0 if no error 516// return -1 if error, 0 if no error
521int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg); 517int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg);
522// print all available syscallsseccomp
523void syscall_print(void);
524 518
525// fs_trace.c 519// fs_trace.c
526void fs_trace_preload(void); 520void fs_trace_preload(void);
@@ -603,7 +597,7 @@ void protocol_list();
603void protocol_print_filter_name(const char *name); 597void protocol_print_filter_name(const char *name);
604void protocol_print_filter(pid_t pid); 598void protocol_print_filter(pid_t pid);
605void protocol_store(const char *prlist); 599void protocol_store(const char *prlist);
606void protocol_filter(void); 600void protocol_filter(const char *fname);
607void protocol_filter_save(void); 601void protocol_filter_save(void);
608void protocol_filter_load(const char *fname); 602void protocol_filter_load(const char *fname);
609 603
@@ -687,6 +681,19 @@ long unsigned int appimage2_size(const char *fname);
687// cmdline.c 681// cmdline.c
688void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); 682void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index);
689 683
684// sbox.c
685// programs
686#define PATH_FNET (LIBDIR "/firejail/fnet")
687#define PATH_FIREMON (PREFIX "/bin/firemon")
688#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp")
689// bitmapped filters for sbox_run
690#define SBOX_ROOT 1
691#define SBOX_USER 2
692#define SBOX_CAPS 4
693#define SBOX_SECCOMP 8
694// run sbox
695int sbox_run(unsigned filter, int num, ...);
696
690 697
691#endif 698#endif
692 699
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 6c566bd90..572b08205 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -754,8 +754,8 @@ void fs_basic_fs(void) {
754 fs_rdonly("/usr"); 754 fs_rdonly("/usr");
755 755
756 // update /var directory in order to support multiple sandboxes running on the same root directory 756 // update /var directory in order to support multiple sandboxes running on the same root directory
757 if (!arg_private_dev) 757// if (!arg_private_dev)
758 fs_dev_shm(); 758// fs_dev_shm();
759 fs_var_lock(); 759 fs_var_lock();
760 fs_var_tmp(); 760 fs_var_tmp();
761 fs_var_log(); 761 fs_var_log();
@@ -1061,8 +1061,8 @@ void fs_overlayfs(void) {
1061 errExit("chroot"); 1061 errExit("chroot");
1062 1062
1063 // update /var directory in order to support multiple sandboxes running on the same root directory 1063 // update /var directory in order to support multiple sandboxes running on the same root directory
1064 if (!arg_private_dev) 1064// if (!arg_private_dev)
1065 fs_dev_shm(); 1065// fs_dev_shm();
1066 fs_var_lock(); 1066 fs_var_lock();
1067 fs_var_tmp(); 1067 fs_var_tmp();
1068 fs_var_log(); 1068 fs_var_log();
@@ -1233,8 +1233,8 @@ void fs_chroot(const char *rootdir) {
1233 1233
1234 if (checkcfg(CFG_CHROOT_DESKTOP)) { 1234 if (checkcfg(CFG_CHROOT_DESKTOP)) {
1235 // update /var directory in order to support multiple sandboxes running on the same root directory 1235 // update /var directory in order to support multiple sandboxes running on the same root directory
1236 if (!arg_private_dev) 1236// if (!arg_private_dev)
1237 fs_dev_shm(); 1237// fs_dev_shm();
1238 fs_var_lock(); 1238 fs_var_lock();
1239 fs_var_tmp(); 1239 fs_var_tmp();
1240 fs_var_log(); 1240 fs_var_log();
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index aa5f7c28b..0186c6f82 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -244,6 +244,7 @@ void fs_private_dev(void){
244} 244}
245 245
246 246
247#if 0
247void fs_dev_shm(void) { 248void fs_dev_shm(void) {
248 uid_t uid = getuid(); // set a new shm only if we started as root 249 uid_t uid = getuid(); // set a new shm only if we started as root
249 if (uid) 250 if (uid)
@@ -282,6 +283,7 @@ void fs_dev_shm(void) {
282 283
283 } 284 }
284} 285}
286#endif
285 287
286static void disable_file_or_dir(const char *fname) { 288static void disable_file_or_dir(const char *fname) {
287 if (arg_debug) 289 if (arg_debug)
diff --git a/src/firejail/join.c b/src/firejail/join.c
index ea44019ca..9b5fba24d 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -296,7 +296,7 @@ void join(pid_t pid, int argc, char **argv, int index) {
296 if (getuid() != 0) 296 if (getuid() != 0)
297 protocol_filter_load(RUN_PROTOCOL_CFG); 297 protocol_filter_load(RUN_PROTOCOL_CFG);
298 if (cfg.protocol) { // not available for uid 0 298 if (cfg.protocol) { // not available for uid 0
299 protocol_filter(); 299 protocol_filter(RUN_SECCOMP_PROTOCOL);
300 } 300 }
301 301
302 // set seccomp filter 302 // set seccomp filter
diff --git a/src/firejail/list.c b/src/firejail/list.c
deleted file mode 100644
index d093a1f85..000000000
--- a/src/firejail/list.c
+++ /dev/null
@@ -1,101 +0,0 @@
1/*
2 * Copyright (C) 2014-2016 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 <sys/types.h>
22#include <sys/stat.h>
23
24static void set_privileges(void) {
25 struct stat s;
26 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
27 EUID_ROOT();
28
29 // elevate privileges
30 if (setreuid(0, 0))
31 errExit("setreuid");
32 if (setregid(0, 0))
33 errExit("setregid");
34 }
35 else
36 drop_privs(1);
37}
38
39static char *get_firemon_path(const char *cmd) {
40 assert(cmd);
41
42 // start the argv[0] program in a new sandbox
43 char *firemon;
44 if (asprintf(&firemon, "%s/bin/firemon %s", PREFIX, cmd) == -1)
45 errExit("asprintf");
46
47 return firemon;
48}
49
50void top(void) {
51 EUID_ASSERT();
52 drop_privs(1);
53 char *cmd = get_firemon_path("--top");
54
55 char *arg[4];
56 arg[0] = "bash";
57 arg[1] = "-c";
58 arg[2] = cmd;
59 arg[3] = NULL;
60 execvp("/bin/bash", arg);
61}
62
63void netstats(void) {
64 EUID_ASSERT();
65 set_privileges();
66 char *cmd = get_firemon_path("--netstats");
67
68 char *arg[4];
69 arg[0] = "bash";
70 arg[1] = "-c";
71 arg[2] = cmd;
72 arg[3] = NULL;
73 execvp("/bin/bash", arg);
74}
75
76void list(void) {
77 EUID_ASSERT();
78 drop_privs(1);
79 char *cmd = get_firemon_path("--list");
80
81 char *arg[4];
82 arg[0] = "bash";
83 arg[1] = "-c";
84 arg[2] = cmd;
85 arg[3] = NULL;
86 execvp("/bin/bash", arg);
87}
88
89void tree(void) {
90 EUID_ASSERT();
91 drop_privs(1);
92 char *cmd = get_firemon_path("--tree");
93
94 char *arg[4];
95 arg[0] = "bash";
96 arg[1] = "-c";
97 arg[2] = cmd;
98 arg[3] = NULL;
99 execvp("/bin/bash", arg);
100}
101
diff --git a/src/firejail/main.c b/src/firejail/main.c
index b5a97c71e..e210ceb31 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -54,9 +54,9 @@ Config cfg; // configuration
54int arg_private = 0; // mount private /home and /tmp directoryu 54int arg_private = 0; // mount private /home and /tmp directoryu
55int arg_private_template = 0; // mount private /home using a template 55int arg_private_template = 0; // mount private /home using a template
56int arg_debug = 0; // print debug messages 56int arg_debug = 0; // print debug messages
57int arg_debug_check_filename; // print debug messages for filename checking 57int arg_debug_check_filename = 0; // print debug messages for filename checking
58int arg_debug_blacklists; // print debug messages for blacklists 58int arg_debug_blacklists = 0; // print debug messages for blacklists
59int arg_debug_whitelists; // print debug messages for whitelists 59int arg_debug_whitelists = 0; // print debug messages for whitelists
60int arg_nonetwork = 0; // --net=none 60int arg_nonetwork = 0; // --net=none
61int arg_command = 0; // -c 61int arg_command = 0; // -c
62int arg_overlay = 0; // overlay option 62int arg_overlay = 0; // overlay option
@@ -404,8 +404,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
404#ifdef HAVE_SECCOMP 404#ifdef HAVE_SECCOMP
405 else if (strcmp(argv[i], "--debug-syscalls") == 0) { 405 else if (strcmp(argv[i], "--debug-syscalls") == 0) {
406 if (checkcfg(CFG_SECCOMP)) { 406 if (checkcfg(CFG_SECCOMP)) {
407 syscall_print(); 407 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-syscalls");
408 exit(0); 408 exit(rv);
409 } 409 }
410 else { 410 else {
411 fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); 411 fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n");
@@ -414,7 +414,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
414 } 414 }
415 else if (strcmp(argv[i], "--debug-errnos") == 0) { 415 else if (strcmp(argv[i], "--debug-errnos") == 0) {
416 if (checkcfg(CFG_SECCOMP)) { 416 if (checkcfg(CFG_SECCOMP)) {
417 errno_print(); 417 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-errnos");
418 exit(rv);
418 } 419 }
419 else { 420 else {
420 fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); 421 fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n");
@@ -438,8 +439,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
438 exit(0); 439 exit(0);
439 } 440 }
440 else if (strcmp(argv[i], "--debug-protocols") == 0) { 441 else if (strcmp(argv[i], "--debug-protocols") == 0) {
441 protocol_list(); 442 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-protocols");
442 exit(0); 443 exit(rv);
443 } 444 }
444 else if (strncmp(argv[i], "--protocol.print=", 17) == 0) { 445 else if (strncmp(argv[i], "--protocol.print=", 17) == 0) {
445 if (checkcfg(CFG_SECCOMP)) { 446 if (checkcfg(CFG_SECCOMP)) {
@@ -498,27 +499,32 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
498 exit(0); 499 exit(0);
499 } 500 }
500 else if (strcmp(argv[i], "--list") == 0) { 501 else if (strcmp(argv[i], "--list") == 0) {
501 list(); 502 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--list");
502 exit(0); 503 exit(rv);
503 } 504 }
504 else if (strcmp(argv[i], "--tree") == 0) { 505 else if (strcmp(argv[i], "--tree") == 0) {
505 tree(); 506 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree");
506 exit(0); 507 exit(rv);
507 } 508 }
508 else if (strcmp(argv[i], "--top") == 0) { 509 else if (strcmp(argv[i], "--top") == 0) {
509 top(); 510 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--top");
510 exit(0); 511 exit(rv);
511 } 512 }
512#ifdef HAVE_NETWORK 513#ifdef HAVE_NETWORK
513 else if (strcmp(argv[i], "--netstats") == 0) { 514 else if (strcmp(argv[i], "--netstats") == 0) {
514 if (checkcfg(CFG_NETWORK)) { 515 if (checkcfg(CFG_NETWORK)) {
515 netstats(); 516 struct stat s;
517 int rv;
518 if (stat("/proc/sys/kernel/grsecurity", &s) == 0)
519 rv = sbox_run(SBOX_ROOT | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
520 else
521 rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
522 exit(rv);
516 } 523 }
517 else { 524 else {
518 fprintf(stderr, "Error: networking features are disabled in Firejail configuration file\n"); 525 fprintf(stderr, "Error: networking features are disabled in Firejail configuration file\n");
519 exit(1); 526 exit(1);
520 } 527 }
521 exit(0);
522 } 528 }
523#endif 529#endif
524#ifdef HAVE_FILE_TRANSFER 530#ifdef HAVE_FILE_TRANSFER
@@ -1112,7 +1118,16 @@ int main(int argc, char **argv) {
1112#ifdef HAVE_SECCOMP 1118#ifdef HAVE_SECCOMP
1113 else if (strncmp(argv[i], "--protocol=", 11) == 0) { 1119 else if (strncmp(argv[i], "--protocol=", 11) == 0) {
1114 if (checkcfg(CFG_SECCOMP)) { 1120 if (checkcfg(CFG_SECCOMP)) {
1115 protocol_store(argv[i] + 11); 1121 if (cfg.protocol) {
1122 if (!arg_quiet)
1123 fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", argv[i] + 11);
1124 }
1125 else {
1126 // store list
1127 cfg.protocol = strdup(argv[i] + 11);
1128 if (!cfg.protocol)
1129 errExit("strdup");
1130 }
1116 } 1131 }
1117 else { 1132 else {
1118 fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); 1133 fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n");
@@ -1605,6 +1620,14 @@ int main(int argc, char **argv) {
1605 return 1; 1620 return 1;
1606 } 1621 }
1607 1622
1623 // don't allow "--chroot=/"
1624 char *rpath = realpath(cfg.chrootdir, NULL);
1625 if (rpath == NULL || strcmp(rpath, "/") == 0) {
1626 fprintf(stderr, "Error: invalid chroot directory\n");
1627 exit(1);
1628 }
1629 free(rpath);
1630
1608 // check chroot directory structure 1631 // check chroot directory structure
1609 if (fs_check_chroot_dir(cfg.chrootdir)) { 1632 if (fs_check_chroot_dir(cfg.chrootdir)) {
1610 fprintf(stderr, "Error: invalid chroot\n"); 1633 fprintf(stderr, "Error: invalid chroot\n");
diff --git a/src/firejail/network.c b/src/firejail/network.c
index 4473ef099..ac0d86559 100644
--- a/src/firejail/network.c
+++ b/src/firejail/network.c
@@ -431,52 +431,6 @@ int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) {
431} 431}
432 432
433 433
434// add a veth device to a bridge
435void net_bridge_add_interface(const char *bridge, const char *dev) {
436 if (strlen(bridge) > IFNAMSIZ) {
437 fprintf(stderr, "Error: invalid network device name %s\n", bridge);
438 exit(1);
439 }
440
441 // somehow adding the interface to the bridge resets MTU on bridge device!!!
442 // workaround: restore MTU on the bridge device
443 // todo: put a real fix in
444 int mtu1 = net_get_mtu(bridge);
445
446 struct ifreq ifr;
447 int err;
448 int ifindex = if_nametoindex(dev);
449
450 if (ifindex <= 0)
451 errExit("if_nametoindex");
452
453 int sock;
454 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
455 errExit("socket");
456
457 memset(&ifr, 0, sizeof(ifr));
458 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
459#ifdef SIOCBRADDIF
460 ifr.ifr_ifindex = ifindex;
461 err = ioctl(sock, SIOCBRADDIF, &ifr);
462 if (err < 0)
463#endif
464 {
465 unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 };
466
467 ifr.ifr_data = (char *) args;
468 err = ioctl(sock, SIOCDEVPRIVATE, &ifr);
469 }
470 (void) err;
471 close(sock);
472
473 int mtu2 = net_get_mtu(bridge);
474 if (mtu1 != mtu2) {
475 if (arg_debug)
476 printf("Restoring MTU for %s\n", bridge);
477 net_set_mtu(bridge, mtu1);
478 }
479}
480 434
481#define BUFSIZE 1024 435#define BUFSIZE 1024
482uint32_t network_get_defaultgw(void) { 436uint32_t network_get_defaultgw(void) {
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c
index 907b84642..35d6dd214 100644
--- a/src/firejail/network_main.c
+++ b/src/firejail/network_main.c
@@ -23,6 +23,7 @@
23#include <sys/stat.h> 23#include <sys/stat.h>
24#include <unistd.h> 24#include <unistd.h>
25#include <net/if.h> 25#include <net/if.h>
26#include <stdarg.h>
26 27
27// configure bridge structure 28// configure bridge structure
28// - extract ip address and mask from the bridge interface 29// - extract ip address and mask from the bridge interface
@@ -127,13 +128,12 @@ void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) {
127 else 128 else
128 dev = br->veth_name; 129 dev = br->veth_name;
129 130
130 net_create_veth(dev, ifname, child); 131// net_create_veth(dev, ifname, child);
131 132 char *cstr;
132 // add interface to the bridge 133 if (asprintf(&cstr, "%d", child) == -1)
133 net_bridge_add_interface(br->dev, dev); 134 errExit("asprintf");
134 135 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 7, PATH_FNET, "create", "veth", dev, ifname, br->dev, cstr);
135 // bring up the interface 136 free(cstr);
136 net_if_up(dev);
137 137
138 char *msg; 138 char *msg;
139 if (asprintf(&msg, "%d.%d.%d.%d address assigned to sandbox", PRINT_IP(br->ipsandbox)) == -1) 139 if (asprintf(&msg, "%d.%d.%d.%d address assigned to sandbox", PRINT_IP(br->ipsandbox)) == -1)
@@ -290,47 +290,61 @@ void net_dns_print(pid_t pid) {
290} 290}
291 291
292void network_main(pid_t child) { 292void network_main(pid_t child) {
293 char *cstr;
294 if (asprintf(&cstr, "%d", child) == -1)
295 errExit("asprintf");
296
293 // create veth pair or macvlan device 297 // create veth pair or macvlan device
294 if (cfg.bridge0.configured) { 298 if (cfg.bridge0.configured) {
295 if (cfg.bridge0.macvlan == 0) { 299 if (cfg.bridge0.macvlan == 0) {
296 net_configure_veth_pair(&cfg.bridge0, "eth0", child); 300 net_configure_veth_pair(&cfg.bridge0, "eth0", child);
297 } 301 }
298 else 302 else
299 net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); 303// net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child);
304 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge0.devsandbox, cfg.bridge0.dev, cstr);
300 } 305 }
301 306
302 if (cfg.bridge1.configured) { 307 if (cfg.bridge1.configured) {
303 if (cfg.bridge1.macvlan == 0) 308 if (cfg.bridge1.macvlan == 0)
304 net_configure_veth_pair(&cfg.bridge1, "eth1", child); 309 net_configure_veth_pair(&cfg.bridge1, "eth1", child);
305 else 310 else
306 net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); 311// net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child);
312 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge1.devsandbox, cfg.bridge1.dev, cstr);
307 } 313 }
308 314
309 if (cfg.bridge2.configured) { 315 if (cfg.bridge2.configured) {
310 if (cfg.bridge2.macvlan == 0) 316 if (cfg.bridge2.macvlan == 0)
311 net_configure_veth_pair(&cfg.bridge2, "eth2", child); 317 net_configure_veth_pair(&cfg.bridge2, "eth2", child);
312 else 318 else
313 net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); 319// net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child);
320 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge2.devsandbox, cfg.bridge2.dev, cstr);
314 } 321 }
315 322
316 if (cfg.bridge3.configured) { 323 if (cfg.bridge3.configured) {
317 if (cfg.bridge3.macvlan == 0) 324 if (cfg.bridge3.macvlan == 0)
318 net_configure_veth_pair(&cfg.bridge3, "eth3", child); 325 net_configure_veth_pair(&cfg.bridge3, "eth3", child);
319 else 326 else
320 net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); 327// net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child);
328 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge3.devsandbox, cfg.bridge3.dev, cstr);
321 } 329 }
322 330
323 // move interfaces in sandbox 331 // move interfaces in sandbox
324 if (cfg.interface0.configured) { 332 if (cfg.interface0.configured) {
325 net_move_interface(cfg.interface0.dev, child); 333// net_move_interface(cfg.interface0.dev, child);
334 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface0.dev, cstr);
326 } 335 }
327 if (cfg.interface1.configured) { 336 if (cfg.interface1.configured) {
328 net_move_interface(cfg.interface1.dev, child); 337// net_move_interface(cfg.interface1.dev, child);
338 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface1.dev, cstr);
329 } 339 }
330 if (cfg.interface2.configured) { 340 if (cfg.interface2.configured) {
331 net_move_interface(cfg.interface2.dev, child); 341// net_move_interface(cfg.interface2.dev, child);
342 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
332 } 343 }
333 if (cfg.interface3.configured) { 344 if (cfg.interface3.configured) {
334 net_move_interface(cfg.interface3.dev, child); 345// net_move_interface(cfg.interface3.dev, child);
346 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
335 } 347 }
348
349 free(cstr);
336} 350}
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index e5c35a89d..f7d5e87e6 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -497,8 +497,18 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
497 497
498 if (strncmp(ptr, "protocol ", 9) == 0) { 498 if (strncmp(ptr, "protocol ", 9) == 0) {
499#ifdef HAVE_SECCOMP 499#ifdef HAVE_SECCOMP
500 if (checkcfg(CFG_SECCOMP)) 500 if (checkcfg(CFG_SECCOMP)) {
501 protocol_store(ptr + 9); 501 if (cfg.protocol) {
502 if (!arg_quiet)
503 fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", ptr + 9);
504 return 0;
505 }
506
507 // store list
508 cfg.protocol = strdup(ptr + 9);
509 if (!cfg.protocol)
510 errExit("strdup");
511 }
502 else 512 else
503 fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); 513 fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n");
504#endif 514#endif
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c
index 1ef5bf13d..43f30e30a 100644
--- a/src/firejail/protocol.c
+++ b/src/firejail/protocol.c
@@ -18,241 +18,44 @@
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 20
21/*
22 struct sock_filter filter[] = {
23 VALIDATE_ARCHITECTURE,
24 EXAMINE_SYSCALL,
25 ONLY(SYS_socket),
26 EXAMINE_ARGUMENT(0), // allow only AF_INET and AF_INET6, drop everything else
27 WHITELIST(AF_INET),
28 WHITELIST(AF_INET6),
29 WHITELIST(AF_PACKET),
30 RETURN_ERRNO(ENOTSUP)
31 };
32 struct sock_fprog prog = {
33 .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
34 .filter = filter,
35 };
36
37
38 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
39 perror("prctl(NO_NEW_PRIVS)");
40 return 1;
41 }
42 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
43 perror("prctl");
44 return 1;
45 }
46*/
47
48#ifdef HAVE_SECCOMP 21#ifdef HAVE_SECCOMP
49#include "firejail.h" 22#include "firejail.h"
50#include "seccomp.h" 23#include "../include/seccomp.h"
51#include <sys/types.h>
52#include <sys/socket.h>
53
54static char *protocol[] = {
55 "unix",
56 "inet",
57 "inet6",
58 "netlink",
59 "packet",
60 NULL
61};
62
63static struct sock_filter protocol_filter_command[] = {
64 WHITELIST(AF_UNIX),
65 WHITELIST(AF_INET),
66 WHITELIST(AF_INET6),
67 WHITELIST(AF_NETLINK),
68 WHITELIST(AF_PACKET)
69};
70// Note: protocol[] and protocol_filter_command are synchronized
71
72// command length
73struct sock_filter whitelist[] = {
74 WHITELIST(AF_UNIX)
75};
76unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter);
77
78 24
79 25// install protocol filter
80static int is_protocol(const char *p) { 26void protocol_filter(const char *fname) {
81 int i = 0;
82 while (protocol[i] != NULL) {
83 if (strcmp(protocol[i], p) == 0)
84 return 1;
85 i++;
86 }
87
88 return 0;
89}
90
91static struct sock_filter *find_protocol_domain(const char *p) {
92 int i = 0;
93 while (protocol[i] != NULL) {
94 if (strcmp(protocol[i], p) == 0)
95 return &protocol_filter_command[i * whitelist_len];
96 i++;
97 }
98
99 return NULL;
100}
101
102// --debug-protocols
103void protocol_list(void) {
104 EUID_ASSERT();
105
106#ifndef SYS_socket 27#ifndef SYS_socket
107 fprintf(stderr, "Warning: --protocol not supported on this platform\n"); 28 if (arg_debug)
29 printf("No support for --protocol on this platform\n");
108 return; 30 return;
109#endif 31#else
110 32 assert(fname);
111 int i = 0;
112 while (protocol[i] != NULL) {
113 printf("%s, ", protocol[i]);
114 i++;
115 }
116 printf("\n");
117}
118
119 33
120// check protocol list and store it in cfg structure 34 // check file
121void protocol_store(const char *prlist) { 35 struct stat s;
122 EUID_ASSERT(); 36 if (stat(fname, &s) == -1) {
123 assert(prlist); 37 fprintf(stderr, "Error: cannot read protocol filter file\n");
124 38 exit(1);
125 if (cfg.protocol && !arg_quiet) {
126 fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", prlist);
127 return;
128 } 39 }
129 40 int size = s.st_size;
130 // temporary list
131 char *tmplist = strdup(prlist);
132 if (!tmplist)
133 errExit("strdup");
134
135 // check list
136 char *token = strtok(tmplist, ",");
137 if (!token)
138 goto errout;
139
140 while (token) {
141 if (!is_protocol(token))
142 goto errout;
143 token = strtok(NULL, ",");
144 }
145 free(tmplist);
146
147 // store list
148 cfg.protocol = strdup(prlist);
149 if (!cfg.protocol)
150 errExit("strdup");
151 return;
152
153errout:
154 fprintf(stderr, "Error: invalid protocol list\n");
155 exit(1);
156}
157 41
158// install protocol filter 42 // read filter
159void protocol_filter(void) {
160 assert(cfg.protocol);
161 if (arg_debug)
162 printf("Set protocol filter: %s\n", cfg.protocol);
163
164#ifndef SYS_socket
165 (void) find_protocol_domain;
166 fprintf(stderr, "Warning: --protocol not supported on this platform\n");
167 return;
168#else
169 // build the filter
170 struct sock_filter filter[32]; // big enough 43 struct sock_filter filter[32]; // big enough
171 memset(&filter[0], 0, sizeof(filter)); 44 memset(&filter[0], 0, sizeof(filter));
172 uint8_t *ptr = (uint8_t *) &filter[0]; 45 int src = open(fname, O_RDONLY);
173 46 int rd = 0;
174 // header 47 while (rd < size) {
175 struct sock_filter filter_start[] = { 48 int rv = read(src, (unsigned char *) filter + rd, size - rd);
176 VALIDATE_ARCHITECTURE, 49 if (rv == -1) {
177 EXAMINE_SYSCALL, 50 fprintf(stderr, "Error: cannot read %s file\n", fname);
178 ONLY(SYS_socket), 51 exit(1);
179 EXAMINE_ARGUMENT(0) 52 }
180 }; 53 rd += rv;
181 memcpy(ptr, &filter_start[0], sizeof(filter_start));
182 ptr += sizeof(filter_start);
183
184#if 0
185printf("entries %u\n", (unsigned) (sizeof(filter_start) / sizeof(struct sock_filter)));
186{
187 unsigned j;
188 unsigned char *ptr2 = (unsigned char *) &filter[0];
189 for (j = 0; j < sizeof(filter); j++, ptr2++) {
190 if ((j % (sizeof(struct sock_filter))) == 0)
191 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
192 printf("%02x, ", (*ptr2) & 0xff);
193 }
194 printf("\n");
195}
196printf("whitelist_len %u, struct sock_filter len %u\n", whitelist_len, (unsigned) sizeof(struct sock_filter));
197#endif
198
199
200 // parse list and add commands
201 char *tmplist = strdup(cfg.protocol);
202 if (!tmplist)
203 errExit("strdup");
204 char *token = strtok(tmplist, ",");
205 if (!token)
206 errExit("strtok");
207
208 while (token) {
209 struct sock_filter *domain = find_protocol_domain(token);
210 assert(domain);
211 memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter));
212 ptr += whitelist_len * sizeof(struct sock_filter);
213 token = strtok(NULL, ",");
214
215#if 0
216printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
217{
218 unsigned j;
219 unsigned char *ptr2 = (unsigned char *) &filter[0];
220 for (j = 0; j < sizeof(filter); j++, ptr2++) {
221 if ((j % (sizeof(struct sock_filter))) == 0)
222 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
223 printf("%02x, ", (*ptr2) & 0xff);
224 }
225 printf("\n");
226}
227#endif
228
229
230 }
231 free(tmplist);
232
233 // add end of filter
234 struct sock_filter filter_end[] = {
235 RETURN_ERRNO(ENOTSUP)
236 };
237 memcpy(ptr, &filter_end[0], sizeof(filter_end));
238 ptr += sizeof(filter_end);
239
240#if 0
241printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
242{
243 unsigned j;
244 unsigned char *ptr2 = (unsigned char *) &filter[0];
245 for (j = 0; j < sizeof(filter); j++, ptr2++) {
246 if ((j % (sizeof(struct sock_filter))) == 0)
247 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
248 printf("%02x, ", (*ptr2) & 0xff);
249 } 54 }
250 printf("\n"); 55 close(src);
251}
252#endif
253 56
254 // install filter 57 // install filter
255 unsigned short entries = (unsigned short) ((uintptr_t) ptr - (uintptr_t) (filter)) / (unsigned) sizeof(struct sock_filter); 58 unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter);
256 struct sock_fprog prog = { 59 struct sock_fprog prog = {
257 .len = entries, 60 .len = entries,
258 .filter = filter, 61 .filter = filter,
@@ -262,7 +65,7 @@ printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (uns
262 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); 65 fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
263 return; 66 return;
264 } 67 }
265#endif // SYS_socket 68#endif
266} 69}
267 70
268void protocol_filter_save(void) { 71void protocol_filter_save(void) {
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index f5cca7494..7a63461ef 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -819,8 +819,24 @@ int sandbox(void* sandbox_arg) {
819#ifdef HAVE_SECCOMP 819#ifdef HAVE_SECCOMP
820 // install protocol filter 820 // install protocol filter
821 if (cfg.protocol) { 821 if (cfg.protocol) {
822 protocol_filter(); // install filter 822 if (arg_debug)
823 protocol_filter_save(); // save filter in PROTOCOL_CFG 823 printf("Set protocol filter: %s\n", cfg.protocol);
824 // as root, create RUN_SECCOMP_PROTOCOL file
825 // this is where fseccomp program will store the protocol filter
826 int dst = open(RUN_SECCOMP_PROTOCOL, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
827 if (dst == -1)
828 errExit("open");
829 close(dst);
830 if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1)
831 errExit("chown");
832
833 // build the seccomp filter as a regular user
834 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 5,
835 PATH_FSECCOMP, "protocol", "build", cfg.protocol, RUN_SECCOMP_PROTOCOL);
836 if (rv)
837 exit(rv);
838 protocol_filter(RUN_SECCOMP_PROTOCOL); // install filter
839 protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG
824 } 840 }
825 841
826 // if a keep list is available, disregard the drop list 842 // if a keep list is available, disregard the drop list
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c
new file mode 100644
index 000000000..d1225c3bc
--- /dev/null
+++ b/src/firejail/sbox.c
@@ -0,0 +1,181 @@
1/*
2 * Copyright (C) 2014-2016 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 <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <net/if.h>
25#include <stdarg.h>
26 #include <sys/wait.h>
27#include "../include/seccomp.h"
28
29static struct sock_filter filter[] = {
30 VALIDATE_ARCHITECTURE,
31 EXAMINE_SYSCALL,
32
33#if defined(__x86_64__)
34#define X32_SYSCALL_BIT 0x40000000
35 // handle X32 ABI
36 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0),
37 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0),
38 RETURN_ERRNO(EPERM),
39#endif
40
41 // syscall list
42#ifdef SYS_mount
43 BLACKLIST(SYS_mount), // mount/unmount filesystems
44#endif
45#ifdef SYS_umount2
46 BLACKLIST(SYS_umount2),
47#endif
48#ifdef SYS_ptrace
49 BLACKLIST(SYS_ptrace), // trace processes
50#endif
51#ifdef SYS_kexec_file_load
52 BLACKLIST(SYS_kexec_file_load),
53#endif
54#ifdef SYS_kexec_load
55 BLACKLIST(SYS_kexec_load), // loading a different kernel
56#endif
57#ifdef SYS_name_to_handle_at
58 BLACKLIST(SYS_name_to_handle_at),
59#endif
60#ifdef SYS_open_by_handle_at
61 BLACKLIST(SYS_open_by_handle_at), // open by handle
62#endif
63#ifdef SYS_init_module
64 BLACKLIST(SYS_init_module), // kernel module handling
65#endif
66#ifdef SYS_finit_module // introduced in 2013
67 BLACKLIST(SYS_finit_module),
68#endif
69#ifdef SYS_create_module
70 BLACKLIST(SYS_create_module),
71#endif
72#ifdef SYS_delete_module
73 BLACKLIST(SYS_delete_module),
74#endif
75#ifdef SYS_iopl
76 BLACKLIST(SYS_iopl), // io permissions
77#endif
78#ifdef SYS_ioperm
79 BLACKLIST(SYS_ioperm),
80#endif
81#ifdef SYS_iopl
82 BLACKLIST(SYS_iopl), // io permissions
83#endif
84#ifdef SYS_ioprio_set
85 BLACKLIST(SYS_ioprio_set),
86#endif
87#ifdef SYS_ni_syscall // new io permissions call on arm devices
88 BLACKLIST(SYS_ni_syscall),
89#endif
90#ifdef SYS_swapon
91 BLACKLIST(SYS_swapon), // swap on/off
92#endif
93#ifdef SYS_swapoff
94 BLACKLIST(SYS_swapoff),
95#endif
96#ifdef SYS_syslog
97 BLACKLIST(SYS_syslog), // kernel printk control
98#endif
99 RETURN_ALLOW
100};
101
102static struct sock_fprog prog = {
103 .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
104 .filter = filter,
105};
106
107typedef struct sbox_config {
108 char *name;
109 char *path;
110 unsigned filters;
111} SboxConfig;
112
113
114int sbox_run(unsigned filter, int num, ...) {
115 EUID_ROOT();
116
117 int i;
118 va_list valist;
119 va_start(valist, num);
120
121 // build argument list
122 char *arg[num + 1];
123 for (i = 0; i < num; i++)
124 arg[i] = va_arg(valist, char*);
125 arg[i] = NULL;
126 va_end(valist);
127
128//#if 0
129{
130int i;
131for (i = 0; i <= num; i++)
132 printf("#%s# ", arg[i]);
133printf("\n");
134}
135//#endif
136 pid_t child = fork();
137 if (child < 0)
138 errExit("fork");
139 if (child == 0) {
140 // apply filters
141 if (filter & SBOX_CAPS)
142 caps_drop_all();
143
144 if (filter & SBOX_SECCOMP) {
145 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
146 perror("prctl(NO_NEW_PRIVS)");
147 }
148 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
149 perror("prctl(PR_SET_SECCOMP)");
150 }
151 }
152
153 if (filter & SBOX_ROOT) {
154 // elevate privileges in order to get grsecurity working
155 if (setreuid(0, 0))
156 errExit("setreuid");
157 if (setregid(0, 0))
158 errExit("setregid");
159 }
160 else if (filter & SBOX_USER)
161 drop_privs(1);
162
163 if (arg[0]) // get rid of scan-build warning
164 execvp(arg[0], arg);
165 else
166 assert(0);
167 perror("execl");
168 _exit(1);
169 }
170
171 int status;
172 if (waitpid(child, &status, 0) == -1 ) {
173 errExit("waitpid");
174 }
175 if (WIFEXITED(status) && status != 0) {
176 fprintf(stderr, "Error: failed to run %s\n", arg[0]);
177 exit(1);
178 }
179
180 return status;
181}
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index 549359d94..09862ec20 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -20,7 +20,7 @@
20 20
21#ifdef HAVE_SECCOMP 21#ifdef HAVE_SECCOMP
22#include "firejail.h" 22#include "firejail.h"
23#include "seccomp.h" 23#include "../include/seccomp.h"
24 24
25#define SECSIZE 128 // initial filter size 25#define SECSIZE 128 // initial filter size
26static struct sock_filter *sfilter = NULL; 26static struct sock_filter *sfilter = NULL;
diff --git a/src/firejail/syscall.c b/src/firejail/syscall.c
index 985cc8bb8..f405f23c8 100644
--- a/src/firejail/syscall.c
+++ b/src/firejail/syscall.c
@@ -31,7 +31,7 @@ static SyscallEntry syslist[] = {
31// 31//
32// code generated using tools/extract-syscall 32// code generated using tools/extract-syscall
33// 33//
34#include "syscall.h" 34#include "../include/syscall.h"
35// 35//
36// end of generated code 36// end of generated code
37// 37//
@@ -102,15 +102,4 @@ int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg)
102 return 0; 102 return 0;
103} 103}
104 104
105void syscall_print(void) {
106 EUID_ASSERT();
107
108 int i;
109 int elems = sizeof(syslist) / sizeof(syslist[0]);
110 for (i = 0; i < elems; i++) {
111 printf("%d\t- %s\n", syslist[i].nr, syslist[i].name);
112 }
113 printf("\n");
114}
115
116#endif // HAVE_SECCOMP 105#endif // HAVE_SECCOMP
diff --git a/src/firejail/util.c b/src/firejail/util.c
index f38b02fd0..4b2e09953 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -171,11 +171,17 @@ void logerr(const char *msg) {
171} 171}
172 172
173 173
174// return -1 if error, 0 if no error 174// return -1 if error, 0 if no error; if destname already exists, return error
175int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { 175int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) {
176 assert(srcname); 176 assert(srcname);
177 assert(destname); 177 assert(destname);
178 178
179 struct stat s;
180 if (stat(destname, &s) == 0) {
181 fprintf(stderr, "Error: file %s already exists\n", destname);
182 return -1;
183 }
184
179 // open source 185 // open source
180 int src = open(srcname, O_RDONLY); 186 int src = open(srcname, O_RDONLY);
181 if (src < 0) { 187 if (src < 0) {
diff --git a/src/fnet/Makefile.in b/src/fnet/Makefile.in
new file mode 100644
index 000000000..1bfb4c68d
--- /dev/null
+++ b/src/fnet/Makefile.in
@@ -0,0 +1,43 @@
1all: fnet
2
3prefix=@prefix@
4exec_prefix=@exec_prefix@
5libdir=@libdir@
6sysconfdir=@sysconfdir@
7
8VERSION=@PACKAGE_VERSION@
9NAME=@PACKAGE_NAME@
10HAVE_SECCOMP_H=@HAVE_SECCOMP_H@
11HAVE_SECCOMP=@HAVE_SECCOMP@
12HAVE_CHROOT=@HAVE_CHROOT@
13HAVE_BIND=@HAVE_BIND@
14HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
15HAVE_NETWORK=@HAVE_NETWORK@
16HAVE_USERNS=@HAVE_USERNS@
17HAVE_X11=@HAVE_X11@
18HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@
19HAVE_WHITELIST=@HAVE_WHITELIST@
20HAVE_GLOBALCFG=@HAVE_GLOBALCFG@
21HAVE_APPARMOR=@HAVE_APPARMOR@
22HAVE_OVERLAYFS=@HAVE_OVERLAYFS@
23HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@
24EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
25
26H_FILE_LIST = $(sort $(wildcard *.[h]))
27C_FILE_LIST = $(sort $(wildcard *.c))
28OBJS = $(C_FILE_LIST:.c=.o)
29BINOBJS = $(foreach file, $(OBJS), $file)
30CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
31LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
32
33%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h
34 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
35
36fnet: $(OBJS) ../lib/libnetlink.o ../lib/common.o
37 $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS)
38
39clean:; rm -f *.o fnet
40
41distclean: clean
42 rm -fr Makefile
43
diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h
new file mode 100644
index 000000000..58efbbed5
--- /dev/null
+++ b/src/fnet/fnet.h
@@ -0,0 +1,40 @@
1 /*
2 * Copyright (C) 2014-2016 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#ifndef FNET_H
21#define FNET_H
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <assert.h>
27#include "../include/common.h"
28
29// veth.c
30int net_create_veth(const char *dev, const char *nsdev, unsigned pid);
31int net_create_macvlan(const char *dev, const char *parent, unsigned pid);
32int net_move_interface(const char *dev, unsigned pid);
33
34// interface.c
35void net_bridge_add_interface(const char *bridge, const char *dev);
36void net_if_up(const char *ifname);
37int net_get_mtu(const char *ifname);
38void net_set_mtu(const char *ifname, int mtu);
39
40#endif
diff --git a/src/fnet/interface.c b/src/fnet/interface.c
new file mode 100644
index 000000000..b1903dd46
--- /dev/null
+++ b/src/fnet/interface.c
@@ -0,0 +1,183 @@
1 /*
2 * Copyright (C) 2014-2016 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
21#include "fnet.h"
22#include <arpa/inet.h>
23#include <sys/socket.h>
24#include <sys/ioctl.h>
25#include <netdb.h>
26#include <ifaddrs.h>
27#include <net/if.h>
28#include <net/if_arp.h>
29#include <net/route.h>
30#include <linux/if_bridge.h>
31
32// add a veth device to a bridge
33void net_bridge_add_interface(const char *bridge, const char *dev) {
34 if (strlen(bridge) > IFNAMSIZ) {
35 fprintf(stderr, "Error fnet: invalid network device name %s\n", bridge);
36 exit(1);
37 }
38
39 // somehow adding the interface to the bridge resets MTU on bridge device!!!
40 // workaround: restore MTU on the bridge device
41 // todo: put a real fix in
42 int mtu1 = net_get_mtu(bridge);
43
44 struct ifreq ifr;
45 int err;
46 int ifindex = if_nametoindex(dev);
47
48 if (ifindex <= 0)
49 errExit("if_nametoindex");
50
51 int sock;
52 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
53 errExit("socket");
54
55 memset(&ifr, 0, sizeof(ifr));
56 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
57#ifdef SIOCBRADDIF
58 ifr.ifr_ifindex = ifindex;
59 err = ioctl(sock, SIOCBRADDIF, &ifr);
60 if (err < 0)
61#endif
62 {
63 unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 };
64
65 ifr.ifr_data = (char *) args;
66 err = ioctl(sock, SIOCDEVPRIVATE, &ifr);
67 }
68 (void) err;
69 close(sock);
70
71 int mtu2 = net_get_mtu(bridge);
72 if (mtu1 != mtu2) {
73 net_set_mtu(bridge, mtu1);
74 }
75}
76
77
78// bring interface up
79void net_if_up(const char *ifname) {
80 if (strlen(ifname) > IFNAMSIZ) {
81 fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname);
82 exit(1);
83 }
84
85 int sock = socket(AF_INET,SOCK_DGRAM,0);
86 if (sock < 0)
87 errExit("socket");
88
89 // get the existing interface flags
90 struct ifreq ifr;
91 memset(&ifr, 0, sizeof(ifr));
92 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
93 ifr.ifr_addr.sa_family = AF_INET;
94
95 // read the existing flags
96 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
97 close(sock);
98 printf("Error fnet: cannot bring up interface %s\n", ifname);
99 errExit("ioctl");
100 }
101
102 ifr.ifr_flags |= IFF_UP;
103
104 // set the new flags
105 if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) {
106 close(sock);
107 printf("Error fnet: cannot bring up interface %s\n", ifname);
108 errExit("ioctl");
109 }
110
111 // checking
112 // read the existing flags
113 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
114 close(sock);
115 printf("Error fnet: cannot bring up interface %s\n", ifname);
116 errExit("ioctl");
117 }
118
119 // wait not more than 500ms for the interface to come up
120 int cnt = 0;
121 while (cnt < 50) {
122 usleep(10000); // sleep 10ms
123
124 // read the existing flags
125 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
126 close(sock);
127 printf("Error fnet: cannot bring up interface %s\n", ifname);
128 errExit("ioctl");
129 }
130 if (ifr.ifr_flags & IFF_RUNNING)
131 break;
132 cnt++;
133 }
134
135 close(sock);
136}
137
138int net_get_mtu(const char *ifname) {
139 int mtu = 0;
140 if (strlen(ifname) > IFNAMSIZ) {
141 fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname);
142 exit(1);
143 }
144
145 int s;
146 struct ifreq ifr;
147
148 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
149 errExit("socket");
150
151 memset(&ifr, 0, sizeof(ifr));
152 ifr.ifr_addr.sa_family = AF_INET;
153 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
154 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0)
155 mtu = ifr.ifr_mtu;
156 close(s);
157
158
159 return mtu;
160}
161
162void net_set_mtu(const char *ifname, int mtu) {
163 if (strlen(ifname) > IFNAMSIZ) {
164 fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname);
165 exit(1);
166 }
167
168 int s;
169 struct ifreq ifr;
170
171 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
172 errExit("socket");
173
174 memset(&ifr, 0, sizeof(ifr));
175 ifr.ifr_addr.sa_family = AF_INET;
176 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
177 ifr.ifr_mtu = mtu;
178 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0)
179 fprintf(stderr, "Warning fnet: cannot set mtu for interface %s\n", ifname);
180 close(s);
181}
182
183
diff --git a/src/fnet/main.c b/src/fnet/main.c
new file mode 100644
index 000000000..f17287cb9
--- /dev/null
+++ b/src/fnet/main.c
@@ -0,0 +1,70 @@
1 /*
2 * Copyright (C) 2014-2016 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 "fnet.h"
21
22static void usage(void) {
23 printf("Usage:\n");
24 printf("\tfnet create veth dev1 dev2 bridge child\n");
25 printf("\tfnet create macvlan dev parent child\n");
26 printf("\tfnet moveif dev proc\n");
27}
28
29int main(int argc, char **argv) {
30#if 0
31{
32system("cat /proc/self/status");
33int i;
34for (i = 0; i < argc; i++)
35 printf("*%s* ", argv[i]);
36printf("\n");
37}
38#endif
39 if (argc < 2)
40 return 1;
41
42
43
44 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
45 usage();
46 return 0;
47 }
48 else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) {
49 // create veth pair and move one end in the the namespace
50 net_create_veth(argv[3], argv[4], atoi(argv[6]));
51
52 // connect the ohter veth end to the bridge ...
53 net_bridge_add_interface(argv[5], argv[3]);
54
55 // ... and bring it up
56 net_if_up(argv[3]);
57 }
58 else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) {
59 net_create_macvlan(argv[3], argv[4], atoi(argv[5]));
60 }
61 else if (argc == 4 && strcmp(argv[1], "moveif") == 0) {
62 net_move_interface(argv[2], atoi(argv[3]));
63 }
64 else {
65 fprintf(stderr, "Error fnet: invalid arguments\n");
66 return 1;
67 }
68
69 return 0;
70}
diff --git a/src/firejail/veth.c b/src/fnet/veth.c
index df3c1d1f9..d06bc9256 100644
--- a/src/firejail/veth.c
+++ b/src/fnet/veth.c
@@ -45,7 +45,7 @@
45 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 45 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
46*/ 46*/
47 47
48#include "firejail.h" 48#include "fnet.h"
49#include "../include/libnetlink.h" 49#include "../include/libnetlink.h"
50#include <linux/veth.h> 50#include <linux/veth.h>
51#include <net/if.h> 51#include <net/if.h>
@@ -63,8 +63,6 @@ int net_create_veth(const char *dev, const char *nsdev, unsigned pid) {
63 int len; 63 int len;
64 struct iplink_req req; 64 struct iplink_req req;
65 65
66 if (arg_debug)
67 printf("create veth %s/%s/%u\n", dev, nsdev, pid);
68 assert(dev); 66 assert(dev);
69 assert(nsdev); 67 assert(nsdev);
70 assert(pid); 68 assert(pid);
@@ -120,8 +118,6 @@ int net_create_veth(const char *dev, const char *nsdev, unsigned pid) {
120int net_create_macvlan(const char *dev, const char *parent, unsigned pid) { 118int net_create_macvlan(const char *dev, const char *parent, unsigned pid) {
121 int len; 119 int len;
122 struct iplink_req req; 120 struct iplink_req req;
123 if (arg_debug)
124 printf("create macvlan %s, parent %s\n", dev, parent);
125 assert(dev); 121 assert(dev);
126 assert(parent); 122 assert(parent);
127 123
@@ -184,8 +180,6 @@ int net_create_macvlan(const char *dev, const char *parent, unsigned pid) {
184// when the interface is moved, netlink does not preserve interface configuration 180// when the interface is moved, netlink does not preserve interface configuration
185int net_move_interface(const char *dev, unsigned pid) { 181int net_move_interface(const char *dev, unsigned pid) {
186 struct iplink_req req; 182 struct iplink_req req;
187 if (arg_debug)
188 printf("move device %s inside the namespace\n", dev);
189 assert(dev); 183 assert(dev);
190 184
191 if (rtnl_open(&rth, 0) < 0) { 185 if (rtnl_open(&rth, 0) < 0) {
diff --git a/src/fseccomp/Makefile.in b/src/fseccomp/Makefile.in
new file mode 100644
index 000000000..e7edd1b8f
--- /dev/null
+++ b/src/fseccomp/Makefile.in
@@ -0,0 +1,43 @@
1all: fseccomp
2
3prefix=@prefix@
4exec_prefix=@exec_prefix@
5libdir=@libdir@
6sysconfdir=@sysconfdir@
7
8VERSION=@PACKAGE_VERSION@
9NAME=@PACKAGE_NAME@
10HAVE_SECCOMP_H=@HAVE_SECCOMP_H@
11HAVE_SECCOMP=@HAVE_SECCOMP@
12HAVE_CHROOT=@HAVE_CHROOT@
13HAVE_BIND=@HAVE_BIND@
14HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
15HAVE_NETWORK=@HAVE_NETWORK@
16HAVE_USERNS=@HAVE_USERNS@
17HAVE_X11=@HAVE_X11@
18HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@
19HAVE_WHITELIST=@HAVE_WHITELIST@
20HAVE_GLOBALCFG=@HAVE_GLOBALCFG@
21HAVE_APPARMOR=@HAVE_APPARMOR@
22HAVE_OVERLAYFS=@HAVE_OVERLAYFS@
23HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@
24EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
25
26H_FILE_LIST = $(sort $(wildcard *.[h]))
27C_FILE_LIST = $(sort $(wildcard *.c))
28OBJS = $(C_FILE_LIST:.c=.o)
29BINOBJS = $(foreach file, $(OBJS), $file)
30CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
31LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
32
33%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h ../include/syscall.h
34 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
35
36fseccomp: $(OBJS) ../lib/libnetlink.o ../lib/common.o
37 $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS)
38
39clean:; rm -f *.o fseccomp
40
41distclean: clean
42 rm -fr Makefile
43
diff --git a/src/fseccomp/errno.c b/src/fseccomp/errno.c
new file mode 100644
index 000000000..625f484bd
--- /dev/null
+++ b/src/fseccomp/errno.c
@@ -0,0 +1,161 @@
1#include "fseccomp.h"
2
3#include <errno.h>
4//#include <attr/xattr.h>
5
6typedef struct {
7 char *name;
8 int nr;
9} ErrnoEntry;
10
11static ErrnoEntry errnolist[] = {
12//
13// code generated using tools/extract-errnos
14//
15 {"EPERM", EPERM},
16 {"ENOENT", ENOENT},
17 {"ESRCH", ESRCH},
18 {"EINTR", EINTR},
19 {"EIO", EIO},
20 {"ENXIO", ENXIO},
21 {"E2BIG", E2BIG},
22 {"ENOEXEC", ENOEXEC},
23 {"EBADF", EBADF},
24 {"ECHILD", ECHILD},
25 {"EAGAIN", EAGAIN},
26 {"ENOMEM", ENOMEM},
27 {"EACCES", EACCES},
28 {"EFAULT", EFAULT},
29 {"ENOTBLK", ENOTBLK},
30 {"EBUSY", EBUSY},
31 {"EEXIST", EEXIST},
32 {"EXDEV", EXDEV},
33 {"ENODEV", ENODEV},
34 {"ENOTDIR", ENOTDIR},
35 {"EISDIR", EISDIR},
36 {"EINVAL", EINVAL},
37 {"ENFILE", ENFILE},
38 {"EMFILE", EMFILE},
39 {"ENOTTY", ENOTTY},
40 {"ETXTBSY", ETXTBSY},
41 {"EFBIG", EFBIG},
42 {"ENOSPC", ENOSPC},
43 {"ESPIPE", ESPIPE},
44 {"EROFS", EROFS},
45 {"EMLINK", EMLINK},
46 {"EPIPE", EPIPE},
47 {"EDOM", EDOM},
48 {"ERANGE", ERANGE},
49 {"EDEADLK", EDEADLK},
50 {"ENAMETOOLONG", ENAMETOOLONG},
51 {"ENOLCK", ENOLCK},
52 {"ENOSYS", ENOSYS},
53 {"ENOTEMPTY", ENOTEMPTY},
54 {"ELOOP", ELOOP},
55 {"EWOULDBLOCK", EWOULDBLOCK},
56 {"ENOMSG", ENOMSG},
57 {"EIDRM", EIDRM},
58 {"ECHRNG", ECHRNG},
59 {"EL2NSYNC", EL2NSYNC},
60 {"EL3HLT", EL3HLT},
61 {"EL3RST", EL3RST},
62 {"ELNRNG", ELNRNG},
63 {"EUNATCH", EUNATCH},
64 {"ENOCSI", ENOCSI},
65 {"EL2HLT", EL2HLT},
66 {"EBADE", EBADE},
67 {"EBADR", EBADR},
68 {"EXFULL", EXFULL},
69 {"ENOANO", ENOANO},
70 {"EBADRQC", EBADRQC},
71 {"EBADSLT", EBADSLT},
72 {"EDEADLOCK", EDEADLOCK},
73 {"EBFONT", EBFONT},
74 {"ENOSTR", ENOSTR},
75 {"ENODATA", ENODATA},
76 {"ETIME", ETIME},
77 {"ENOSR", ENOSR},
78 {"ENONET", ENONET},
79 {"ENOPKG", ENOPKG},
80 {"EREMOTE", EREMOTE},
81 {"ENOLINK", ENOLINK},
82 {"EADV", EADV},
83 {"ESRMNT", ESRMNT},
84 {"ECOMM", ECOMM},
85 {"EPROTO", EPROTO},
86 {"EMULTIHOP", EMULTIHOP},
87 {"EDOTDOT", EDOTDOT},
88 {"EBADMSG", EBADMSG},
89 {"EOVERFLOW", EOVERFLOW},
90 {"ENOTUNIQ", ENOTUNIQ},
91 {"EBADFD", EBADFD},
92 {"EREMCHG", EREMCHG},
93 {"ELIBACC", ELIBACC},
94 {"ELIBBAD", ELIBBAD},
95 {"ELIBSCN", ELIBSCN},
96 {"ELIBMAX", ELIBMAX},
97 {"ELIBEXEC", ELIBEXEC},
98 {"EILSEQ", EILSEQ},
99 {"ERESTART", ERESTART},
100 {"ESTRPIPE", ESTRPIPE},
101 {"EUSERS", EUSERS},
102 {"ENOTSOCK", ENOTSOCK},
103 {"EDESTADDRREQ", EDESTADDRREQ},
104 {"EMSGSIZE", EMSGSIZE},
105 {"EPROTOTYPE", EPROTOTYPE},
106 {"ENOPROTOOPT", ENOPROTOOPT},
107 {"EPROTONOSUPPORT", EPROTONOSUPPORT},
108 {"ESOCKTNOSUPPORT", ESOCKTNOSUPPORT},
109 {"EOPNOTSUPP", EOPNOTSUPP},
110 {"EPFNOSUPPORT", EPFNOSUPPORT},
111 {"EAFNOSUPPORT", EAFNOSUPPORT},
112 {"EADDRINUSE", EADDRINUSE},
113 {"EADDRNOTAVAIL", EADDRNOTAVAIL},
114 {"ENETDOWN", ENETDOWN},
115 {"ENETUNREACH", ENETUNREACH},
116 {"ENETRESET", ENETRESET},
117 {"ECONNABORTED", ECONNABORTED},
118 {"ECONNRESET", ECONNRESET},
119 {"ENOBUFS", ENOBUFS},
120 {"EISCONN", EISCONN},
121 {"ENOTCONN", ENOTCONN},
122 {"ESHUTDOWN", ESHUTDOWN},
123 {"ETOOMANYREFS", ETOOMANYREFS},
124 {"ETIMEDOUT", ETIMEDOUT},
125 {"ECONNREFUSED", ECONNREFUSED},
126 {"EHOSTDOWN", EHOSTDOWN},
127 {"EHOSTUNREACH", EHOSTUNREACH},
128 {"EALREADY", EALREADY},
129 {"EINPROGRESS", EINPROGRESS},
130 {"ESTALE", ESTALE},
131 {"EUCLEAN", EUCLEAN},
132 {"ENOTNAM", ENOTNAM},
133 {"ENAVAIL", ENAVAIL},
134 {"EISNAM", EISNAM},
135 {"EREMOTEIO", EREMOTEIO},
136 {"EDQUOT", EDQUOT},
137 {"ENOMEDIUM", ENOMEDIUM},
138 {"EMEDIUMTYPE", EMEDIUMTYPE},
139 {"ECANCELED", ECANCELED},
140 {"ENOKEY", ENOKEY},
141 {"EKEYEXPIRED", EKEYEXPIRED},
142 {"EKEYREVOKED", EKEYREVOKED},
143 {"EKEYREJECTED", EKEYREJECTED},
144 {"EOWNERDEAD", EOWNERDEAD},
145 {"ENOTRECOVERABLE", ENOTRECOVERABLE},
146 {"ERFKILL", ERFKILL},
147 {"EHWPOISON", EHWPOISON},
148 {"ENOTSUP", ENOTSUP},
149#ifdef ENOATTR
150 {"ENOATTR", ENOATTR},
151#endif
152};
153
154void errno_print(void) {
155 int i;
156 int elems = sizeof(errnolist) / sizeof(errnolist[0]);
157 for (i = 0; i < elems; i++) {
158 printf("%d\t- %s\n", errnolist[i].nr, errnolist[i].name);
159 }
160 printf("\n");
161}
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h
new file mode 100644
index 000000000..57757ea6c
--- /dev/null
+++ b/src/fseccomp/fseccomp.h
@@ -0,0 +1,18 @@
1#ifndef FSECCOMP_H
2#define FSECCOMP_H
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <assert.h>
7#include "../include/common.h"
8
9// syscall.c
10void syscall_print(void);
11
12// errno.c
13void errno_print(void);
14
15// protocol.c
16void protocol_print(void);
17void protocol_build_filter(const char *prlist, const char *fname);
18#endif
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c
new file mode 100644
index 000000000..59d426a78
--- /dev/null
+++ b/src/fseccomp/main.c
@@ -0,0 +1,42 @@
1#include "fseccomp.h"
2
3static void usage(void) {
4 printf("Usage:\n");
5 printf("\tfseccomp debug-syscalls\n");
6 printf("\tfseccomp debug-errnos\n");
7 printf("\tfseccomp debug-protocols\n");
8 printf("\tfseccomp protocol build list file\n");
9}
10
11int main(int argc, char **argv) {
12//#if 0
13{
14//system("cat /proc/self/status");
15int i;
16for (i = 0; i < argc; i++)
17 printf("*%s* ", argv[i]);
18printf("\n");
19}
20//#endif
21 if (argc < 2)
22 return 1;
23
24 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
25 usage();
26 return 0;
27 }
28 else if (argc == 2 && strcmp(argv[1], "debug-syscalls") == 0)
29 syscall_print();
30 else if (argc == 2 && strcmp(argv[1], "debug-errnos") == 0)
31 errno_print();
32 else if (argc == 2 && strcmp(argv[1], "debug-protocols") == 0)
33 protocol_print();
34 else if (argc == 5 && strcmp(argv[1], "protocol") == 0 && strcmp(argv[2], "build") == 0)
35 protocol_build_filter(argv[3], argv[4]);
36 else {
37 fprintf(stderr, "Error fseccomp: invalid arguments\n");
38 return 1;
39 }
40
41 return 0;
42} \ No newline at end of file
diff --git a/src/fseccomp/protocol.c b/src/fseccomp/protocol.c
new file mode 100644
index 000000000..38c5f9d88
--- /dev/null
+++ b/src/fseccomp/protocol.c
@@ -0,0 +1,219 @@
1/*
2 * Copyright (C) 2014-2016 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
21/*
22 struct sock_filter filter[] = {
23 VALIDATE_ARCHITECTURE,
24 EXAMINE_SYSCALL,
25 ONLY(SYS_socket),
26 EXAMINE_ARGUMENT(0), // allow only AF_INET and AF_INET6, drop everything else
27 WHITELIST(AF_INET),
28 WHITELIST(AF_INET6),
29 WHITELIST(AF_PACKET),
30 RETURN_ERRNO(ENOTSUP)
31 };
32 struct sock_fprog prog = {
33 .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
34 .filter = filter,
35 };
36
37
38 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
39 perror("prctl(NO_NEW_PRIVS)");
40 return 1;
41 }
42 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
43 perror("prctl");
44 return 1;
45 }
46*/
47
48#include "fseccomp.h"
49#include "../include/seccomp.h"
50#include <sys/syscall.h>
51#include <sys/types.h>
52#include <sys/socket.h>
53
54static char *protocol[] = {
55 "unix",
56 "inet",
57 "inet6",
58 "netlink",
59 "packet",
60 NULL
61};
62
63static struct sock_filter protocol_filter_command[] = {
64 WHITELIST(AF_UNIX),
65 WHITELIST(AF_INET),
66 WHITELIST(AF_INET6),
67 WHITELIST(AF_NETLINK),
68 WHITELIST(AF_PACKET)
69};
70// Note: protocol[] and protocol_filter_command are synchronized
71
72// command length
73struct sock_filter whitelist[] = {
74 WHITELIST(AF_UNIX)
75};
76unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter);
77
78static struct sock_filter *find_protocol_domain(const char *p) {
79 int i = 0;
80 while (protocol[i] != NULL) {
81 if (strcmp(protocol[i], p) == 0)
82 return &protocol_filter_command[i * whitelist_len];
83 i++;
84 }
85
86 return NULL;
87}
88
89
90void protocol_print(void) {
91#ifndef SYS_socket
92 fprintf(stderr, "Warning fseccomp: firejail --protocol not supported on this platform\n");
93 return;
94#endif
95
96 int i = 0;
97 while (protocol[i] != NULL) {
98 printf("%s, ", protocol[i]);
99 i++;
100 }
101 printf("\n");
102}
103
104// install protocol filter
105void protocol_build_filter(const char *prlist, const char *fname) {
106 assert(prlist);
107 assert(fname);
108
109#ifndef SYS_socket
110 fprintf(stderr, "Warning: --protocol not supported on this platform\n");
111 return;
112#else
113 // build the filter
114 struct sock_filter filter[32]; // big enough
115 memset(&filter[0], 0, sizeof(filter));
116 uint8_t *ptr = (uint8_t *) &filter[0];
117
118 // header
119 struct sock_filter filter_start[] = {
120 VALIDATE_ARCHITECTURE,
121 EXAMINE_SYSCALL,
122 ONLY(SYS_socket),
123 EXAMINE_ARGUMENT(0)
124 };
125 memcpy(ptr, &filter_start[0], sizeof(filter_start));
126 ptr += sizeof(filter_start);
127
128#if 0
129printf("entries %u\n", (unsigned) (sizeof(filter_start) / sizeof(struct sock_filter)));
130{
131 unsigned j;
132 unsigned char *ptr2 = (unsigned char *) &filter[0];
133 for (j = 0; j < sizeof(filter); j++, ptr2++) {
134 if ((j % (sizeof(struct sock_filter))) == 0)
135 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
136 printf("%02x, ", (*ptr2) & 0xff);
137 }
138 printf("\n");
139}
140printf("whitelist_len %u, struct sock_filter len %u\n", whitelist_len, (unsigned) sizeof(struct sock_filter));
141#endif
142
143
144 // parse list and add commands
145 char *tmplist = strdup(prlist);
146 if (!tmplist)
147 errExit("strdup");
148 char *token = strtok(tmplist, ",");
149 if (!token)
150 errExit("strtok");
151
152 while (token) {
153 struct sock_filter *domain = find_protocol_domain(token);
154 if (domain == NULL) {
155 fprintf(stderr, "Error fseccomp: %s is not a valid protocol\n", token);
156 exit(1);
157 }
158 memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter));
159 ptr += whitelist_len * sizeof(struct sock_filter);
160 token = strtok(NULL, ",");
161
162#if 0
163printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
164{
165 unsigned j;
166 unsigned char *ptr2 = (unsigned char *) &filter[0];
167 for (j = 0; j < sizeof(filter); j++, ptr2++) {
168 if ((j % (sizeof(struct sock_filter))) == 0)
169 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
170 printf("%02x, ", (*ptr2) & 0xff);
171 }
172 printf("\n");
173}
174#endif
175
176
177 }
178 free(tmplist);
179
180 // add end of filter
181 struct sock_filter filter_end[] = {
182 RETURN_ERRNO(ENOTSUP)
183 };
184 memcpy(ptr, &filter_end[0], sizeof(filter_end));
185 ptr += sizeof(filter_end);
186
187#if 0
188printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
189{
190 unsigned j;
191 unsigned char *ptr2 = (unsigned char *) &filter[0];
192 for (j = 0; j < sizeof(filter); j++, ptr2++) {
193 if ((j % (sizeof(struct sock_filter))) == 0)
194 printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
195 printf("%02x, ", (*ptr2) & 0xff);
196 }
197 printf("\n");
198}
199#endif
200 // save filter to file
201 int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
202 if (dst < 0) {
203 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
204 exit(1);
205 }
206
207 int size = (int) ((uintptr_t) ptr - (uintptr_t) (filter));
208 int written = 0;
209 while (written < size) {
210 int rv = write(dst, (unsigned char *) filter + written, size - written);
211 if (rv == -1) {
212 fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname);
213 exit(1);
214 }
215 written += rv;
216 }
217 close(dst);
218#endif // SYS_socket
219}
diff --git a/src/fseccomp/syscall.c b/src/fseccomp/syscall.c
new file mode 100644
index 000000000..c67d45598
--- /dev/null
+++ b/src/fseccomp/syscall.c
@@ -0,0 +1,26 @@
1#include "fseccomp.h"
2#include <sys/syscall.h>
3
4typedef struct {
5 char *name;
6 int nr;
7} SyscallEntry;
8
9static SyscallEntry syslist[] = {
10//
11// code generated using tools/extract-syscall
12//
13#include "../include/syscall.h"
14//
15// end of generated code
16//
17}; // end of syslist
18
19void syscall_print(void) {
20 int i;
21 int elems = sizeof(syslist) / sizeof(syslist[0]);
22 for (i = 0; i < elems; i++) {
23 printf("%d\t- %s\n", syslist[i].nr, syslist[i].name);
24 }
25 printf("\n");
26}
diff --git a/src/firejail/seccomp.h b/src/include/seccomp.h
index 7d646dd9e..7d646dd9e 100644
--- a/src/firejail/seccomp.h
+++ b/src/include/seccomp.h
diff --git a/src/firejail/syscall.h b/src/include/syscall.h
index 68d4b5736..9a29779c9 100644
--- a/src/firejail/syscall.h
+++ b/src/include/syscall.h
@@ -20,7 +20,6 @@
20 20
21// content extracted from /bits/syscall.h file form glibc 2.22 21// content extracted from /bits/syscall.h file form glibc 2.22
22// using ../tools/extract_syscall tool 22// using ../tools/extract_syscall tool
23
24#if !defined __x86_64__ 23#if !defined __x86_64__
25#ifdef SYS__llseek 24#ifdef SYS__llseek
26#ifdef __NR__llseek 25#ifdef __NR__llseek