]> git.proxmox.com Git - mirror_lxc.git/blame_incremental - src/lxc/seccomp.c
seccomp: remove unnecessary memset
[mirror_lxc.git] / src / lxc / seccomp.c
... / ...
CommitLineData
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
36lxc_log_define(lxc_seccomp, lxc);
37
38static 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
62static 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
72static 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
95static 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
112static 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
132struct v2_rule_args {
133 uint32_t index;
134 uint64_t value;
135 uint64_t mask;
136 enum scmp_compare op;
137};
138
139struct seccomp_v2_rule {
140 uint32_t action;
141 uint32_t args_num;
142 struct v2_rule_args args_value[6];
143};
144
145static 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 * index: the index for syscall arguments (type uint)
168 * value: the value for syscall arguments (type uint64)
169 * op: the operator for syscall arguments(string),
170 a valid list of constants as of libseccomp v2.3.2 is
171 SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE,
172 SCMP_CMP_GT, SCMP_CMP_MASKED_EQ, or !=,<=,==,>=,>,&=
173 * valueTwo: the value for syscall arguments only used for mask eq (type uint64, optional)
174 * Returns 0 on success, < 0 otherwise.
175 */
176static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args)
177{
178 int ret = 0;
179 uint64_t value = 0;
180 uint64_t mask = 0;
181 enum scmp_compare op = 0;
182 uint32_t index = 0;
183 char s[31] = {0};
184 char *tmp = NULL;
185
186 tmp = strchr(key, '[');
187 if (!tmp) {
188 ERROR("Failed to interpret args");
189 return -1;
190 }
191 ret = sscanf(tmp, "[%i,%lli,%30[^0-9^,],%lli", &index, (long long unsigned int *)&value, s, (long long unsigned int *)&mask);
192 if ((ret != 3 && ret != 4) || index >= 6) {
193 ERROR("Failed to interpret args value");
194 return -1;
195 }
196
197 op = parse_v2_rule_op(s);
198 if (op == _SCMP_CMP_MAX) {
199 ERROR("Failed to interpret args operator value");
200 return -1;
201 }
202
203 rule_args->index = index;
204 rule_args->value = value;
205 rule_args->mask = mask;
206 rule_args->op = op;
207 return 0;
208}
209
210/* This function is used to parse the seccomp rule entry.
211 * @line : seccomp rule entry string.
212 * @def_action : default action used in the case if the 'line' contain non valid action.
213 * @rules : output struct.
214 * Returns 0 on success, < 0 otherwise.
215 */
216static int parse_v2_rules(char *line, uint32_t def_action, struct seccomp_v2_rule *rules)
217{
218 int ret = 0 ;
219 int i = 0;
220 char *tmp = NULL;
221 char *key = NULL;
222 char *saveptr = NULL;
223
224 tmp = strdup(line);
225 if (!tmp)
226 return -1;
227
228 /* read optional action which follows the syscall */
229 rules->action = get_v2_action(tmp, def_action);
230 if (rules->action == -1) {
231 ERROR("Failed to interpret action");
232 ret = -1;
233 goto out;
234 }
235
236 rules->args_num = 0;
237 if (!strchr(tmp, '[')) {
238 ret = 0;
239 goto out;
240 }
241
242 for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6; (key = strtok_r(NULL, "]", &saveptr)), i++) {
243 ret = get_seccomp_arg_value(key, &rules->args_value[i]);
244 if (ret < 0) {
245 ret = -1;
246 goto out;
247 }
248 rules->args_num++;
249 }
250
251 ret = 0;
252out:
253 free(tmp);
254 return ret;
255}
256
257#endif
258
259#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
260enum lxc_hostarch_t {
261 lxc_seccomp_arch_all = 0,
262 lxc_seccomp_arch_native,
263 lxc_seccomp_arch_i386,
264 lxc_seccomp_arch_x32,
265 lxc_seccomp_arch_amd64,
266 lxc_seccomp_arch_arm,
267 lxc_seccomp_arch_arm64,
268 lxc_seccomp_arch_ppc64,
269 lxc_seccomp_arch_ppc64le,
270 lxc_seccomp_arch_ppc,
271 lxc_seccomp_arch_mips,
272 lxc_seccomp_arch_mips64,
273 lxc_seccomp_arch_mips64n32,
274 lxc_seccomp_arch_mipsel,
275 lxc_seccomp_arch_mipsel64,
276 lxc_seccomp_arch_mipsel64n32,
277 lxc_seccomp_arch_s390x,
278 lxc_seccomp_arch_unknown = 999,
279};
280
281#ifdef __MIPSEL__
282# define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
283# define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
284#else
285# define MIPS_ARCH_O32 lxc_seccomp_arch_mips
286# define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
287#endif
288
289int get_hostarch(void)
290{
291 struct utsname uts;
292 if (uname(&uts) < 0) {
293 SYSERROR("Failed to read host arch");
294 return -1;
295 }
296 if (strcmp(uts.machine, "i686") == 0)
297 return lxc_seccomp_arch_i386;
298 /* no x32 kernels */
299 else if (strcmp(uts.machine, "x86_64") == 0)
300 return lxc_seccomp_arch_amd64;
301 else if (strncmp(uts.machine, "armv7", 5) == 0)
302 return lxc_seccomp_arch_arm;
303 else if (strncmp(uts.machine, "aarch64", 7) == 0)
304 return lxc_seccomp_arch_arm64;
305 else if (strncmp(uts.machine, "ppc64le", 7) == 0)
306 return lxc_seccomp_arch_ppc64le;
307 else if (strncmp(uts.machine, "ppc64", 5) == 0)
308 return lxc_seccomp_arch_ppc64;
309 else if (strncmp(uts.machine, "ppc", 3) == 0)
310 return lxc_seccomp_arch_ppc;
311 else if (strncmp(uts.machine, "mips64", 6) == 0)
312 return MIPS_ARCH_N64;
313 else if (strncmp(uts.machine, "mips", 4) == 0)
314 return MIPS_ARCH_O32;
315 else if (strncmp(uts.machine, "s390x", 5) == 0)
316 return lxc_seccomp_arch_s390x;
317 return lxc_seccomp_arch_unknown;
318}
319
320scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action, bool *needs_merge)
321{
322 scmp_filter_ctx ctx;
323 int ret;
324 uint32_t arch;
325
326 switch(n_arch) {
327 case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
328 case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
329 case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
330 case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
331#ifdef SCMP_ARCH_AARCH64
332 case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
333#endif
334#ifdef SCMP_ARCH_PPC64LE
335 case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
336#endif
337#ifdef SCMP_ARCH_PPC64
338 case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
339#endif
340#ifdef SCMP_ARCH_PPC
341 case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
342#endif
343#ifdef SCMP_ARCH_MIPS
344 case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
345 case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
346 case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
347 case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
348 case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
349 case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
350#endif
351#ifdef SCMP_ARCH_S390X
352 case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
353#endif
354 default: return NULL;
355 }
356
357 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
358 ERROR("Error initializing seccomp context");
359 return NULL;
360 }
361 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
362 ERROR("Failed to turn off no-new-privs");
363 seccomp_release(ctx);
364 return NULL;
365 }
366#ifdef SCMP_FLTATR_ATL_TSKIP
367 if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
368 WARN("Failed to turn on seccomp nop-skip, continuing");
369 }
370#endif
371
372 ret = seccomp_arch_exist(ctx, arch);
373 if (ret < 0) {
374 if (ret != -EEXIST) {
375 ERROR("%s - Failed to determine whether arch %d is "
376 "already present in the main seccomp context",
377 strerror(-ret), (int)n_arch);
378 seccomp_release(ctx);
379 return NULL;
380 }
381
382 ret = seccomp_arch_add(ctx, arch);
383 if (ret != 0) {
384 ERROR("%s - Failed to add arch %d to main seccomp context",
385 strerror(-ret), (int)n_arch);
386 seccomp_release(ctx);
387 return NULL;
388 }
389 TRACE("Added arch %d to main seccomp context", (int)n_arch);
390
391 ret = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE);
392 if (ret != 0) {
393 ERROR("Failed to remove native arch from main seccomp context");
394 seccomp_release(ctx);
395 return NULL;
396 }
397 TRACE("Removed native arch from main seccomp context");
398
399 *needs_merge = true;
400 } else {
401 *needs_merge = false;
402 TRACE("Arch %d already present in main seccomp context", (int)n_arch);
403 }
404
405 return ctx;
406}
407
408bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
409 struct seccomp_v2_rule *rule)
410{
411 int nr, ret, i;
412 struct scmp_arg_cmp arg_cmp[6];
413
414 memset(arg_cmp, 0 ,sizeof(arg_cmp));
415
416 ret = seccomp_arch_exist(ctx, arch);
417 if (arch && ret != 0) {
418 ERROR("BUG: Seccomp: rule and context arch do not match (arch "
419 "%d): %s",
420 arch, strerror(-ret));
421 return false;
422 }
423
424 /*get the syscall name*/
425 char *p = strchr(line, ' ');
426 if (p)
427 *p = '\0';
428
429 if (strncmp(line, "reject_force_umount", 19) == 0) {
430 INFO("Setting Seccomp rule to reject force umounts");
431 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
432 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
433 if (ret < 0) {
434 ERROR("Failed (%d) loading rule to reject force "
435 "umount: %s",
436 ret, strerror(-ret));
437 return false;
438 }
439 return true;
440 }
441
442 nr = seccomp_syscall_resolve_name(line);
443 if (nr == __NR_SCMP_ERROR) {
444 WARN("Seccomp: failed to resolve syscall: %s", line);
445 WARN("This syscall will NOT be blacklisted");
446 return true;
447 }
448 if (nr < 0) {
449 WARN("Seccomp: got negative for syscall: %d: %s", nr, line);
450 WARN("This syscall will NOT be blacklisted");
451 return true;
452 }
453
454 for (i = 0; i < rule->args_num; i++) {
455 INFO("arg_cmp[%d]:SCMP_CMP(%u, %llu, %llu, %llu)", i,
456 rule->args_value[i].index,
457 (long long unsigned int)rule->args_value[i].op,
458 (long long unsigned int)rule->args_value[i].mask,
459 (long long unsigned int)rule->args_value[i].value);
460
461 if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
462 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);
463 else
464 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].value);
465 }
466
467 ret = seccomp_rule_add_exact_array(ctx, rule->action, nr, rule->args_num, arg_cmp);
468 if (ret < 0) {
469 ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s",
470 ret, line, nr, rule->action, get_action_name(rule->action), strerror(-ret));
471 return false;
472 }
473 return true;
474}
475
476/*
477 * v2 consists of
478 * [x86]
479 * open
480 * read
481 * write
482 * close
483 * # a comment
484 * [x86_64]
485 * open
486 * read
487 * write
488 * close
489 */
490static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
491{
492 char *p;
493 int ret;
494 bool blacklist = false;
495 uint32_t default_policy_action = -1, default_rule_action = -1;
496 enum lxc_hostarch_t native_arch = get_hostarch(),
497 cur_rule_arch = native_arch;
498 struct seccomp_v2_rule rule;
499 struct scmp_ctx_info {
500 uint32_t architectures[3];
501 scmp_filter_ctx contexts[3];
502 bool needs_merge[3];
503 } ctx;
504
505 if (strncmp(line, "blacklist", 9) == 0)
506 blacklist = true;
507 else if (strncmp(line, "whitelist", 9) != 0) {
508 ERROR("Bad seccomp policy style: %s", line);
509 return -1;
510 }
511
512 if ((p = strchr(line, ' '))) {
513 default_policy_action = get_v2_default_action(p + 1);
514 if (default_policy_action == -2)
515 return -1;
516 }
517
518 /* for blacklist, allow any syscall which has no rule */
519 if (blacklist) {
520 if (default_policy_action == -1)
521 default_policy_action = SCMP_ACT_ALLOW;
522 if (default_rule_action == -1)
523 default_rule_action = SCMP_ACT_KILL;
524 } else {
525 if (default_policy_action == -1)
526 default_policy_action = SCMP_ACT_KILL;
527 if (default_rule_action == -1)
528 default_rule_action = SCMP_ACT_ALLOW;
529 }
530
531 memset(&ctx, 0, sizeof(ctx));
532 ctx.architectures[0] = SCMP_ARCH_NATIVE;
533 ctx.architectures[1] = SCMP_ARCH_NATIVE;
534 ctx.architectures[2] = SCMP_ARCH_NATIVE;
535 if (native_arch == lxc_seccomp_arch_amd64) {
536 cur_rule_arch = lxc_seccomp_arch_all;
537
538 ctx.architectures[0] = SCMP_ARCH_X86;
539 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386,
540 default_policy_action,
541 &ctx.needs_merge[0]);
542 if (!ctx.contexts[0])
543 goto bad;
544
545 ctx.architectures[1] = SCMP_ARCH_X32;
546 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32,
547 default_policy_action,
548 &ctx.needs_merge[1]);
549 if (!ctx.contexts[1])
550 goto bad;
551
552 ctx.architectures[2] = SCMP_ARCH_X86_64;
553 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64,
554 default_policy_action,
555 &ctx.needs_merge[2]);
556 if (!ctx.contexts[2])
557 goto bad;
558#ifdef SCMP_ARCH_PPC
559 } else if (native_arch == lxc_seccomp_arch_ppc64) {
560 cur_rule_arch = lxc_seccomp_arch_all;
561
562 ctx.architectures[0] = SCMP_ARCH_PPC;
563 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc,
564 default_policy_action,
565 &ctx.needs_merge[0]);
566 if (!ctx.contexts[0])
567 goto bad;
568
569 ctx.architectures[2] = SCMP_ARCH_PPC64;
570 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_ppc64,
571 default_policy_action,
572 &ctx.needs_merge[2]);
573 if (!ctx.contexts[2])
574 goto bad;
575#endif
576#ifdef SCMP_ARCH_ARM
577 } else if (native_arch == lxc_seccomp_arch_arm64) {
578 cur_rule_arch = lxc_seccomp_arch_all;
579
580 ctx.architectures[0] = SCMP_ARCH_ARM;
581 ctx.contexts[0] =
582 get_new_ctx(lxc_seccomp_arch_arm, default_policy_action,
583 &ctx.needs_merge[0]);
584 if (!ctx.contexts[0])
585 goto bad;
586
587#ifdef SCMP_ARCH_AARCH64
588 ctx.architectures[2] = SCMP_ARCH_AARCH64;
589 ctx.contexts[2] =
590 get_new_ctx(lxc_seccomp_arch_arm64, default_policy_action,
591 &ctx.needs_merge[2]);
592 if (!ctx.contexts[2])
593 goto bad;
594#endif
595#endif
596#ifdef SCMP_ARCH_MIPS
597 } else if (native_arch == lxc_seccomp_arch_mips64) {
598 cur_rule_arch = lxc_seccomp_arch_all;
599
600 ctx.architectures[0] = SCMP_ARCH_MIPS;
601 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips,
602 default_policy_action,
603 &ctx.needs_merge[0]);
604 if (!ctx.contexts[0])
605 goto bad;
606
607 ctx.architectures[1] = SCMP_ARCH_MIPS64N32;
608 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
609 default_policy_action,
610 &ctx.needs_merge[1]);
611 if (!ctx.contexts[1])
612 goto bad;
613
614 ctx.architectures[2] = SCMP_ARCH_MIPS64;
615 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64,
616 default_policy_action,
617 &ctx.needs_merge[2]);
618 if (!ctx.contexts[2])
619 goto bad;
620 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
621 cur_rule_arch = lxc_seccomp_arch_all;
622
623 ctx.architectures[0] = SCMP_ARCH_MIPSEL;
624 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
625 default_policy_action,
626 &ctx.needs_merge[0]);
627 if (!ctx.contexts[0])
628 goto bad;
629
630 ctx.architectures[1] = SCMP_ARCH_MIPSEL64N32;
631 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
632 default_policy_action,
633 &ctx.needs_merge[1]);
634 if (!ctx.contexts[1])
635 goto bad;
636
637 ctx.architectures[2] = SCMP_ARCH_MIPSEL64;
638 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64,
639 default_policy_action,
640 &ctx.needs_merge[2]);
641 if (!ctx.contexts[2])
642 goto bad;
643#endif
644 }
645
646 if (default_policy_action != SCMP_ACT_KILL) {
647 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
648 if (ret != 0) {
649 ERROR("Error re-initializing Seccomp");
650 return -1;
651 }
652 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
653 ERROR("Failed to turn off no-new-privs");
654 return -1;
655 }
656#ifdef SCMP_FLTATR_ATL_TSKIP
657 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
658 WARN("Failed to turn on seccomp nop-skip, continuing");
659 }
660#endif
661 }
662
663 while (fgets(line, 1024, f)) {
664
665 if (line[0] == '#')
666 continue;
667 if (strlen(line) == 0)
668 continue;
669 remove_trailing_newlines(line);
670 INFO("processing: .%s", line);
671 if (line[0] == '[') {
672 /* Read the architecture for next set of rules. */
673 if (strcmp(line, "[x86]") == 0 ||
674 strcmp(line, "[X86]") == 0) {
675 if (native_arch != lxc_seccomp_arch_i386 &&
676 native_arch != lxc_seccomp_arch_amd64) {
677 cur_rule_arch = lxc_seccomp_arch_unknown;
678 continue;
679 }
680 cur_rule_arch = lxc_seccomp_arch_i386;
681 } else if (strcmp(line, "[x32]") == 0 ||
682 strcmp(line, "[X32]") == 0) {
683 if (native_arch != lxc_seccomp_arch_amd64) {
684 cur_rule_arch = lxc_seccomp_arch_unknown;
685 continue;
686 }
687 cur_rule_arch = lxc_seccomp_arch_x32;
688 } else if (strcmp(line, "[X86_64]") == 0 ||
689 strcmp(line, "[x86_64]") == 0) {
690 if (native_arch != lxc_seccomp_arch_amd64) {
691 cur_rule_arch = lxc_seccomp_arch_unknown;
692 continue;
693 }
694 cur_rule_arch = lxc_seccomp_arch_amd64;
695 } else if (strcmp(line, "[all]") == 0 ||
696 strcmp(line, "[ALL]") == 0) {
697 cur_rule_arch = lxc_seccomp_arch_all;
698 }
699#ifdef SCMP_ARCH_ARM
700 else if (strcmp(line, "[arm]") == 0 ||
701 strcmp(line, "[ARM]") == 0) {
702 if (native_arch != lxc_seccomp_arch_arm &&
703 native_arch != lxc_seccomp_arch_arm64) {
704 cur_rule_arch = lxc_seccomp_arch_unknown;
705 continue;
706 }
707 cur_rule_arch = lxc_seccomp_arch_arm;
708 }
709#endif
710#ifdef SCMP_ARCH_AARCH64
711 else if (strcmp(line, "[arm64]") == 0 ||
712 strcmp(line, "[ARM64]") == 0) {
713 if (native_arch != lxc_seccomp_arch_arm64) {
714 cur_rule_arch = lxc_seccomp_arch_unknown;
715 continue;
716 }
717 cur_rule_arch = lxc_seccomp_arch_arm64;
718 }
719#endif
720#ifdef SCMP_ARCH_PPC64LE
721 else if (strcmp(line, "[ppc64le]") == 0 ||
722 strcmp(line, "[PPC64LE]") == 0) {
723 if (native_arch != lxc_seccomp_arch_ppc64le) {
724 cur_rule_arch = lxc_seccomp_arch_unknown;
725 continue;
726 }
727 cur_rule_arch = lxc_seccomp_arch_ppc64le;
728 }
729#endif
730#ifdef SCMP_ARCH_PPC64
731 else if (strcmp(line, "[ppc64]") == 0 ||
732 strcmp(line, "[PPC64]") == 0) {
733 if (native_arch != lxc_seccomp_arch_ppc64) {
734 cur_rule_arch = lxc_seccomp_arch_unknown;
735 continue;
736 }
737 cur_rule_arch = lxc_seccomp_arch_ppc64;
738 }
739#endif
740#ifdef SCMP_ARCH_PPC
741 else if (strcmp(line, "[ppc]") == 0 ||
742 strcmp(line, "[PPC]") == 0) {
743 if (native_arch != lxc_seccomp_arch_ppc &&
744 native_arch != lxc_seccomp_arch_ppc64) {
745 cur_rule_arch = lxc_seccomp_arch_unknown;
746 continue;
747 }
748 cur_rule_arch = lxc_seccomp_arch_ppc;
749 }
750#endif
751#ifdef SCMP_ARCH_MIPS
752 else if (strcmp(line, "[mips64]") == 0 ||
753 strcmp(line, "[MIPS64]") == 0) {
754 if (native_arch != lxc_seccomp_arch_mips64) {
755 cur_rule_arch = lxc_seccomp_arch_unknown;
756 continue;
757 }
758 cur_rule_arch = lxc_seccomp_arch_mips64;
759 } else if (strcmp(line, "[mips64n32]") == 0 ||
760 strcmp(line, "[MIPS64N32]") == 0) {
761 if (native_arch != lxc_seccomp_arch_mips64) {
762 cur_rule_arch = lxc_seccomp_arch_unknown;
763 continue;
764 }
765 cur_rule_arch = lxc_seccomp_arch_mips64n32;
766 } else if (strcmp(line, "[mips]") == 0 ||
767 strcmp(line, "[MIPS]") == 0) {
768 if (native_arch != lxc_seccomp_arch_mips &&
769 native_arch != lxc_seccomp_arch_mips64) {
770 cur_rule_arch = lxc_seccomp_arch_unknown;
771 continue;
772 }
773 cur_rule_arch = lxc_seccomp_arch_mips;
774 } else if (strcmp(line, "[mipsel64]") == 0 ||
775 strcmp(line, "[MIPSEL64]") == 0) {
776 if (native_arch != lxc_seccomp_arch_mipsel64) {
777 cur_rule_arch = lxc_seccomp_arch_unknown;
778 continue;
779 }
780 cur_rule_arch = lxc_seccomp_arch_mipsel64;
781 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
782 strcmp(line, "[MIPSEL64N32]") == 0) {
783 if (native_arch != lxc_seccomp_arch_mipsel64) {
784 cur_rule_arch = lxc_seccomp_arch_unknown;
785 continue;
786 }
787 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
788 } else if (strcmp(line, "[mipsel]") == 0 ||
789 strcmp(line, "[MIPSEL]") == 0) {
790 if (native_arch != lxc_seccomp_arch_mipsel &&
791 native_arch != lxc_seccomp_arch_mipsel64) {
792 cur_rule_arch = lxc_seccomp_arch_unknown;
793 continue;
794 }
795 cur_rule_arch = lxc_seccomp_arch_mipsel;
796 }
797#endif
798#ifdef SCMP_ARCH_S390X
799 else if (strcmp(line, "[s390x]") == 0 ||
800 strcmp(line, "[S390X]") == 0) {
801 if (native_arch != lxc_seccomp_arch_s390x) {
802 cur_rule_arch = lxc_seccomp_arch_unknown;
803 continue;
804 }
805 cur_rule_arch = lxc_seccomp_arch_s390x;
806 }
807#endif
808 else
809 goto bad_arch;
810
811 continue;
812 }
813
814 /* irrelevant arch - i.e. arm on i386 */
815 if (cur_rule_arch == lxc_seccomp_arch_unknown)
816 continue;
817
818 memset(&rule, 0, sizeof(rule));
819 /* read optional action which follows the syscall */
820 ret = parse_v2_rules(line, default_rule_action, &rule);
821 if (ret != 0) {
822 ERROR("Failed to interpret seccomp rule");
823 goto bad_rule;
824 }
825
826 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
827 conf->seccomp_ctx, &rule))
828 goto bad_rule;
829 INFO("Added native rule for arch %d for %s action %d(%s)",
830 SCMP_ARCH_NATIVE, line, rule.action,
831 get_action_name(rule.action));
832
833 if (ctx.architectures[0] != SCMP_ARCH_NATIVE) {
834 if (!do_resolve_add_rule(ctx.architectures[0], line,
835 ctx.contexts[0], &rule))
836 goto bad_rule;
837 INFO("Added compat rule for arch %d for %s action %d(%s)",
838 ctx.architectures[0], line, rule.action,
839 get_action_name(rule.action));
840 }
841
842 if (ctx.architectures[1] != SCMP_ARCH_NATIVE) {
843 if (!do_resolve_add_rule(ctx.architectures[1], line,
844 ctx.contexts[1], &rule))
845 goto bad_rule;
846 INFO("Added compat rule for arch %d for %s action %d(%s)",
847 ctx.architectures[1], line, rule.action,
848 get_action_name(rule.action));
849 }
850
851 if (ctx.architectures[2] != SCMP_ARCH_NATIVE) {
852 if (!do_resolve_add_rule(ctx.architectures[2], line,
853 ctx.contexts[2], &rule))
854 goto bad_rule;
855 INFO("Added native rule for arch %d for %s action %d(%s)",
856 ctx.architectures[2], line, rule.action,
857 get_action_name(rule.action));
858 }
859 }
860
861 INFO("Merging compat seccomp contexts into main context");
862 if (ctx.contexts[0]) {
863 if (ctx.needs_merge[0]) {
864 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[0]);
865 if (ret < 0) {
866 ERROR("Failed to merge first compat seccomp "
867 "context into main context");
868 goto bad;
869 }
870 TRACE("Merged first compat seccomp context into main context");
871 } else {
872 seccomp_release(ctx.contexts[0]);
873 ctx.contexts[0] = NULL;
874 }
875 }
876
877 if (ctx.contexts[1]) {
878 if (ctx.needs_merge[1]) {
879 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[1]);
880 if (ret < 0) {
881 ERROR("Failed to merge first compat seccomp "
882 "context into main context");
883 goto bad;
884 }
885 TRACE("Merged second compat seccomp context into main context");
886 } else {
887 seccomp_release(ctx.contexts[1]);
888 ctx.contexts[1] = NULL;
889 }
890 }
891
892 if (ctx.contexts[2]) {
893 if (ctx.needs_merge[2]) {
894 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[2]);
895 if (ret < 0) {
896 ERROR("Failed to merge third compat seccomp "
897 "context into main context");
898 goto bad;
899 }
900 TRACE("Merged third compat seccomp context into main context");
901 } else {
902 seccomp_release(ctx.contexts[2]);
903 ctx.contexts[2] = NULL;
904 }
905 }
906
907 return 0;
908
909bad_arch:
910 ERROR("Unsupported arch: %s.", line);
911bad_rule:
912bad:
913 if (ctx.contexts[0])
914 seccomp_release(ctx.contexts[0]);
915 if (ctx.contexts[1])
916 seccomp_release(ctx.contexts[1]);
917 if (ctx.contexts[2])
918 seccomp_release(ctx.contexts[2]);
919
920 return -1;
921}
922#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
923static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
924{
925 return -1;
926}
927#endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
928
929/*
930 * The first line of the config file has a policy language version
931 * the second line has some directives
932 * then comes policy subject to the directives
933 * right now version must be '1' or '2'
934 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
935 * (version == 2) and can include 'debug' (though debug is not yet supported).
936 */
937static int parse_config(FILE *f, struct lxc_conf *conf)
938{
939 char line[1024];
940 int ret, version;
941
942 ret = fscanf(f, "%d\n", &version);
943 if (ret != 1 || (version != 1 && version != 2)) {
944 ERROR("Invalid version");
945 return -1;
946 }
947 if (!fgets(line, 1024, f)) {
948 ERROR("Invalid config file");
949 return -1;
950 }
951 if (version == 1 && !strstr(line, "whitelist")) {
952 ERROR("Only whitelist policy is supported");
953 return -1;
954 }
955
956 if (strstr(line, "debug")) {
957 ERROR("Debug not yet implemented");
958 return -1;
959 }
960
961 if (version == 1)
962 return parse_config_v1(f, conf);
963 return parse_config_v2(f, line, conf);
964}
965
966/*
967 * use_seccomp: return true if we should try and apply a seccomp policy
968 * if defined for the container.
969 * This will return false if
970 * 1. seccomp is not enabled in the kernel
971 * 2. a seccomp policy is already enabled for this task
972 */
973static bool use_seccomp(void)
974{
975 FILE *f = fopen("/proc/self/status", "r");
976 char line[1024];
977 bool already_enabled = false;
978 bool found = false;
979 int ret, v;
980
981 if (!f)
982 return true;
983
984 while (fgets(line, 1024, f)) {
985 if (strncmp(line, "Seccomp:", 8) == 0) {
986 found = true;
987 ret = sscanf(line + 8, "%d", &v);
988 if (ret == 1 && v != 0)
989 already_enabled = true;
990 break;
991 }
992 }
993
994 fclose(f);
995 if (!found) { /* no Seccomp line, no seccomp in kernel */
996 INFO("Seccomp is not enabled in the kernel");
997 return false;
998 }
999 if (already_enabled) { /* already seccomp-confined */
1000 INFO("Already seccomp-confined, not loading new policy");
1001 return false;
1002 }
1003 return true;
1004}
1005
1006int lxc_read_seccomp_config(struct lxc_conf *conf)
1007{
1008 FILE *f;
1009 int ret;
1010 int check_seccomp_attr_set;
1011
1012 if (!conf->seccomp)
1013 return 0;
1014
1015 if (!use_seccomp())
1016 return 0;
1017#if HAVE_SCMP_FILTER_CTX
1018 /* XXX for debug, pass in SCMP_ACT_TRAP */
1019 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
1020 ret = !conf->seccomp_ctx;
1021#else
1022 ret = seccomp_init(SCMP_ACT_KILL) < 0;
1023#endif
1024 if (ret) {
1025 ERROR("Failed initializing seccomp");
1026 return -1;
1027 }
1028
1029/* turn off no-new-privs. We don't want it in lxc, and it breaks
1030 * with apparmor */
1031#if HAVE_SCMP_FILTER_CTX
1032 check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
1033#else
1034 check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
1035#endif
1036 if (check_seccomp_attr_set) {
1037 ERROR("Failed to turn off no-new-privs");
1038 return -1;
1039 }
1040#ifdef SCMP_FLTATR_ATL_TSKIP
1041 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
1042 WARN("Failed to turn on seccomp nop-skip, continuing");
1043 }
1044#endif
1045
1046 f = fopen(conf->seccomp, "r");
1047 if (!f) {
1048 SYSERROR("Failed to open seccomp policy file %s", conf->seccomp);
1049 return -1;
1050 }
1051 ret = parse_config(f, conf);
1052 fclose(f);
1053 return ret;
1054}
1055
1056int lxc_seccomp_load(struct lxc_conf *conf)
1057{
1058 int ret;
1059 if (!conf->seccomp)
1060 return 0;
1061 if (!use_seccomp())
1062 return 0;
1063 ret = seccomp_load(
1064#if HAVE_SCMP_FILTER_CTX
1065 conf->seccomp_ctx
1066#endif
1067 );
1068 if (ret < 0) {
1069 ERROR("Error loading the seccomp policy: %s", strerror(-ret));
1070 return -1;
1071 }
1072
1073/* After load seccomp filter into the kernel successfully, export the current seccomp
1074 * filter to log file */
1075#if HAVE_SCMP_FILTER_CTX
1076 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
1077 lxc_log_fd >= 0) {
1078 ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
1079 /* Just give an warning when export error */
1080 if (ret < 0)
1081 WARN("Failed to export seccomp filter to log file: %s", strerror(-ret));
1082 }
1083#endif
1084 return 0;
1085}
1086
1087void lxc_seccomp_free(struct lxc_conf *conf)
1088{
1089 free(conf->seccomp);
1090 conf->seccomp = NULL;
1091#if HAVE_SCMP_FILTER_CTX
1092 if (conf->seccomp_ctx) {
1093 seccomp_release(conf->seccomp_ctx);
1094 conf->seccomp_ctx = NULL;
1095 }
1096#endif
1097}