diff options
author | Topi Miettinen <toiwoton@gmail.com> | 2017-08-19 23:22:38 +0300 |
---|---|---|
committer | Topi Miettinen <toiwoton@gmail.com> | 2017-08-19 23:33:11 +0300 |
commit | d01216de45884300c87e7d3ccb70e53ebb461449 (patch) | |
tree | 480519f5849df4c6048a7f62ec97f96e51174c3e /src/fseccomp | |
parent | Merge update after #1483 (diff) | |
download | firejail-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
Diffstat (limited to 'src/fseccomp')
-rw-r--r-- | src/fseccomp/fseccomp.h | 1 | ||||
-rw-r--r-- | src/fseccomp/main.c | 3 | ||||
-rw-r--r-- | src/fseccomp/seccomp_print.c | 19 | ||||
-rw-r--r-- | src/fseccomp/seccomp_secondary.c | 97 |
4 files changed, 87 insertions, 33 deletions
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 |
47 | void seccomp_secondary_64(const char *fname); | 47 | void seccomp_secondary_64(const char *fname); |
48 | void seccomp_secondary_32(const char *fname); | 48 | void seccomp_secondary_32(const char *fname); |
49 | void seccomp_secondary_block(const char *fname); | ||
49 | 50 | ||
50 | // seccomp_file.c | 51 | // seccomp_file.c |
51 | void write_to_file(int fd, const void *data, int size); | 52 | void 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 | ||
25 | static 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 | |||
24 | void seccomp_secondary_64(const char *fname) { | 45 | void 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); | 187 | void 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 | } |