]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/seccomp.c
Merge pull request #2114 from brauner/2018-01-27/make_name_arg_optional
[mirror_lxc.git] / src / lxc / seccomp.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright Canonical, Inc. 2012
5 *
6 * Authors:
7 * Serge Hallyn <serge.hallyn@canonical.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _GNU_SOURCE
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <seccomp.h>
29 #include <sys/mount.h>
30 #include <sys/utsname.h>
31
32 #include "config.h"
33 #include "log.h"
34 #include "lxcseccomp.h"
35
36 lxc_log_define(lxc_seccomp, lxc);
37
38 static int parse_config_v1(FILE *f, struct lxc_conf *conf)
39 {
40 char line[1024];
41 int ret;
42
43 while (fgets(line, 1024, f)) {
44 int nr;
45 ret = sscanf(line, "%d", &nr);
46 if (ret != 1)
47 return -1;
48 ret = seccomp_rule_add(
49 #if HAVE_SCMP_FILTER_CTX
50 conf->seccomp_ctx,
51 #endif
52 SCMP_ACT_ALLOW, nr, 0);
53 if (ret < 0) {
54 ERROR("Failed loading allow rule for %d", nr);
55 return ret;
56 }
57 }
58 return 0;
59 }
60
61 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
62 static void remove_trailing_newlines(char *l)
63 {
64 char *p = l;
65
66 while (*p)
67 p++;
68 while (--p >= l && *p == '\n')
69 *p = '\0';
70 }
71
72 static uint32_t get_v2_default_action(char *line)
73 {
74 uint32_t ret_action = -1;
75
76 while (*line == ' ')
77 line++;
78 /* After 'whitelist' or 'blacklist' comes default behavior. */
79 if (strncmp(line, "kill", 4) == 0)
80 ret_action = SCMP_ACT_KILL;
81 else if (strncmp(line, "errno", 5) == 0) {
82 int e;
83 if (sscanf(line + 5, "%d", &e) != 1) {
84 ERROR("Bad errno value in %s", line);
85 return -2;
86 }
87 ret_action = SCMP_ACT_ERRNO(e);
88 } else if (strncmp(line, "allow", 5) == 0)
89 ret_action = SCMP_ACT_ALLOW;
90 else if (strncmp(line, "trap", 4) == 0)
91 ret_action = SCMP_ACT_TRAP;
92 return ret_action;
93 }
94
95 static const char *get_action_name(uint32_t action)
96 {
97 /* The upper 16 bits indicate the type of the seccomp action. */
98 switch(action & 0xffff0000){
99 case SCMP_ACT_KILL:
100 return "kill";
101 case SCMP_ACT_ALLOW:
102 return "allow";
103 case SCMP_ACT_TRAP:
104 return "trap";
105 case SCMP_ACT_ERRNO(0):
106 return "errno";
107 default:
108 return "invalid action";
109 }
110 }
111
112 static uint32_t get_v2_action(char *line, uint32_t def_action)
113 {
114 char *p = strchr(line, ' ');
115 uint32_t ret;
116
117 if (!p)
118 return def_action;
119 p++;
120 while (*p == ' ')
121 p++;
122 if (!*p || *p == '#')
123 return def_action;
124 ret = get_v2_default_action(p);
125 switch(ret) {
126 case -2: return -1;
127 case -1: return def_action;
128 default: return ret;
129 }
130 }
131
132 struct v2_rule_args {
133 uint32_t index;
134 uint64_t value;
135 uint64_t mask;
136 enum scmp_compare op;
137 };
138
139 struct seccomp_v2_rule {
140 uint32_t action;
141 uint32_t args_num;
142 struct v2_rule_args args_value[6];
143 };
144
145 static enum scmp_compare parse_v2_rule_op(char *s)
146 {
147 if (strcmp(s, "SCMP_CMP_NE") == 0 || strcmp(s, "!=") == 0)
148 return SCMP_CMP_NE;
149 else if (strcmp(s, "SCMP_CMP_LT") == 0 || strcmp(s, "<") == 0)
150 return SCMP_CMP_LT;
151 else if (strcmp(s, "SCMP_CMP_LE") == 0 || strcmp(s, "<=") == 0)
152 return SCMP_CMP_LE;
153 else if (strcmp(s, "SCMP_CMP_EQ") == 0 || strcmp(s, "==") == 0)
154 return SCMP_CMP_EQ;
155 else if (strcmp(s, "SCMP_CMP_GE") == 0 || strcmp(s, ">=") == 0)
156 return SCMP_CMP_GE;
157 else if (strcmp(s, "SCMP_CMP_GT") == 0 || strcmp(s, ">") == 0)
158 return SCMP_CMP_GT;
159 else if (strcmp(s, "SCMP_CMP_MASKED_EQ") == 0 || strcmp(s, "&=") == 0)
160 return SCMP_CMP_MASKED_EQ;
161
162 return _SCMP_CMP_MAX;
163 }
164
165 /* This function is used to parse the args string into the structure.
166 * args string format:[index,value,op,valueTwo] or [index,value,op]
167 * For one arguments, [index,value,valueTwo,op]
168 * index: the index for syscall arguments (type uint)
169 * value: the value for syscall arguments (type uint64)
170 * op: the operator for syscall arguments(string),
171 a valid list of constants as of libseccomp v2.3.2 is
172 SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE,
173 SCMP_CMP_GT, SCMP_CMP_MASKED_EQ, or !=,<=,==,>=,>,&=
174 * valueTwo: the value for syscall arguments only used for mask eq (type uint64, optional)
175 * Returns 0 on success, < 0 otherwise.
176 */
177 static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args)
178 {
179 int ret = 0;
180 uint64_t value = 0;
181 uint64_t mask = 0;
182 enum scmp_compare op = 0;
183 uint32_t index = 0;
184 char s[30] = {0};
185 char *tmp = NULL;
186
187 memset(s, 0, sizeof(s));
188 tmp = strchr(key, '[');
189 if (!tmp) {
190 ERROR("Failed to interpret args");
191 return -1;
192 }
193 ret = sscanf(tmp, "[%i,%lli,%30[^0-9^,],%lli", &index, (long long unsigned int *)&value, s, (long long unsigned int *)&mask);
194 if ((ret != 3 && ret != 4) || index >= 6) {
195 ERROR("Failed to interpret args value");
196 return -1;
197 }
198
199 op = parse_v2_rule_op(s);
200 if (op == _SCMP_CMP_MAX) {
201 ERROR("Failed to interpret args operator value");
202 return -1;
203 }
204
205 rule_args->index = index;
206 rule_args->value = value;
207 rule_args->mask = mask;
208 rule_args->op = op;
209 return 0;
210 }
211
212 /* This function is used to parse the seccomp rule entry.
213 * @line : seccomp rule entry string.
214 * @def_action : default action used in the case if the 'line' contain non valid action.
215 * @rules : output struct.
216 * Returns 0 on success, < 0 otherwise.
217 */
218 static int parse_v2_rules(char *line, uint32_t def_action, struct seccomp_v2_rule *rules)
219 {
220 int ret = 0 ;
221 int i = 0;
222 char *tmp = NULL;
223 char *key = NULL;
224 char *saveptr = NULL;
225
226 tmp = strdup(line);
227 if (!tmp)
228 return -1;
229
230 /* read optional action which follows the syscall */
231 rules->action = get_v2_action(tmp, def_action);
232 if (rules->action == -1) {
233 ERROR("Failed to interpret action");
234 ret = -1;
235 goto out;
236 }
237
238 rules->args_num = 0;
239 if (!strchr(tmp, '[')) {
240 ret = 0;
241 goto out;
242 }
243
244 for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6; (key = strtok_r(NULL, "]", &saveptr)), i++) {
245 ret = get_seccomp_arg_value(key, &rules->args_value[i]);
246 if (ret < 0) {
247 ret = -1;
248 goto out;
249 }
250 rules->args_num++;
251 }
252
253 ret = 0;
254 out:
255 free(tmp);
256 return ret;
257 }
258
259 #endif
260
261 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
262 enum lxc_hostarch_t {
263 lxc_seccomp_arch_all = 0,
264 lxc_seccomp_arch_native,
265 lxc_seccomp_arch_i386,
266 lxc_seccomp_arch_x32,
267 lxc_seccomp_arch_amd64,
268 lxc_seccomp_arch_arm,
269 lxc_seccomp_arch_arm64,
270 lxc_seccomp_arch_ppc64,
271 lxc_seccomp_arch_ppc64le,
272 lxc_seccomp_arch_ppc,
273 lxc_seccomp_arch_mips,
274 lxc_seccomp_arch_mips64,
275 lxc_seccomp_arch_mips64n32,
276 lxc_seccomp_arch_mipsel,
277 lxc_seccomp_arch_mipsel64,
278 lxc_seccomp_arch_mipsel64n32,
279 lxc_seccomp_arch_s390x,
280 lxc_seccomp_arch_unknown = 999,
281 };
282
283 #ifdef __MIPSEL__
284 # define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
285 # define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
286 #else
287 # define MIPS_ARCH_O32 lxc_seccomp_arch_mips
288 # define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
289 #endif
290
291 int get_hostarch(void)
292 {
293 struct utsname uts;
294 if (uname(&uts) < 0) {
295 SYSERROR("Failed to read host arch");
296 return -1;
297 }
298 if (strcmp(uts.machine, "i686") == 0)
299 return lxc_seccomp_arch_i386;
300 /* no x32 kernels */
301 else if (strcmp(uts.machine, "x86_64") == 0)
302 return lxc_seccomp_arch_amd64;
303 else if (strncmp(uts.machine, "armv7", 5) == 0)
304 return lxc_seccomp_arch_arm;
305 else if (strncmp(uts.machine, "aarch64", 7) == 0)
306 return lxc_seccomp_arch_arm64;
307 else if (strncmp(uts.machine, "ppc64le", 7) == 0)
308 return lxc_seccomp_arch_ppc64le;
309 else if (strncmp(uts.machine, "ppc64", 5) == 0)
310 return lxc_seccomp_arch_ppc64;
311 else if (strncmp(uts.machine, "ppc", 3) == 0)
312 return lxc_seccomp_arch_ppc;
313 else if (strncmp(uts.machine, "mips64", 6) == 0)
314 return MIPS_ARCH_N64;
315 else if (strncmp(uts.machine, "mips", 4) == 0)
316 return MIPS_ARCH_O32;
317 else if (strncmp(uts.machine, "s390x", 5) == 0)
318 return lxc_seccomp_arch_s390x;
319 return lxc_seccomp_arch_unknown;
320 }
321
322 scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
323 {
324 scmp_filter_ctx ctx;
325 int ret;
326 uint32_t arch;
327
328 switch(n_arch) {
329 case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
330 case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
331 case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
332 case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
333 #ifdef SCMP_ARCH_AARCH64
334 case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
335 #endif
336 #ifdef SCMP_ARCH_PPC64LE
337 case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
338 #endif
339 #ifdef SCMP_ARCH_PPC64
340 case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
341 #endif
342 #ifdef SCMP_ARCH_PPC
343 case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
344 #endif
345 #ifdef SCMP_ARCH_MIPS
346 case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
347 case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
348 case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
349 case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
350 case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
351 case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
352 #endif
353 #ifdef SCMP_ARCH_S390X
354 case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
355 #endif
356 default: return NULL;
357 }
358
359 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
360 ERROR("Error initializing seccomp context");
361 return NULL;
362 }
363 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
364 ERROR("Failed to turn off no-new-privs");
365 seccomp_release(ctx);
366 return NULL;
367 }
368 #ifdef SCMP_FLTATR_ATL_TSKIP
369 if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
370 WARN("Failed to turn on seccomp nop-skip, continuing");
371 }
372 #endif
373 ret = seccomp_arch_add(ctx, arch);
374 if (ret != 0) {
375 ERROR("Seccomp error %d (%s) adding arch: %d", ret,
376 strerror(-ret), (int)n_arch);
377 seccomp_release(ctx);
378 return NULL;
379 }
380 if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
381 ERROR("Seccomp error removing native arch");
382 seccomp_release(ctx);
383 return NULL;
384 }
385
386 return ctx;
387 }
388
389 bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
390 struct seccomp_v2_rule *rule)
391 {
392 int nr, ret, i;
393 struct scmp_arg_cmp arg_cmp[6];
394
395 memset(arg_cmp, 0 ,sizeof(arg_cmp));
396
397 ret = seccomp_arch_exist(ctx, arch);
398 if (arch && ret != 0) {
399 ERROR("BUG: Seccomp: rule and context arch do not match (arch "
400 "%d): %s",
401 arch, strerror(-ret));
402 return false;
403 }
404
405 /*get the syscall name*/
406 char *p = strchr(line, ' ');
407 if (p)
408 *p = '\0';
409
410 if (strncmp(line, "reject_force_umount", 19) == 0) {
411 INFO("Setting Seccomp rule to reject force umounts");
412 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
413 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
414 if (ret < 0) {
415 ERROR("Failed (%d) loading rule to reject force "
416 "umount: %s",
417 ret, strerror(-ret));
418 return false;
419 }
420 return true;
421 }
422
423 nr = seccomp_syscall_resolve_name(line);
424 if (nr == __NR_SCMP_ERROR) {
425 WARN("Seccomp: failed to resolve syscall: %s", line);
426 WARN("This syscall will NOT be blacklisted");
427 return true;
428 }
429 if (nr < 0) {
430 WARN("Seccomp: got negative for syscall: %d: %s", nr, line);
431 WARN("This syscall will NOT be blacklisted");
432 return true;
433 }
434
435 for (i = 0; i < rule->args_num; i++) {
436 INFO("arg_cmp[%d]:SCMP_CMP(%u, %llu, %llu, %llu)", i,
437 rule->args_value[i].index,
438 (long long unsigned int)rule->args_value[i].op,
439 (long long unsigned int)rule->args_value[i].mask,
440 (long long unsigned int)rule->args_value[i].value);
441
442 if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
443 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].mask, rule->args_value[i].value);
444 else
445 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].value);
446 }
447
448 ret = seccomp_rule_add_exact_array(ctx, rule->action, nr, rule->args_num, arg_cmp);
449 if (ret < 0) {
450 ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s",
451 ret, line, nr, rule->action, get_action_name(rule->action), strerror(-ret));
452 return false;
453 }
454 return true;
455 }
456
457 /*
458 * v2 consists of
459 * [x86]
460 * open
461 * read
462 * write
463 * close
464 * # a comment
465 * [x86_64]
466 * open
467 * read
468 * write
469 * close
470 */
471 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
472 {
473 char *p;
474 int ret;
475 scmp_filter_ctx compat_ctx[2] = {NULL, NULL};
476 bool blacklist = false;
477 uint32_t default_policy_action = -1, default_rule_action = -1;
478 enum lxc_hostarch_t native_arch = get_hostarch(),
479 cur_rule_arch = native_arch;
480 uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};
481 struct seccomp_v2_rule rule;
482
483 if (strncmp(line, "blacklist", 9) == 0)
484 blacklist = true;
485 else if (strncmp(line, "whitelist", 9) != 0) {
486 ERROR("Bad seccomp policy style: %s", line);
487 return -1;
488 }
489
490 if ((p = strchr(line, ' '))) {
491 default_policy_action = get_v2_default_action(p + 1);
492 if (default_policy_action == -2)
493 return -1;
494 }
495
496 /* for blacklist, allow any syscall which has no rule */
497 if (blacklist) {
498 if (default_policy_action == -1)
499 default_policy_action = SCMP_ACT_ALLOW;
500 if (default_rule_action == -1)
501 default_rule_action = SCMP_ACT_KILL;
502 } else {
503 if (default_policy_action == -1)
504 default_policy_action = SCMP_ACT_KILL;
505 if (default_rule_action == -1)
506 default_rule_action = SCMP_ACT_ALLOW;
507 }
508
509 if (native_arch == lxc_seccomp_arch_amd64) {
510 cur_rule_arch = lxc_seccomp_arch_all;
511 compat_arch[0] = SCMP_ARCH_X86;
512 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
513 default_policy_action);
514 compat_arch[1] = SCMP_ARCH_X32;
515 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
516 default_policy_action);
517 if (!compat_ctx[0] || !compat_ctx[1])
518 goto bad;
519 #ifdef SCMP_ARCH_PPC
520 } else if (native_arch == lxc_seccomp_arch_ppc64) {
521 cur_rule_arch = lxc_seccomp_arch_all;
522 compat_arch[0] = SCMP_ARCH_PPC;
523 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc,
524 default_policy_action);
525 if (!compat_ctx[0])
526 goto bad;
527 #endif
528 #ifdef SCMP_ARCH_ARM
529 } else if (native_arch == lxc_seccomp_arch_arm64) {
530 cur_rule_arch = lxc_seccomp_arch_all;
531 compat_arch[0] = SCMP_ARCH_ARM;
532 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm,
533 default_policy_action);
534 if (!compat_ctx[0])
535 goto bad;
536 #endif
537 #ifdef SCMP_ARCH_MIPS
538 } else if (native_arch == lxc_seccomp_arch_mips64) {
539 cur_rule_arch = lxc_seccomp_arch_all;
540 compat_arch[0] = SCMP_ARCH_MIPS;
541 compat_arch[1] = SCMP_ARCH_MIPS64N32;
542 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips,
543 default_policy_action);
544 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
545 default_policy_action);
546 if (!compat_ctx[0] || !compat_ctx[1])
547 goto bad;
548 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
549 cur_rule_arch = lxc_seccomp_arch_all;
550 compat_arch[0] = SCMP_ARCH_MIPSEL;
551 compat_arch[1] = SCMP_ARCH_MIPSEL64N32;
552 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
553 default_policy_action);
554 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
555 default_policy_action);
556 if (!compat_ctx[0] || !compat_ctx[1])
557 goto bad;
558 #endif
559 }
560
561 if (default_policy_action != SCMP_ACT_KILL) {
562 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
563 if (ret != 0) {
564 ERROR("Error re-initializing Seccomp");
565 return -1;
566 }
567 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
568 ERROR("Failed to turn off no-new-privs");
569 return -1;
570 }
571 #ifdef SCMP_FLTATR_ATL_TSKIP
572 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
573 WARN("Failed to turn on seccomp nop-skip, continuing");
574 }
575 #endif
576 }
577
578 while (fgets(line, 1024, f)) {
579
580 if (line[0] == '#')
581 continue;
582 if (strlen(line) == 0)
583 continue;
584 remove_trailing_newlines(line);
585 INFO("processing: .%s", line);
586 if (line[0] == '[') {
587 /* Read the architecture for next set of rules. */
588 if (strcmp(line, "[x86]") == 0 ||
589 strcmp(line, "[X86]") == 0) {
590 if (native_arch != lxc_seccomp_arch_i386 &&
591 native_arch != lxc_seccomp_arch_amd64) {
592 cur_rule_arch = lxc_seccomp_arch_unknown;
593 continue;
594 }
595 cur_rule_arch = lxc_seccomp_arch_i386;
596 } else if (strcmp(line, "[x32]") == 0 ||
597 strcmp(line, "[X32]") == 0) {
598 if (native_arch != lxc_seccomp_arch_amd64) {
599 cur_rule_arch = lxc_seccomp_arch_unknown;
600 continue;
601 }
602 cur_rule_arch = lxc_seccomp_arch_x32;
603 } else if (strcmp(line, "[X86_64]") == 0 ||
604 strcmp(line, "[x86_64]") == 0) {
605 if (native_arch != lxc_seccomp_arch_amd64) {
606 cur_rule_arch = lxc_seccomp_arch_unknown;
607 continue;
608 }
609 cur_rule_arch = lxc_seccomp_arch_amd64;
610 } else if (strcmp(line, "[all]") == 0 ||
611 strcmp(line, "[ALL]") == 0) {
612 cur_rule_arch = lxc_seccomp_arch_all;
613 }
614 #ifdef SCMP_ARCH_ARM
615 else if (strcmp(line, "[arm]") == 0 ||
616 strcmp(line, "[ARM]") == 0) {
617 if (native_arch != lxc_seccomp_arch_arm &&
618 native_arch != lxc_seccomp_arch_arm64) {
619 cur_rule_arch = lxc_seccomp_arch_unknown;
620 continue;
621 }
622 cur_rule_arch = lxc_seccomp_arch_arm;
623 }
624 #endif
625 #ifdef SCMP_ARCH_AARCH64
626 else if (strcmp(line, "[arm64]") == 0 ||
627 strcmp(line, "[ARM64]") == 0) {
628 if (native_arch != lxc_seccomp_arch_arm64) {
629 cur_rule_arch = lxc_seccomp_arch_unknown;
630 continue;
631 }
632 cur_rule_arch = lxc_seccomp_arch_arm64;
633 }
634 #endif
635 #ifdef SCMP_ARCH_PPC64LE
636 else if (strcmp(line, "[ppc64le]") == 0 ||
637 strcmp(line, "[PPC64LE]") == 0) {
638 if (native_arch != lxc_seccomp_arch_ppc64le) {
639 cur_rule_arch = lxc_seccomp_arch_unknown;
640 continue;
641 }
642 cur_rule_arch = lxc_seccomp_arch_ppc64le;
643 }
644 #endif
645 #ifdef SCMP_ARCH_PPC64
646 else if (strcmp(line, "[ppc64]") == 0 ||
647 strcmp(line, "[PPC64]") == 0) {
648 if (native_arch != lxc_seccomp_arch_ppc64) {
649 cur_rule_arch = lxc_seccomp_arch_unknown;
650 continue;
651 }
652 cur_rule_arch = lxc_seccomp_arch_ppc64;
653 }
654 #endif
655 #ifdef SCMP_ARCH_PPC
656 else if (strcmp(line, "[ppc]") == 0 ||
657 strcmp(line, "[PPC]") == 0) {
658 if (native_arch != lxc_seccomp_arch_ppc &&
659 native_arch != lxc_seccomp_arch_ppc64) {
660 cur_rule_arch = lxc_seccomp_arch_unknown;
661 continue;
662 }
663 cur_rule_arch = lxc_seccomp_arch_ppc;
664 }
665 #endif
666 #ifdef SCMP_ARCH_MIPS
667 else if (strcmp(line, "[mips64]") == 0 ||
668 strcmp(line, "[MIPS64]") == 0) {
669 if (native_arch != lxc_seccomp_arch_mips64) {
670 cur_rule_arch = lxc_seccomp_arch_unknown;
671 continue;
672 }
673 cur_rule_arch = lxc_seccomp_arch_mips64;
674 } else if (strcmp(line, "[mips64n32]") == 0 ||
675 strcmp(line, "[MIPS64N32]") == 0) {
676 if (native_arch != lxc_seccomp_arch_mips64) {
677 cur_rule_arch = lxc_seccomp_arch_unknown;
678 continue;
679 }
680 cur_rule_arch = lxc_seccomp_arch_mips64n32;
681 } else if (strcmp(line, "[mips]") == 0 ||
682 strcmp(line, "[MIPS]") == 0) {
683 if (native_arch != lxc_seccomp_arch_mips &&
684 native_arch != lxc_seccomp_arch_mips64) {
685 cur_rule_arch = lxc_seccomp_arch_unknown;
686 continue;
687 }
688 cur_rule_arch = lxc_seccomp_arch_mips;
689 } else if (strcmp(line, "[mipsel64]") == 0 ||
690 strcmp(line, "[MIPSEL64]") == 0) {
691 if (native_arch != lxc_seccomp_arch_mipsel64) {
692 cur_rule_arch = lxc_seccomp_arch_unknown;
693 continue;
694 }
695 cur_rule_arch = lxc_seccomp_arch_mipsel64;
696 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
697 strcmp(line, "[MIPSEL64N32]") == 0) {
698 if (native_arch != lxc_seccomp_arch_mipsel64) {
699 cur_rule_arch = lxc_seccomp_arch_unknown;
700 continue;
701 }
702 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
703 } else if (strcmp(line, "[mipsel]") == 0 ||
704 strcmp(line, "[MIPSEL]") == 0) {
705 if (native_arch != lxc_seccomp_arch_mipsel &&
706 native_arch != lxc_seccomp_arch_mipsel64) {
707 cur_rule_arch = lxc_seccomp_arch_unknown;
708 continue;
709 }
710 cur_rule_arch = lxc_seccomp_arch_mipsel;
711 }
712 #endif
713 #ifdef SCMP_ARCH_S390X
714 else if (strcmp(line, "[s390x]") == 0 ||
715 strcmp(line, "[S390X]") == 0) {
716 if (native_arch != lxc_seccomp_arch_s390x) {
717 cur_rule_arch = lxc_seccomp_arch_unknown;
718 continue;
719 }
720 cur_rule_arch = lxc_seccomp_arch_s390x;
721 }
722 #endif
723 else
724 goto bad_arch;
725
726 continue;
727 }
728
729 /* irrelevant arch - i.e. arm on i386 */
730 if (cur_rule_arch == lxc_seccomp_arch_unknown)
731 continue;
732
733 memset(&rule, 0, sizeof(rule));
734 /* read optional action which follows the syscall */
735 ret = parse_v2_rules(line, default_rule_action, &rule);
736 if (ret != 0) {
737 ERROR("Failed to interpret seccomp rule");
738 goto bad_rule;
739 }
740
741 if (cur_rule_arch == native_arch ||
742 cur_rule_arch == lxc_seccomp_arch_native ||
743 compat_arch[0] == SCMP_ARCH_NATIVE) {
744 INFO("Adding native rule for %s action %d(%s)", line, rule.action,
745 get_action_name(rule.action));
746 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
747 goto bad_rule;
748 }
749 else if (cur_rule_arch != lxc_seccomp_arch_all) {
750 int arch_index =
751 cur_rule_arch == lxc_seccomp_arch_mips64n32 ||
752 cur_rule_arch == lxc_seccomp_arch_mipsel64n32 ? 1 : 0;
753
754 INFO("Adding compat-only rule for %s action %d(%s)", line, rule.action,
755 get_action_name(rule.action));
756 if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], &rule))
757 goto bad_rule;
758 }
759 else {
760 INFO("Adding native rule for %s action %d(%s)", line, rule.action,
761 get_action_name(rule.action));
762 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
763 goto bad_rule;
764 INFO("Adding compat rule for %s action %d(%s)", line, rule.action,
765 get_action_name(rule.action));
766 if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], &rule))
767 goto bad_rule;
768 if (compat_arch[1] != SCMP_ARCH_NATIVE &&
769 !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], &rule))
770 goto bad_rule;
771 }
772 }
773
774 if (compat_ctx[0]) {
775 INFO("Merging in the compat Seccomp ctx into the main one");
776 if (seccomp_merge(conf->seccomp_ctx, compat_ctx[0]) != 0 ||
777 (compat_ctx[1] != NULL && seccomp_merge(conf->seccomp_ctx, compat_ctx[1]) != 0)) {
778 ERROR("Error merging compat Seccomp contexts");
779 goto bad;
780 }
781 }
782
783 return 0;
784
785 bad_arch:
786 ERROR("Unsupported arch: %s.", line);
787 bad_rule:
788 bad:
789 if (compat_ctx[0])
790 seccomp_release(compat_ctx[0]);
791 if (compat_ctx[1])
792 seccomp_release(compat_ctx[1]);
793 return -1;
794 }
795 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
796 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
797 {
798 return -1;
799 }
800 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
801
802 /*
803 * The first line of the config file has a policy language version
804 * the second line has some directives
805 * then comes policy subject to the directives
806 * right now version must be '1' or '2'
807 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
808 * (version == 2) and can include 'debug' (though debug is not yet supported).
809 */
810 static int parse_config(FILE *f, struct lxc_conf *conf)
811 {
812 char line[1024];
813 int ret, version;
814
815 ret = fscanf(f, "%d\n", &version);
816 if (ret != 1 || (version != 1 && version != 2)) {
817 ERROR("Invalid version");
818 return -1;
819 }
820 if (!fgets(line, 1024, f)) {
821 ERROR("Invalid config file");
822 return -1;
823 }
824 if (version == 1 && !strstr(line, "whitelist")) {
825 ERROR("Only whitelist policy is supported");
826 return -1;
827 }
828
829 if (strstr(line, "debug")) {
830 ERROR("Debug not yet implemented");
831 return -1;
832 }
833
834 if (version == 1)
835 return parse_config_v1(f, conf);
836 return parse_config_v2(f, line, conf);
837 }
838
839 /*
840 * use_seccomp: return true if we should try and apply a seccomp policy
841 * if defined for the container.
842 * This will return false if
843 * 1. seccomp is not enabled in the kernel
844 * 2. a seccomp policy is already enabled for this task
845 */
846 static bool use_seccomp(void)
847 {
848 FILE *f = fopen("/proc/self/status", "r");
849 char line[1024];
850 bool already_enabled = false;
851 bool found = false;
852 int ret, v;
853
854 if (!f)
855 return true;
856
857 while (fgets(line, 1024, f)) {
858 if (strncmp(line, "Seccomp:", 8) == 0) {
859 found = true;
860 ret = sscanf(line + 8, "%d", &v);
861 if (ret == 1 && v != 0)
862 already_enabled = true;
863 break;
864 }
865 }
866
867 fclose(f);
868 if (!found) { /* no Seccomp line, no seccomp in kernel */
869 INFO("Seccomp is not enabled in the kernel");
870 return false;
871 }
872 if (already_enabled) { /* already seccomp-confined */
873 INFO("Already seccomp-confined, not loading new policy");
874 return false;
875 }
876 return true;
877 }
878
879 int lxc_read_seccomp_config(struct lxc_conf *conf)
880 {
881 FILE *f;
882 int ret;
883 int check_seccomp_attr_set;
884
885 if (!conf->seccomp)
886 return 0;
887
888 if (!use_seccomp())
889 return 0;
890 #if HAVE_SCMP_FILTER_CTX
891 /* XXX for debug, pass in SCMP_ACT_TRAP */
892 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
893 ret = !conf->seccomp_ctx;
894 #else
895 ret = seccomp_init(SCMP_ACT_KILL) < 0;
896 #endif
897 if (ret) {
898 ERROR("Failed initializing seccomp");
899 return -1;
900 }
901
902 /* turn off no-new-privs. We don't want it in lxc, and it breaks
903 * with apparmor */
904 #if HAVE_SCMP_FILTER_CTX
905 check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
906 #else
907 check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
908 #endif
909 if (check_seccomp_attr_set) {
910 ERROR("Failed to turn off no-new-privs");
911 return -1;
912 }
913 #ifdef SCMP_FLTATR_ATL_TSKIP
914 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
915 WARN("Failed to turn on seccomp nop-skip, continuing");
916 }
917 #endif
918
919 f = fopen(conf->seccomp, "r");
920 if (!f) {
921 SYSERROR("Failed to open seccomp policy file %s", conf->seccomp);
922 return -1;
923 }
924 ret = parse_config(f, conf);
925 fclose(f);
926 return ret;
927 }
928
929 int lxc_seccomp_load(struct lxc_conf *conf)
930 {
931 int ret;
932 if (!conf->seccomp)
933 return 0;
934 if (!use_seccomp())
935 return 0;
936 ret = seccomp_load(
937 #if HAVE_SCMP_FILTER_CTX
938 conf->seccomp_ctx
939 #endif
940 );
941 if (ret < 0) {
942 ERROR("Error loading the seccomp policy: %s", strerror(-ret));
943 return -1;
944 }
945
946 /* After load seccomp filter into the kernel successfully, export the current seccomp
947 * filter to log file */
948 #if HAVE_SCMP_FILTER_CTX
949 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
950 lxc_log_fd >= 0) {
951 ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
952 /* Just give an warning when export error */
953 if (ret < 0)
954 WARN("Failed to export seccomp filter to log file: %s", strerror(-ret));
955 }
956 #endif
957 return 0;
958 }
959
960 void lxc_seccomp_free(struct lxc_conf *conf)
961 {
962 free(conf->seccomp);
963 conf->seccomp = NULL;
964 #if HAVE_SCMP_FILTER_CTX
965 if (conf->seccomp_ctx) {
966 seccomp_release(conf->seccomp_ctx);
967 conf->seccomp_ctx = NULL;
968 }
969 #endif
970 }