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