aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Topi Miettinen <toiwoton@gmail.com>2017-08-19 23:22:38 +0300
committerLibravatar Topi Miettinen <toiwoton@gmail.com>2017-08-19 23:33:11 +0300
commitd01216de45884300c87e7d3ccb70e53ebb461449 (patch)
tree480519f5849df4c6048a7f62ec97f96e51174c3e
parentMerge update after #1483 (diff)
downloadfirejail-d01216de45884300c87e7d3ccb70e53ebb461449.tar.gz
firejail-d01216de45884300c87e7d3ccb70e53ebb461449.tar.zst
firejail-d01216de45884300c87e7d3ccb70e53ebb461449.zip
Feature: switch/config option to block secondary architectures
Add a feature for a new (opt-in) command line switch and config file option to block secondary architectures entirely. Also block changing Linux execution domain with personality() system call for the primary architecture. Closes #1479
-rw-r--r--.gitignore1
-rw-r--r--Makefile.in6
-rw-r--r--src/firejail/firejail.h5
-rw-r--r--src/firejail/main.c12
-rw-r--r--src/firejail/preproc.c10
-rw-r--r--src/firejail/profile.c10
-rw-r--r--src/firejail/seccomp.c35
-rw-r--r--src/fseccomp/fseccomp.h1
-rw-r--r--src/fseccomp/main.c3
-rw-r--r--src/fseccomp/seccomp_print.c19
-rw-r--r--src/fseccomp/seccomp_secondary.c97
-rw-r--r--src/include/seccomp.h9
-rw-r--r--src/man/firejail-profile.txt4
-rw-r--r--src/man/firejail.txt15
14 files changed, 178 insertions, 49 deletions
diff --git a/.gitignore b/.gitignore
index 3ed76f776..30793847c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,4 +30,5 @@ seccomp
30seccomp.debug 30seccomp.debug
31seccomp.i386 31seccomp.i386
32seccomp.amd64 32seccomp.amd64
33seccomp.block_secondary
33seccomp.mdwx 34seccomp.mdwx
diff --git a/Makefile.in b/Makefile.in
index af30d860e..442766e27 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -2,7 +2,7 @@ all: apps man filters
2MYLIBS = src/lib 2MYLIBS = src/lib
3APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy src/fldd src/libpostexecseccomp 3APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/fnet src/fseccomp src/fcopy src/fldd src/libpostexecseccomp
4MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 4MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5
5SECCOMP_FILTERS = seccomp seccomp.i386 seccomp.amd64 5SECCOMP_FILTERS = seccomp seccomp.debug seccomp.i386 seccomp.amd64 seccomp.block_secondary seccomp.mwdx
6 6
7prefix=@prefix@ 7prefix=@prefix@
8exec_prefix=@exec_prefix@ 8exec_prefix=@exec_prefix@
@@ -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 secondary block seccomp.block_secondary
48 src/fseccomp/fseccomp memory-deny-write-execute seccomp.mdwx 49 src/fseccomp/fseccomp memory-deny-write-execute seccomp.mdwx
49endif 50endif
50 51
@@ -53,7 +54,7 @@ clean:
53 $(MAKE) -C $$dir clean; \ 54 $(MAKE) -C $$dir clean; \
54 done 55 done
55 rm -f $(MANPAGES) $(MANPAGES:%=%.gz) firejail*.rpm 56 rm -f $(MANPAGES) $(MANPAGES:%=%.gz) firejail*.rpm
56 rm -f seccomp seccomp.debug seccomp.i386 seccomp.amd64 seccomp.mdwx 57 rm -f $(SECCOMP_FILTERS)
57 rm -f test/utils/index.html* 58 rm -f test/utils/index.html*
58 rm -f test/utils/wget-log 59 rm -f test/utils/wget-log
59 rm -f test/utils/lstesting 60 rm -f test/utils/lstesting
@@ -104,6 +105,7 @@ ifeq ($(HAVE_SECCOMP),-DHAVE_SECCOMP)
104 install -c -m 0644 seccomp.debug $(DESTDIR)/$(libdir)/firejail/. 105 install -c -m 0644 seccomp.debug $(DESTDIR)/$(libdir)/firejail/.
105 install -c -m 0644 seccomp.i386 $(DESTDIR)/$(libdir)/firejail/. 106 install -c -m 0644 seccomp.i386 $(DESTDIR)/$(libdir)/firejail/.
106 install -c -m 0644 seccomp.amd64 $(DESTDIR)/$(libdir)/firejail/. 107 install -c -m 0644 seccomp.amd64 $(DESTDIR)/$(libdir)/firejail/.
108 install -c -m 0644 seccomp.block_secondary $(DESTDIR)/$(libdir)/firejail/.
107 install -c -m 0644 seccomp.mdwx $(DESTDIR)/$(libdir)/firejail/. 109 install -c -m 0644 seccomp.mdwx $(DESTDIR)/$(libdir)/firejail/.
108endif 110endif
109ifeq ($(HAVE_CONTRIB_INSTALL),yes) 111ifeq ($(HAVE_CONTRIB_INSTALL),yes)
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 90f88ef37..71c5ae87c 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -57,12 +57,14 @@
57#define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures 57#define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures
58#define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures 58#define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures
59#define RUN_SECCOMP_MDWX "/run/firejail/mnt/seccomp.mdwx" // filter for memory-deny-write-execute 59#define RUN_SECCOMP_MDWX "/run/firejail/mnt/seccomp.mdwx" // filter for memory-deny-write-execute
60#define RUN_SECCOMP_BLOCK_SECONDARY "/run/firejail/mnt/seccomp.block_secondary" // secondary arch blocking filter
60#define RUN_SECCOMP_POSTEXEC "/run/firejail/mnt/seccomp.postexec" // filter for post-exec library 61#define RUN_SECCOMP_POSTEXEC "/run/firejail/mnt/seccomp.postexec" // filter for post-exec library
61#define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make 62#define PATH_SECCOMP_DEFAULT (LIBDIR "/firejail/seccomp") // default filter built during make
62#define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make 63#define PATH_SECCOMP_DEFAULT_DEBUG (LIBDIR "/firejail/seccomp.debug") // default filter built during make
63#define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make 64#define PATH_SECCOMP_AMD64 (LIBDIR "/firejail/seccomp.amd64") // amd64 filter built during make
64#define PATH_SECCOMP_I386 (LIBDIR "/firejail/seccomp.i386") // i386 filter built during make 65#define PATH_SECCOMP_I386 (LIBDIR "/firejail/seccomp.i386") // i386 filter built during make
65#define PATH_SECCOMP_MDWX (LIBDIR "/firejail/seccomp.mdwx") // filter for memory-deny-write-execute built during make 66#define PATH_SECCOMP_MDWX (LIBDIR "/firejail/seccomp.mdwx") // filter for memory-deny-write-execute built during make
67#define PATH_SECCOMP_BLOCK_SECONDARY (LIBDIR "/firejail/seccomp.block_secondary") // secondary arch blocking filter built during make
66 68
67 69
68#define RUN_DEV_DIR "/run/firejail/mnt/dev" 70#define RUN_DEV_DIR "/run/firejail/mnt/dev"
@@ -307,6 +309,7 @@ extern int arg_overlay_reuse; // allow the reuse of overlays
307 309
308extern int arg_seccomp; // enable default seccomp filter 310extern int arg_seccomp; // enable default seccomp filter
309extern int arg_seccomp_postexec; // need postexec ld.preload library? 311extern int arg_seccomp_postexec; // need postexec ld.preload library?
312extern int arg_seccomp_block_secondary; // block any secondary architectures
310 313
311extern int arg_caps_default_filter; // enable default capabilities filter 314extern int arg_caps_default_filter; // enable default capabilities filter
312extern int arg_caps_drop; // drop list 315extern int arg_caps_drop; // drop list
@@ -538,8 +541,6 @@ void fs_private_home_list(void);
538char *seccomp_check_list(const char *str); 541char *seccomp_check_list(const char *str);
539int seccomp_install_filters(void); 542int seccomp_install_filters(void);
540int seccomp_load(const char *fname); 543int seccomp_load(const char *fname);
541void seccomp_filter_32(void);
542void seccomp_filter_64(void);
543int seccomp_filter_drop(int enforce_seccomp); 544int seccomp_filter_drop(int enforce_seccomp);
544int seccomp_filter_keep(void); 545int seccomp_filter_keep(void);
545void seccomp_print_filter(pid_t pid); 546void seccomp_print_filter(pid_t pid);
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 71a37beb7..3f805a7e0 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -57,6 +57,7 @@ int arg_overlay_reuse = 0; // allow the reuse of overlays
57 57
58int arg_seccomp = 0; // enable default seccomp filter 58int arg_seccomp = 0; // enable default seccomp filter
59int arg_seccomp_postexec = 0; // need postexec ld.preload library? 59int arg_seccomp_postexec = 0; // need postexec ld.preload library?
60int arg_seccomp_block_secondary = 0; // block any secondary architectures
60 61
61int arg_caps_default_filter = 0; // enable default capabilities filter 62int arg_caps_default_filter = 0; // enable default capabilities filter
62int arg_caps_drop = 0; // drop list 63int arg_caps_drop = 0; // drop list
@@ -1147,6 +1148,13 @@ int main(int argc, char **argv) {
1147 else 1148 else
1148 exit_err_feature("seccomp"); 1149 exit_err_feature("seccomp");
1149 } 1150 }
1151 else if (strcmp(argv[i], "--seccomp.block-secondary") == 0) {
1152 if (checkcfg(CFG_SECCOMP)) {
1153 arg_seccomp_block_secondary = 1;
1154 }
1155 else
1156 exit_err_feature("seccomp");
1157 }
1150 else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) { 1158 else if (strcmp(argv[i], "--memory-deny-write-execute") == 0) {
1151 if (checkcfg(CFG_SECCOMP)) 1159 if (checkcfg(CFG_SECCOMP))
1152 arg_memory_deny_write_execute = 1; 1160 arg_memory_deny_write_execute = 1;
@@ -2239,6 +2247,10 @@ int main(int argc, char **argv) {
2239 } 2247 }
2240 } 2248 }
2241 2249
2250 // enable seccomp if only seccomp.block-secondary was specified
2251 if (arg_seccomp_block_secondary)
2252 arg_seccomp = 1;
2253
2242 // log command 2254 // log command
2243 logargs(argc, argv); 2255 logargs(argc, argv);
2244 if (fullargc) { 2256 if (fullargc) {
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c
index 583cc4610..bf1ef0469 100644
--- a/src/firejail/preproc.c
+++ b/src/firejail/preproc.c
@@ -75,9 +75,13 @@ void preproc_mount_mnt_dir(void) {
75 tmpfs_mounted = 1; 75 tmpfs_mounted = 1;
76 fs_logger2("tmpfs", RUN_MNT_DIR); 76 fs_logger2("tmpfs", RUN_MNT_DIR);
77 77
78 //copy defaultl seccomp files 78 if (arg_seccomp_block_secondary)
79 copy_file(PATH_SECCOMP_I386, RUN_SECCOMP_I386, getuid(), getgid(), 0644); // root needed 79 copy_file(PATH_SECCOMP_BLOCK_SECONDARY, RUN_SECCOMP_BLOCK_SECONDARY, getuid(), getgid(), 0644); // root needed
80 copy_file(PATH_SECCOMP_AMD64, RUN_SECCOMP_AMD64, getuid(), getgid(), 0644); // root needed 80 else {
81 //copy default seccomp files
82 copy_file(PATH_SECCOMP_I386, RUN_SECCOMP_I386, getuid(), getgid(), 0644); // root needed
83 copy_file(PATH_SECCOMP_AMD64, RUN_SECCOMP_AMD64, getuid(), getgid(), 0644); // root needed
84 }
81 if (arg_allow_debuggers) 85 if (arg_allow_debuggers)
82 copy_file(PATH_SECCOMP_DEFAULT_DEBUG, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed 86 copy_file(PATH_SECCOMP_DEFAULT_DEBUG, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed
83 else 87 else
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 7753ee3b2..fc390c83a 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -577,6 +577,16 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
577 return 0; 577 return 0;
578 } 578 }
579 579
580 if (strcmp(ptr, "seccomp.block-secondary") == 0) {
581#ifdef HAVE_SECCOMP
582 if (checkcfg(CFG_SECCOMP)) {
583 arg_seccomp_block_secondary = 1;
584 }
585 else
586 warning_feature_disabled("seccomp");
587#endif
588 return 0;
589 }
580 // seccomp drop list without default list 590 // seccomp drop list without default list
581 if (strncmp(ptr, "seccomp.drop ", 13) == 0) { 591 if (strncmp(ptr, "seccomp.drop ", 13) == 0) {
582#ifdef HAVE_SECCOMP 592#ifdef HAVE_SECCOMP
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index e855ce7ed..aaf53b2a1 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -118,7 +118,7 @@ errexit:
118} 118}
119 119
120// i386 filter installed on amd64 architectures 120// i386 filter installed on amd64 architectures
121void seccomp_filter_32(void) { 121static void seccomp_filter_32(void) {
122 if (seccomp_load(RUN_SECCOMP_I386) == 0) { 122 if (seccomp_load(RUN_SECCOMP_I386) == 0) {
123 if (arg_debug) 123 if (arg_debug)
124 printf("Dual i386/amd64 seccomp filter configured\n"); 124 printf("Dual i386/amd64 seccomp filter configured\n");
@@ -126,13 +126,20 @@ void seccomp_filter_32(void) {
126} 126}
127 127
128// amd64 filter installed on i386 architectures 128// amd64 filter installed on i386 architectures
129void seccomp_filter_64(void) { 129static void seccomp_filter_64(void) {
130 if (seccomp_load(RUN_SECCOMP_AMD64) == 0) { 130 if (seccomp_load(RUN_SECCOMP_AMD64) == 0) {
131 if (arg_debug) 131 if (arg_debug)
132 printf("Dual i386/amd64 seccomp filter configured\n"); 132 printf("Dual i386/amd64 seccomp filter configured\n");
133 } 133 }
134} 134}
135 135
136static void seccomp_filter_block_secondary(void) {
137 if (seccomp_load(RUN_SECCOMP_BLOCK_SECONDARY) == 0) {
138 if (arg_debug)
139 printf("Secondary arch blocking seccomp filter configured\n");
140 }
141}
142
136// drop filter for seccomp option 143// drop filter for seccomp option
137int seccomp_filter_drop(int enforce_seccomp) { 144int seccomp_filter_drop(int enforce_seccomp) {
138 // if we have multiple seccomp commands, only one of them is executed 145 // if we have multiple seccomp commands, only one of them is executed
@@ -143,21 +150,29 @@ int seccomp_filter_drop(int enforce_seccomp) {
143 if (cfg.seccomp_list_drop == NULL) { 150 if (cfg.seccomp_list_drop == NULL) {
144 // default seccomp 151 // default seccomp
145 if (cfg.seccomp_list == NULL) { 152 if (cfg.seccomp_list == NULL) {
153 if (arg_seccomp_block_secondary)
154 seccomp_filter_block_secondary();
155 else {
146#if defined(__x86_64__) 156#if defined(__x86_64__)
147 seccomp_filter_32(); 157 seccomp_filter_32();
148#endif 158#endif
149#if defined(__i386__) 159#if defined(__i386__)
150 seccomp_filter_64(); 160 seccomp_filter_64();
151#endif 161#endif
162 }
152 } 163 }
153 // default seccomp filter with additional drop list 164 // default seccomp filter with additional drop list
154 else { // cfg.seccomp_list != NULL 165 else { // cfg.seccomp_list != NULL
166 if (arg_seccomp_block_secondary)
167 seccomp_filter_block_secondary();
168 else {
155#if defined(__x86_64__) 169#if defined(__x86_64__)
156 seccomp_filter_32(); 170 seccomp_filter_32();
157#endif 171#endif
158#if defined(__i386__) 172#if defined(__i386__)
159 seccomp_filter_64(); 173 seccomp_filter_64();
160#endif 174#endif
175 }
161 if (arg_debug) 176 if (arg_debug)
162 printf("Build default+drop seccomp filter\n"); 177 printf("Build default+drop seccomp filter\n");
163 178
@@ -175,7 +190,10 @@ int seccomp_filter_drop(int enforce_seccomp) {
175 } 190 }
176 191
177 // drop list without defaults - secondary filters are not installed 192 // drop list without defaults - secondary filters are not installed
193 // except when secondary architectures are explicitly blocked
178 else { // cfg.seccomp_list_drop != NULL 194 else { // cfg.seccomp_list_drop != NULL
195 if (arg_seccomp_block_secondary)
196 seccomp_filter_block_secondary();
179 if (arg_debug) 197 if (arg_debug)
180 printf("Build drop seccomp filter\n"); 198 printf("Build drop seccomp filter\n");
181 199
@@ -216,6 +234,11 @@ int seccomp_filter_drop(int enforce_seccomp) {
216 234
217// keep filter for seccomp option 235// keep filter for seccomp option
218int seccomp_filter_keep(void) { 236int seccomp_filter_keep(void) {
237 // secondary filters are not installed except when secondary
238 // architectures are explicitly blocked
239 if (arg_seccomp_block_secondary)
240 seccomp_filter_block_secondary();
241
219 if (arg_debug) 242 if (arg_debug)
220 printf("Build drop seccomp filter\n"); 243 printf("Build drop seccomp filter\n");
221 244
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h
index 144b612ae..2deb282f5 100644
--- a/src/fseccomp/fseccomp.h
+++ b/src/fseccomp/fseccomp.h
@@ -46,6 +46,7 @@ void protocol_build_filter(const char *prlist, const char *fname);
46// seccomp_secondary.c 46// seccomp_secondary.c
47void seccomp_secondary_64(const char *fname); 47void seccomp_secondary_64(const char *fname);
48void seccomp_secondary_32(const char *fname); 48void seccomp_secondary_32(const char *fname);
49void seccomp_secondary_block(const char *fname);
49 50
50// seccomp_file.c 51// seccomp_file.c
51void write_to_file(int fd, const void *data, int size); 52void write_to_file(int fd, const void *data, int size);
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c
index 3bf7de0fa..ae0ae64ef 100644
--- a/src/fseccomp/main.c
+++ b/src/fseccomp/main.c
@@ -28,6 +28,7 @@ static void usage(void) {
28 printf("\tfseccomp protocol build list file\n"); 28 printf("\tfseccomp protocol build list file\n");
29 printf("\tfseccomp secondary 64 file\n"); 29 printf("\tfseccomp secondary 64 file\n");
30 printf("\tfseccomp secondary 32 file\n"); 30 printf("\tfseccomp secondary 32 file\n");
31 printf("\tfseccomp secondary block file\n");
31 printf("\tfseccomp default file\n"); 32 printf("\tfseccomp default file\n");
32 printf("\tfseccomp default file allow-debuggers\n"); 33 printf("\tfseccomp default file allow-debuggers\n");
33 printf("\tfseccomp drop file1 file2 list\n"); 34 printf("\tfseccomp drop file1 file2 list\n");
@@ -74,6 +75,8 @@ printf("\n");
74 seccomp_secondary_64(argv[3]); 75 seccomp_secondary_64(argv[3]);
75 else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "32") == 0) 76 else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "32") == 0)
76 seccomp_secondary_32(argv[3]); 77 seccomp_secondary_32(argv[3]);
78 else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "block") == 0)
79 seccomp_secondary_block(argv[3]);
77 else if (argc == 3 && strcmp(argv[1], "default") == 0) 80 else if (argc == 3 && strcmp(argv[1], "default") == 0)
78 seccomp_default(argv[2], 0); 81 seccomp_default(argv[2], 0);
79 else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) 82 else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0)
diff --git a/src/fseccomp/seccomp_print.c b/src/fseccomp/seccomp_print.c
index 19fe7a545..7af95d51c 100644
--- a/src/fseccomp/seccomp_print.c
+++ b/src/fseccomp/seccomp_print.c
@@ -113,6 +113,25 @@ static int detect_filter_type(void) {
113 printf(" EXAMINE_SYSCALL\n"); 113 printf(" EXAMINE_SYSCALL\n");
114 return sizeof(start_secondary_32) / sizeof(struct sock_filter); 114 return sizeof(start_secondary_32) / sizeof(struct sock_filter);
115 } 115 }
116
117 const struct sock_filter start_secondary_block[] = {
118 VALIDATE_ARCHITECTURE_KILL,
119#if defined(__x86_64__)
120 EXAMINE_SYSCALL,
121 HANDLE_X32_KILL,
122#else
123 EXAMINE_SYSCALL
124#endif
125 };
126
127 if (memcmp(&start_secondary_block[0], filter, sizeof(start_secondary_block)) == 0) {
128 printf(" VALIDATE_ARCHITECTURE_KILL\n");
129 printf(" EXAMINE_SYSCALL\n");
130#if defined(__x86_64__)
131 printf(" HANDLE_X32_KILL\n");
132#endif
133 return sizeof(start_secondary_block) / sizeof(struct sock_filter);
134 }
116 135
117 return 0; // filter unrecognized 136 return 0; // filter unrecognized
118} 137}
diff --git a/src/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c
index fceb2c3ec..dd69b58cc 100644
--- a/src/fseccomp/seccomp_secondary.c
+++ b/src/fseccomp/seccomp_secondary.c
@@ -19,8 +19,29 @@
19*/ 19*/
20#include "fseccomp.h" 20#include "fseccomp.h"
21#include "../include/seccomp.h" 21#include "../include/seccomp.h"
22#include <sys/personality.h>
22#include <sys/syscall.h> 23#include <sys/syscall.h>
23 24
25static void write_filter(const char *fname, size_t size, const void *filter) {
26 // save filter to file
27 int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
28 if (dst < 0) {
29 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
30 exit(1);
31 }
32
33 size_t written = 0;
34 while (written < size) {
35 ssize_t rv = write(dst, (unsigned char *) filter + written, size - written);
36 if (rv == -1) {
37 fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname);
38 exit(1);
39 }
40 written += rv;
41 }
42 close(dst);
43}
44
24void seccomp_secondary_64(const char *fname) { 45void seccomp_secondary_64(const char *fname) {
25 // hardcoded syscall values 46 // hardcoded syscall values
26 struct sock_filter filter[] = { 47 struct sock_filter filter[] = {
@@ -84,23 +105,7 @@ void seccomp_secondary_64(const char *fname) {
84 }; 105 };
85 106
86 // save filter to file 107 // save filter to file
87 int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 108 write_filter(fname, sizeof(filter), filter);
88 if (dst < 0) {
89 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
90 exit(1);
91 }
92
93 int size = (int) sizeof(filter);
94 int written = 0;
95 while (written < size) {
96 int rv = write(dst, (unsigned char *) filter + written, size - written);
97 if (rv == -1) {
98 fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname);
99 exit(1);
100 }
101 written += rv;
102 }
103 close(dst);
104} 109}
105 110
106// i386 filter installed on amd64 architectures 111// i386 filter installed on amd64 architectures
@@ -166,21 +171,47 @@ void seccomp_secondary_32(const char *fname) {
166 }; 171 };
167 172
168 // save filter to file 173 // save filter to file
169 int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 174 write_filter(fname, sizeof(filter), filter);
170 if (dst < 0) { 175}
171 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
172 exit(1);
173 }
174 176
175 int size = (int) sizeof(filter); 177#define jmp_from_to(from_addr, to_addr) ((to_addr) - (from_addr) - 1)
176 int written = 0; 178
177 while (written < size) { 179#if __BYTE_ORDER == __BIG_ENDIAN
178 int rv = write(dst, (unsigned char *) filter + written, size - written); 180#define MSW 0
179 if (rv == -1) { 181#define LSW (sizeof(int))
180 fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); 182#else
181 exit(1); 183#define MSW (sizeof(int))
182 } 184#define LSW 0
183 written += rv; 185#endif
184 } 186
185 close(dst); 187void seccomp_secondary_block(const char *fname) {
188 struct sock_filter filter[] = {
189 // block other architectures
190 VALIDATE_ARCHITECTURE_KILL,
191 EXAMINE_SYSCALL,
192#if defined(__x86_64__)
193 // block x32
194 HANDLE_X32_KILL,
195#endif
196 // block personality(2) where domain != PER_LINUX or 0xffffffff (query current personality)
197 // 0: if personality(2), continue to 1, else goto 7 (allow)
198 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYS_personality, 0, jmp_from_to(0, 7)),
199 // 1: get LSW of system call argument 0
200 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, args[0])) + LSW),
201 // 2: if LSW(arg0) == PER_LINUX, goto step 4, else continue to 3
202 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, PER_LINUX, jmp_from_to(2, 4), 0),
203 // 3: if LSW(arg0) == 0xffffffff, continue to 4, else goto 6 (kill)
204 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 0, jmp_from_to(3, 6)),
205 // 4: get MSW of system call argument 0
206 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, args[0])) + MSW),
207 // 5: if MSW(arg0) == 0, goto 7 (allow) else continue to 6 (kill)
208 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, jmp_from_to(5, 7), 0),
209 // 6:
210 KILL_PROCESS,
211 // 7:
212 RETURN_ALLOW
213 };
214
215 // save filter to file
216 write_filter(fname, sizeof(filter), filter);
186} 217}
diff --git a/src/include/seccomp.h b/src/include/seccomp.h
index b1a19a9b6..2f2b2384d 100644
--- a/src/include/seccomp.h
+++ b/src/include/seccomp.h
@@ -105,6 +105,11 @@ struct seccomp_data {
105 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ 105 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
106 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 106 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
107 107
108#define VALIDATE_ARCHITECTURE_KILL \
109 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \
110 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
111 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
112
108#define VALIDATE_ARCHITECTURE_64 \ 113#define VALIDATE_ARCHITECTURE_64 \
109 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ 114 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \
110 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0), \ 115 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0), \
@@ -122,6 +127,10 @@ struct seccomp_data {
122 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \ 127 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \
123 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \ 128 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \
124 RETURN_ERRNO(EPERM) 129 RETURN_ERRNO(EPERM)
130#define HANDLE_X32_KILL \
131 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \
132 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \
133 KILL_PROCESS
125#endif 134#endif
126 135
127#define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ 136#define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index 2a7d926b9..050c3d7e5 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -310,6 +310,10 @@ Enable seccomp filter and blacklist the syscalls in the default list. See man 1
310\fBseccomp syscall,syscall,syscall 310\fBseccomp syscall,syscall,syscall
311Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter. 311Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter.
312.TP 312.TP
313\fBseccomp.block-secondary
314Enable seccomp filter and filter system call architectures
315so that only the native architecture is allowed.
316.TP
313\fBseccomp.drop syscall,syscall,syscall 317\fBseccomp.drop syscall,syscall,syscall
314Enable seccomp filter and blacklist the system calls in the list. 318Enable seccomp filter and blacklist the system calls in the list.
315.TP 319.TP
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 89b815e02..d1970c985 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -1572,9 +1572,10 @@ system call can be specified by its number instead of name with prefix
1572$, so for example $165 would be equal to mount on i386. 1572$, so for example $165 would be equal to mount on i386.
1573 1573
1574.br 1574.br
1575System architecture is not strictly imposed. The filter is applied 1575System architecture is strictly imposed only if flag
1576at run time only if the correct architecture was detected. For the case of I386 and AMD64 1576\-\-seccomp.block_secondary is used. The filter is applied at run time
1577both 32-bit and 64-bit filters are installed. 1577only if the correct architecture was detected. For the case of I386
1578and AMD64 both 32-bit and 64-bit filters are installed.
1578.br 1579.br
1579 1580
1580.br 1581.br
@@ -1646,6 +1647,14 @@ Bad system call
1646.br 1647.br
1647 1648
1648.TP 1649.TP
1650\fB\-\-seccomp.block_secondary
1651Enable seccomp filter and filter system call architectures so that
1652only the native architecture is allowed. For example, on amd64, i386
1653and x32 system calls are blocked as well as changing the execution
1654domain with personality(2) system call.
1655.br
1656
1657.TP
1649\fB\-\-seccomp.drop=syscall,syscall,syscall 1658\fB\-\-seccomp.drop=syscall,syscall,syscall
1650Enable seccomp filter, and blacklist the syscalls specified by the command. 1659Enable seccomp filter, and blacklist the syscalls specified by the command.
1651.br 1660.br